oci/devices_linux.go
53b9b99e
 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"
 )
 
005506d3
 // Device transforms a libcontainer configs.Device to a specs.LinuxDevice object.
 func Device(d *configs.Device) specs.LinuxDevice {
 	return specs.LinuxDevice{
53b9b99e
 		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)),
 	}
 }
 
005506d3
 func deviceCgroup(d *configs.Device) specs.LinuxDeviceCgroup {
53b9b99e
 	t := string(d.Type)
005506d3
 	return specs.LinuxDeviceCgroup{
53b9b99e
 		Allow:  true,
005506d3
 		Type:   t,
53b9b99e
 		Major:  &d.Major,
 		Minor:  &d.Minor,
005506d3
 		Access: d.Permissions,
53b9b99e
 	}
 }
 
 // DevicesFromPath computes a list of devices and device permissions from paths (pathOnHost and pathInContainer) and cgroup permissions.
005506d3
 func DevicesFromPath(pathOnHost, pathInContainer, cgroupPermissions string) (devs []specs.LinuxDevice, devPermissions []specs.LinuxDeviceCgroup, err error) {
53b9b99e
 	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)
 }