github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/volume/local/local_unix.go (about) 1 // +build linux freebsd 2 3 // Package local provides the default implementation for volumes. It 4 // is used to mount data volume containers and directories local to 5 // the host server. 6 package local 7 8 import ( 9 "fmt" 10 "net" 11 "os" 12 "path/filepath" 13 "strings" 14 "syscall" 15 "time" 16 17 "github.com/pkg/errors" 18 19 "github.com/docker/docker/pkg/mount" 20 ) 21 22 var ( 23 oldVfsDir = filepath.Join("vfs", "dir") 24 25 validOpts = map[string]bool{ 26 "type": true, // specify the filesystem type for mount, e.g. nfs 27 "o": true, // generic mount options 28 "device": true, // device to mount from 29 } 30 ) 31 32 type optsConfig struct { 33 MountType string 34 MountOpts string 35 MountDevice string 36 } 37 38 func (o *optsConfig) String() string { 39 return fmt.Sprintf("type='%s' device='%s' o='%s'", o.MountType, o.MountDevice, o.MountOpts) 40 } 41 42 // scopedPath verifies that the path where the volume is located 43 // is under Docker's root and the valid local paths. 44 func (r *Root) scopedPath(realPath string) bool { 45 // Volumes path for Docker version >= 1.7 46 if strings.HasPrefix(realPath, filepath.Join(r.scope, volumesPathName)) && realPath != filepath.Join(r.scope, volumesPathName) { 47 return true 48 } 49 50 // Volumes path for Docker version < 1.7 51 if strings.HasPrefix(realPath, filepath.Join(r.scope, oldVfsDir)) { 52 return true 53 } 54 55 return false 56 } 57 58 func setOpts(v *localVolume, opts map[string]string) error { 59 if len(opts) == 0 { 60 return nil 61 } 62 if err := validateOpts(opts); err != nil { 63 return err 64 } 65 66 v.opts = &optsConfig{ 67 MountType: opts["type"], 68 MountOpts: opts["o"], 69 MountDevice: opts["device"], 70 } 71 return nil 72 } 73 74 func (v *localVolume) mount() error { 75 if v.opts.MountDevice == "" { 76 return fmt.Errorf("missing device in volume options") 77 } 78 mountOpts := v.opts.MountOpts 79 if v.opts.MountType == "nfs" { 80 if addrValue := getAddress(v.opts.MountOpts); addrValue != "" && net.ParseIP(addrValue).To4() == nil { 81 ipAddr, err := net.ResolveIPAddr("ip", addrValue) 82 if err != nil { 83 return errors.Wrapf(err, "error resolving passed in nfs address") 84 } 85 mountOpts = strings.Replace(mountOpts, "addr="+addrValue, "addr="+ipAddr.String(), 1) 86 } 87 } 88 err := mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, mountOpts) 89 return errors.Wrapf(err, "error while mounting volume with options: %s", v.opts) 90 } 91 92 func (v *localVolume) CreatedAt() (time.Time, error) { 93 fileInfo, err := os.Stat(v.path) 94 if err != nil { 95 return time.Time{}, err 96 } 97 sec, nsec := fileInfo.Sys().(*syscall.Stat_t).Ctim.Unix() 98 return time.Unix(sec, nsec), nil 99 }