| 1 | // Real mount command. go-fuse only builds on linux, darwin, and freebsd. |
| 2 | //go:build (linux || darwin || freebsd) && !nofuse |
| 3 | |
| 4 | package commands |
| 5 | |
| 6 | import ( |
| 7 | "fmt" |
| 8 | "io" |
| 9 | |
| 10 | oldcmds "github.com/ipfs/kubo/commands" |
| 11 | cmdenv "github.com/ipfs/kubo/core/commands/cmdenv" |
| 12 | nodeMount "github.com/ipfs/kubo/fuse/node" |
| 13 | |
| 14 | cmds "github.com/ipfs/go-ipfs-cmds" |
| 15 | config "github.com/ipfs/kubo/config" |
| 16 | ) |
| 17 | |
| 18 | const ( |
| 19 | mountIPFSPathOptionName = "ipfs-path" |
| 20 | mountIPNSPathOptionName = "ipns-path" |
| 21 | mountMFSPathOptionName = "mfs-path" |
| 22 | ) |
| 23 | |
| 24 | var MountCmd = &cmds.Command{ |
| 25 | Status: cmds.Experimental, |
| 26 | Helptext: cmds.HelpText{ |
| 27 | Tagline: "Mounts IPFS to the filesystem (read-only).", |
| 28 | ShortDescription: ` |
| 29 | Mount IPFS at a read-only mountpoint on the OS (default: /ipfs, /ipns, /mfs). |
| 30 | All IPFS objects will be accessible under that directory. Note that the |
| 31 | root will not be listable, as it is virtual. Access known paths directly. |
| 32 | |
| 33 | You may have to create /ipfs and /ipns before using 'ipfs mount': |
| 34 | |
| 35 | > sudo mkdir /ipfs /ipns /mfs |
| 36 | > sudo chown $(whoami) /ipfs /ipns /mfs |
| 37 | > ipfs daemon & |
| 38 | > ipfs mount |
| 39 | `, |
| 40 | LongDescription: ` |
| 41 | Mount IPFS at a read-only mountpoint on the OS. The default, /ipfs and /ipns, |
| 42 | are set in the configuration file, but can be overridden by the options. |
| 43 | All IPFS objects will be accessible under this directory. Note that the |
| 44 | root will not be listable, as it is virtual. Access known paths directly. |
| 45 | |
| 46 | You may have to create /ipfs and /ipns before using 'ipfs mount': |
| 47 | |
| 48 | > sudo mkdir /ipfs /ipns /mfs |
| 49 | > sudo chown $(whoami) /ipfs /ipns /mfs |
| 50 | > ipfs daemon & |
| 51 | > ipfs mount |
| 52 | |
| 53 | Example: |
| 54 | |
| 55 | # setup |
| 56 | > mkdir foo |
| 57 | > echo "baz" > foo/bar |
| 58 | > ipfs add -r foo |
| 59 | added QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR foo/bar |
| 60 | added QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC foo |
| 61 | > ipfs ls QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC |
| 62 | QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR 12 bar |
| 63 | > ipfs cat QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR |
| 64 | baz |
| 65 | |
| 66 | # mount |
| 67 | > ipfs daemon & |
| 68 | > ipfs mount |
| 69 | IPFS mounted at: /ipfs |
| 70 | IPNS mounted at: /ipns |
| 71 | MFS mounted at: /mfs |
| 72 | > cd /ipfs/QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC |
| 73 | > ls |
| 74 | bar |
| 75 | > cat bar |
| 76 | baz |
| 77 | > cat /ipfs/QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC/bar |
| 78 | baz |
| 79 | > cat /ipfs/QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR |
| 80 | baz |
| 81 | `, |
| 82 | }, |
| 83 | Options: []cmds.Option{ |
| 84 | cmds.StringOption(mountIPFSPathOptionName, "f", "The path where IPFS should be mounted."), |
| 85 | cmds.StringOption(mountIPNSPathOptionName, "n", "The path where IPNS should be mounted."), |
| 86 | cmds.StringOption(mountMFSPathOptionName, "m", "The path where MFS should be mounted."), |
| 87 | }, |
| 88 | Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { |
| 89 | cfg, err := env.(*oldcmds.Context).GetConfig() |
| 90 | if err != nil { |
| 91 | return err |
| 92 | } |
| 93 | |
| 94 | nd, err := cmdenv.GetNode(env) |
| 95 | if err != nil { |
| 96 | return err |
| 97 | } |
| 98 | |
| 99 | // error if we aren't running node in online mode |
| 100 | if !nd.IsOnline { |
| 101 | return ErrNotOnline |
| 102 | } |
| 103 | |
| 104 | fsdir, found := req.Options[mountIPFSPathOptionName].(string) |
| 105 | if !found { |
| 106 | fsdir = cfg.Mounts.IPFS // use default value |
| 107 | } |
| 108 | |
| 109 | // get default mount points |
| 110 | nsdir, found := req.Options[mountIPNSPathOptionName].(string) |
| 111 | if !found { |
| 112 | nsdir = cfg.Mounts.IPNS // NB: be sure to not redeclare! |
| 113 | } |
| 114 | |
| 115 | mfsdir, found := req.Options[mountMFSPathOptionName].(string) |
| 116 | if !found { |
| 117 | mfsdir = cfg.Mounts.MFS |
| 118 | } |
| 119 | |
| 120 | err = nodeMount.Mount(nd, fsdir, nsdir, mfsdir) |
| 121 | if err != nil { |
| 122 | return err |
| 123 | } |
| 124 | |
| 125 | var output config.Mounts |
| 126 | output.IPFS = fsdir |
| 127 | output.IPNS = nsdir |
| 128 | output.MFS = mfsdir |
| 129 | return cmds.EmitOnce(res, &output) |
| 130 | }, |
| 131 | Type: config.Mounts{}, |
| 132 | Encoders: cmds.EncoderMap{ |
| 133 | cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, mounts *config.Mounts) error { |
| 134 | // Extra space after "MFS" so "mounted at:" lines up with |
| 135 | // IPFS and IPNS in the column above. Matches LongDescription. |
| 136 | fmt.Fprintf(w, "IPFS mounted at: %s\n", cmdenv.EscNonPrint(mounts.IPFS)) |
| 137 | fmt.Fprintf(w, "IPNS mounted at: %s\n", cmdenv.EscNonPrint(mounts.IPNS)) |
| 138 | fmt.Fprintf(w, "MFS mounted at: %s\n", cmdenv.EscNonPrint(mounts.MFS)) |
| 139 | |
| 140 | return nil |
| 141 | }), |
| 142 | }, |
| 143 | } |