| package oci |
| |
| import ( |
| "fmt" |
| "os" |
| "path/filepath" |
| "strings" |
| |
| "github.com/opencontainers/runc/libcontainer/configs" |
| "github.com/opencontainers/runc/libcontainer/devices" |
| specs "github.com/opencontainers/runtime-spec/specs-go" |
| ) |
| |
| // Device transforms a libcontainer configs.Device to a specs.LinuxDevice object. |
| func Device(d *configs.Device) specs.LinuxDevice { |
| return specs.LinuxDevice{ |
| Type: string(d.Type), |
| Path: d.Path, |
| Major: d.Major, |
| Minor: d.Minor, |
| FileMode: fmPtr(int64(d.FileMode)), |
| UID: u32Ptr(int64(d.Uid)), |
| GID: u32Ptr(int64(d.Gid)), |
| } |
| } |
| |
| func deviceCgroup(d *configs.Device) specs.LinuxDeviceCgroup { |
| t := string(d.Type) |
| return specs.LinuxDeviceCgroup{ |
| Allow: true, |
| Type: t, |
| Major: &d.Major, |
| Minor: &d.Minor, |
| Access: d.Permissions, |
| } |
| } |
| |
| // DevicesFromPath computes a list of devices and device permissions from paths (pathOnHost and pathInContainer) and cgroup permissions. |
| func DevicesFromPath(pathOnHost, pathInContainer, cgroupPermissions string) (devs []specs.LinuxDevice, devPermissions []specs.LinuxDeviceCgroup, err error) { |
| resolvedPathOnHost := pathOnHost |
| |
| // check if it is a symbolic link |
| if src, e := os.Lstat(pathOnHost); e == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink { |
| if linkedPathOnHost, e := filepath.EvalSymlinks(pathOnHost); e == nil { |
| resolvedPathOnHost = linkedPathOnHost |
| } |
| } |
| |
| device, err := devices.DeviceFromPath(resolvedPathOnHost, cgroupPermissions) |
| // if there was no error, return the device |
| if err == nil { |
| device.Path = pathInContainer |
| return append(devs, Device(device)), append(devPermissions, deviceCgroup(device)), nil |
| } |
| |
| // if the device is not a device node |
| // try to see if it's a directory holding many devices |
| if err == devices.ErrNotADevice { |
| |
| // check if it is a directory |
| if src, e := os.Stat(resolvedPathOnHost); e == nil && src.IsDir() { |
| |
| // mount the internal devices recursively |
| filepath.Walk(resolvedPathOnHost, func(dpath string, f os.FileInfo, e error) error { |
| childDevice, e := devices.DeviceFromPath(dpath, cgroupPermissions) |
| if e != nil { |
| // ignore the device |
| return nil |
| } |
| |
| // add the device to userSpecified devices |
| childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, pathInContainer, 1) |
| devs = append(devs, Device(childDevice)) |
| devPermissions = append(devPermissions, deviceCgroup(childDevice)) |
| |
| return nil |
| }) |
| } |
| } |
| |
| if len(devs) > 0 { |
| return devs, devPermissions, nil |
| } |
| |
| return devs, devPermissions, fmt.Errorf("error gathering device information while adding custom device %q: %s", pathOnHost, err) |
| } |