github.com/stevegt/moby@v1.13.1/oci/devices_linux.go (about) 1 package oci 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strings" 8 9 "github.com/opencontainers/runc/libcontainer/configs" 10 "github.com/opencontainers/runc/libcontainer/devices" 11 specs "github.com/opencontainers/runtime-spec/specs-go" 12 ) 13 14 // Device transforms a libcontainer configs.Device to a specs.Device object. 15 func Device(d *configs.Device) specs.Device { 16 return specs.Device{ 17 Type: string(d.Type), 18 Path: d.Path, 19 Major: d.Major, 20 Minor: d.Minor, 21 FileMode: fmPtr(int64(d.FileMode)), 22 UID: u32Ptr(int64(d.Uid)), 23 GID: u32Ptr(int64(d.Gid)), 24 } 25 } 26 27 func deviceCgroup(d *configs.Device) specs.DeviceCgroup { 28 t := string(d.Type) 29 return specs.DeviceCgroup{ 30 Allow: true, 31 Type: &t, 32 Major: &d.Major, 33 Minor: &d.Minor, 34 Access: &d.Permissions, 35 } 36 } 37 38 // DevicesFromPath computes a list of devices and device permissions from paths (pathOnHost and pathInContainer) and cgroup permissions. 39 func DevicesFromPath(pathOnHost, pathInContainer, cgroupPermissions string) (devs []specs.Device, devPermissions []specs.DeviceCgroup, err error) { 40 resolvedPathOnHost := pathOnHost 41 42 // check if it is a symbolic link 43 if src, e := os.Lstat(pathOnHost); e == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink { 44 if linkedPathOnHost, e := filepath.EvalSymlinks(pathOnHost); e == nil { 45 resolvedPathOnHost = linkedPathOnHost 46 } 47 } 48 49 device, err := devices.DeviceFromPath(resolvedPathOnHost, cgroupPermissions) 50 // if there was no error, return the device 51 if err == nil { 52 device.Path = pathInContainer 53 return append(devs, Device(device)), append(devPermissions, deviceCgroup(device)), nil 54 } 55 56 // if the device is not a device node 57 // try to see if it's a directory holding many devices 58 if err == devices.ErrNotADevice { 59 60 // check if it is a directory 61 if src, e := os.Stat(resolvedPathOnHost); e == nil && src.IsDir() { 62 63 // mount the internal devices recursively 64 filepath.Walk(resolvedPathOnHost, func(dpath string, f os.FileInfo, e error) error { 65 childDevice, e := devices.DeviceFromPath(dpath, cgroupPermissions) 66 if e != nil { 67 // ignore the device 68 return nil 69 } 70 71 // add the device to userSpecified devices 72 childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, pathInContainer, 1) 73 devs = append(devs, Device(childDevice)) 74 devPermissions = append(devPermissions, deviceCgroup(childDevice)) 75 76 return nil 77 }) 78 } 79 } 80 81 if len(devs) > 0 { 82 return devs, devPermissions, nil 83 } 84 85 return devs, devPermissions, fmt.Errorf("error gathering device information while adding custom device %q: %s", pathOnHost, err) 86 }