github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/fuse/mount/mount.go (about)

     1  // package mount provides a simple abstraction around a mount point
     2  package mount
     3  
     4  import (
     5  	"fmt"
     6  	"io"
     7  	"os/exec"
     8  	"runtime"
     9  	"time"
    10  
    11  	goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
    12  
    13  	u "github.com/ipfs/go-ipfs/util"
    14  )
    15  
    16  var log = u.Logger("mount")
    17  
    18  var MountTimeout = time.Second * 5
    19  
    20  // Mount represents a filesystem mount
    21  type Mount interface {
    22  	// MountPoint is the path at which this mount is mounted
    23  	MountPoint() string
    24  
    25  	// Unmounts the mount
    26  	Unmount() error
    27  
    28  	// Process returns the mount's Process to be able to link it
    29  	// to other processes. Unmount upon closing.
    30  	Process() goprocess.Process
    31  }
    32  
    33  // ForceUnmount attempts to forcibly unmount a given mount.
    34  // It does so by calling diskutil or fusermount directly.
    35  func ForceUnmount(m Mount) error {
    36  	point := m.MountPoint()
    37  	log.Warningf("Force-Unmounting %s...", point)
    38  
    39  	var cmd *exec.Cmd
    40  	switch runtime.GOOS {
    41  	case "darwin":
    42  		cmd = exec.Command("diskutil", "umount", "force", point)
    43  	case "linux":
    44  		cmd = exec.Command("fusermount", "-u", point)
    45  	default:
    46  		return fmt.Errorf("unmount: unimplemented")
    47  	}
    48  
    49  	errc := make(chan error, 1)
    50  	go func() {
    51  		defer close(errc)
    52  
    53  		// try vanilla unmount first.
    54  		if err := exec.Command("umount", point).Run(); err == nil {
    55  			return
    56  		}
    57  
    58  		// retry to unmount with the fallback cmd
    59  		errc <- cmd.Run()
    60  	}()
    61  
    62  	select {
    63  	case <-time.After(7 * time.Second):
    64  		return fmt.Errorf("umount timeout")
    65  	case err := <-errc:
    66  		return err
    67  	}
    68  }
    69  
    70  // ForceUnmountManyTimes attempts to forcibly unmount a given mount,
    71  // many times. It does so by calling diskutil or fusermount directly.
    72  // Attempts a given number of times.
    73  func ForceUnmountManyTimes(m Mount, attempts int) error {
    74  	var err error
    75  	for i := 0; i < attempts; i++ {
    76  		err = ForceUnmount(m)
    77  		if err == nil {
    78  			return err
    79  		}
    80  
    81  		<-time.After(time.Millisecond * 500)
    82  	}
    83  	return fmt.Errorf("Unmount %s failed after 10 seconds of trying.", m.MountPoint())
    84  }
    85  
    86  type closer struct {
    87  	M Mount
    88  }
    89  
    90  func (c *closer) Close() error {
    91  	log.Error(" (c *closer) Close(),", c.M.MountPoint())
    92  	return c.M.Unmount()
    93  }
    94  
    95  func Closer(m Mount) io.Closer {
    96  	return &closer{m}
    97  }