package ipns import ( "fmt" "os/exec" "runtime" "time" fuse "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" fs "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" core "github.com/jbenet/go-ipfs/core" mount "github.com/jbenet/go-ipfs/fuse/mount" ) // Mount mounts an IpfsNode instance at a particular path. It // serves until the process receives exit signals (to Unmount). func Mount(ipfs *core.IpfsNode, fpath string, ipfspath string) (mount.Mount, error) { log.Infof("Mounting ipns at %s...", fpath) // setup the Mount abstraction. m := mount.New(ipfs.Context(), fpath) // go serve the mount m.Mount(func(m mount.Mount) error { return internalMount(ipfs, fpath, ipfspath) }, internalUnmount) select { case <-m.Closed(): return nil, fmt.Errorf("failed to mount") case <-time.After(time.Second): // assume it worked... } // bind the mount (ContextGroup) to the node, so that when the node exits // the fsclosers are automatically closed. ipfs.AddChildGroup(m) return m, nil } // mount attempts to mount at the provided FUSE mount point func internalMount(ipfs *core.IpfsNode, fpath string, ipfspath string) error { c, err := fuse.Mount(fpath) if err != nil { return err } defer c.Close() fsys, err := NewIpns(ipfs, ipfs.PrivateKey, ipfspath) if err != nil { return err } log.Infof("Mounted ipns at %s.", fpath) if err := fs.Serve(c, fsys); err != nil { return err } // check if the mount process has an error to report <-c.Ready if err := c.MountError; err != nil { return err } return nil } // unmount attempts to unmount the provided FUSE mount point, forcibly // if necessary. func internalUnmount(m mount.Mount) error { point := m.MountPoint() log.Infof("Unmounting ipns at %s...", point) var cmd *exec.Cmd switch runtime.GOOS { case "darwin": cmd = exec.Command("diskutil", "umount", "force", point) case "linux": cmd = exec.Command("fusermount", "-u", point) default: return fmt.Errorf("unmount: unimplemented") } errc := make(chan error, 1) go func() { if err := exec.Command("umount", point).Run(); err == nil { errc <- err } // retry to unmount with the fallback cmd errc <- cmd.Run() }() select { case <-time.After(1 * time.Second): return fmt.Errorf("umount timeout") case err := <-errc: return err } }