github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/cmd/mountlib/rc.go (about) 1 package mountlib 2 3 import ( 4 "context" 5 "errors" 6 "log" 7 "sort" 8 "sync" 9 "time" 10 11 "github.com/rclone/rclone/fs" 12 "github.com/rclone/rclone/fs/rc" 13 "github.com/rclone/rclone/vfs/vfsflags" 14 ) 15 16 var ( 17 // mutex to protect all the variables in this block 18 mountMu sync.Mutex 19 // Mount functions available 20 mountFns = map[string]MountFn{} 21 // Map of mounted path => MountInfo 22 liveMounts = map[string]*MountPoint{} 23 // Supported mount types 24 supportedMountTypes = []string{"mount", "cmount", "mount2"} 25 ) 26 27 // ResolveMountMethod returns mount function by name 28 func ResolveMountMethod(mountType string) (string, MountFn) { 29 if mountType != "" { 30 return mountType, mountFns[mountType] 31 } 32 for _, mountType := range supportedMountTypes { 33 if mountFns[mountType] != nil { 34 return mountType, mountFns[mountType] 35 } 36 } 37 return "", nil 38 } 39 40 // AddRc adds mount and unmount functionality to rc 41 func AddRc(mountUtilName string, mountFunction MountFn) { 42 mountMu.Lock() 43 defer mountMu.Unlock() 44 // rcMount allows the mount command to be run from rc 45 mountFns[mountUtilName] = mountFunction 46 } 47 48 func init() { 49 rc.Add(rc.Call{ 50 Path: "mount/mount", 51 AuthRequired: true, 52 Fn: mountRc, 53 Title: "Create a new mount point", 54 Help: `rclone allows Linux, FreeBSD, macOS and Windows to mount any of 55 Rclone's cloud storage systems as a file system with FUSE. 56 57 If no mountType is provided, the priority is given as follows: 1. mount 2.cmount 3.mount2 58 59 This takes the following parameters: 60 61 - fs - a remote path to be mounted (required) 62 - mountPoint: valid path on the local machine (required) 63 - mountType: one of the values (mount, cmount, mount2) specifies the mount implementation to use 64 - mountOpt: a JSON object with Mount options in. 65 - vfsOpt: a JSON object with VFS options in. 66 67 Example: 68 69 rclone rc mount/mount fs=mydrive: mountPoint=/home/<user>/mountPoint 70 rclone rc mount/mount fs=mydrive: mountPoint=/home/<user>/mountPoint mountType=mount 71 rclone rc mount/mount fs=TestDrive: mountPoint=/mnt/tmp vfsOpt='{"CacheMode": 2}' mountOpt='{"AllowOther": true}' 72 73 The vfsOpt are as described in options/get and can be seen in the the 74 "vfs" section when running and the mountOpt can be seen in the "mount" section: 75 76 rclone rc options/get 77 `, 78 }) 79 } 80 81 // mountRc allows the mount command to be run from rc 82 func mountRc(ctx context.Context, in rc.Params) (out rc.Params, err error) { 83 mountPoint, err := in.GetString("mountPoint") 84 if err != nil { 85 return nil, err 86 } 87 88 vfsOpt := vfsflags.Opt 89 err = in.GetStructMissingOK("vfsOpt", &vfsOpt) 90 if err != nil { 91 return nil, err 92 } 93 94 mountOpt := Opt 95 err = in.GetStructMissingOK("mountOpt", &mountOpt) 96 if err != nil { 97 return nil, err 98 } 99 100 if mountOpt.Daemon { 101 return nil, errors.New("daemon option not supported over the API") 102 } 103 104 mountType, err := in.GetString("mountType") 105 106 mountMu.Lock() 107 defer mountMu.Unlock() 108 109 if err != nil { 110 mountType = "" 111 } 112 mountType, mountFn := ResolveMountMethod(mountType) 113 if mountFn == nil { 114 return nil, errors.New("mount option specified is not registered, or is invalid") 115 } 116 117 // Get Fs.fs to be mounted from fs parameter in the params 118 fdst, err := rc.GetFs(ctx, in) 119 if err != nil { 120 return nil, err 121 } 122 123 mnt := NewMountPoint(mountFn, mountPoint, fdst, &mountOpt, &vfsOpt) 124 _, err = mnt.Mount() 125 if err != nil { 126 log.Printf("mount FAILED: %v", err) 127 return nil, err 128 } 129 go func() { 130 if err = mnt.Wait(); err != nil { 131 log.Printf("unmount FAILED: %v", err) 132 return 133 } 134 mountMu.Lock() 135 defer mountMu.Unlock() 136 delete(liveMounts, mountPoint) 137 }() 138 // Add mount to list if mount point was successfully created 139 liveMounts[mountPoint] = mnt 140 141 fs.Debugf(nil, "Mount for %s created at %s using %s", fdst.String(), mountPoint, mountType) 142 return nil, nil 143 } 144 145 func init() { 146 rc.Add(rc.Call{ 147 Path: "mount/unmount", 148 AuthRequired: true, 149 Fn: unMountRc, 150 Title: "Unmount selected active mount", 151 Help: ` 152 rclone allows Linux, FreeBSD, macOS and Windows to 153 mount any of Rclone's cloud storage systems as a file system with 154 FUSE. 155 156 This takes the following parameters: 157 158 - mountPoint: valid path on the local machine where the mount was created (required) 159 160 Example: 161 162 rclone rc mount/unmount mountPoint=/home/<user>/mountPoint 163 `, 164 }) 165 } 166 167 // unMountRc allows the umount command to be run from rc 168 func unMountRc(_ context.Context, in rc.Params) (out rc.Params, err error) { 169 mountPoint, err := in.GetString("mountPoint") 170 if err != nil { 171 return nil, err 172 } 173 mountMu.Lock() 174 defer mountMu.Unlock() 175 mountInfo, found := liveMounts[mountPoint] 176 if !found { 177 return nil, errors.New("mount not found") 178 } 179 if err = mountInfo.Unmount(); err != nil { 180 return nil, err 181 } 182 delete(liveMounts, mountPoint) 183 return nil, nil 184 } 185 186 func init() { 187 rc.Add(rc.Call{ 188 Path: "mount/types", 189 AuthRequired: true, 190 Fn: mountTypesRc, 191 Title: "Show all possible mount types", 192 Help: `This shows all possible mount types and returns them as a list. 193 194 This takes no parameters and returns 195 196 - mountTypes: list of mount types 197 198 The mount types are strings like "mount", "mount2", "cmount" and can 199 be passed to mount/mount as the mountType parameter. 200 201 Eg 202 203 rclone rc mount/types 204 `, 205 }) 206 } 207 208 // mountTypesRc returns a list of available mount types. 209 func mountTypesRc(_ context.Context, in rc.Params) (out rc.Params, err error) { 210 var mountTypes = []string{} 211 mountMu.Lock() 212 defer mountMu.Unlock() 213 for mountType := range mountFns { 214 mountTypes = append(mountTypes, mountType) 215 } 216 sort.Strings(mountTypes) 217 return rc.Params{ 218 "mountTypes": mountTypes, 219 }, nil 220 } 221 222 func init() { 223 rc.Add(rc.Call{ 224 Path: "mount/listmounts", 225 AuthRequired: true, 226 Fn: listMountsRc, 227 Title: "Show current mount points", 228 Help: `This shows currently mounted points, which can be used for performing an unmount. 229 230 This takes no parameters and returns 231 232 - mountPoints: list of current mount points 233 234 Eg 235 236 rclone rc mount/listmounts 237 `, 238 }) 239 } 240 241 // MountInfo is a transitional structure for json marshaling 242 type MountInfo struct { 243 Fs string `json:"Fs"` 244 MountPoint string `json:"MountPoint"` 245 MountedOn time.Time `json:"MountedOn"` 246 } 247 248 // listMountsRc returns a list of current mounts sorted by mount path 249 func listMountsRc(_ context.Context, in rc.Params) (out rc.Params, err error) { 250 mountMu.Lock() 251 defer mountMu.Unlock() 252 var keys []string 253 for key := range liveMounts { 254 keys = append(keys, key) 255 } 256 sort.Strings(keys) 257 mountPoints := []MountInfo{} 258 for _, k := range keys { 259 m := liveMounts[k] 260 info := MountInfo{ 261 Fs: fs.ConfigString(m.Fs), 262 MountPoint: m.MountPoint, 263 MountedOn: m.MountedOn, 264 } 265 mountPoints = append(mountPoints, info) 266 } 267 return rc.Params{ 268 "mountPoints": mountPoints, 269 }, nil 270 } 271 272 func init() { 273 rc.Add(rc.Call{ 274 Path: "mount/unmountall", 275 AuthRequired: true, 276 Fn: unmountAll, 277 Title: "Unmount all active mounts", 278 Help: ` 279 rclone allows Linux, FreeBSD, macOS and Windows to 280 mount any of Rclone's cloud storage systems as a file system with 281 FUSE. 282 283 This takes no parameters and returns error if unmount does not succeed. 284 285 Eg 286 287 rclone rc mount/unmountall 288 `, 289 }) 290 } 291 292 // unmountAll unmounts all the created mounts 293 func unmountAll(_ context.Context, in rc.Params) (out rc.Params, err error) { 294 mountMu.Lock() 295 defer mountMu.Unlock() 296 for mountPoint, mountInfo := range liveMounts { 297 if err = mountInfo.Unmount(); err != nil { 298 fs.Debugf(nil, "Couldn't unmount : %s", mountPoint) 299 return nil, err 300 } 301 delete(liveMounts, mountPoint) 302 } 303 return nil, nil 304 }