github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/oci/devices_linux.go (about) 1 package oci // import "github.com/demonoid81/moby/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.LinuxDevice object. 15 func Device(d *configs.Device) specs.LinuxDevice { 16 return specs.LinuxDevice{ 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.LinuxDeviceCgroup { 28 t := string(d.Type) 29 return specs.LinuxDeviceCgroup{ 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.LinuxDevice, devPermissions []specs.LinuxDeviceCgroup, 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 // TODO check if additional errors should be handled or logged 65 _ = filepath.Walk(resolvedPathOnHost, func(dpath string, f os.FileInfo, _ error) error { 66 childDevice, e := devices.DeviceFromPath(dpath, cgroupPermissions) 67 if e != nil { 68 // ignore the device 69 return nil 70 } 71 72 // add the device to userSpecified devices 73 childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, pathInContainer, 1) 74 devs = append(devs, Device(childDevice)) 75 devPermissions = append(devPermissions, deviceCgroup(childDevice)) 76 77 return nil 78 }) 79 } 80 } 81 82 if len(devs) > 0 { 83 return devs, devPermissions, nil 84 } 85 86 return devs, devPermissions, fmt.Errorf("error gathering device information while adding custom device %q: %s", pathOnHost, err) 87 }