github.com/moby/docker@v26.1.3+incompatible/oci/devices_linux.go (about)

     1  package oci // import "github.com/docker/docker/oci"
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	coci "github.com/containerd/containerd/oci"
    10  	specs "github.com/opencontainers/runtime-spec/specs-go"
    11  )
    12  
    13  func deviceCgroup(d *specs.LinuxDevice, permissions string) specs.LinuxDeviceCgroup {
    14  	return specs.LinuxDeviceCgroup{
    15  		Allow:  true,
    16  		Type:   d.Type,
    17  		Major:  &d.Major,
    18  		Minor:  &d.Minor,
    19  		Access: permissions,
    20  	}
    21  }
    22  
    23  // DevicesFromPath computes a list of devices and device permissions from paths (pathOnHost and pathInContainer) and cgroup permissions.
    24  func DevicesFromPath(pathOnHost, pathInContainer, cgroupPermissions string) (devs []specs.LinuxDevice, devPermissions []specs.LinuxDeviceCgroup, err error) {
    25  	resolvedPathOnHost := pathOnHost
    26  
    27  	// check if it is a symbolic link
    28  	if src, e := os.Lstat(pathOnHost); e == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
    29  		if linkedPathOnHost, e := filepath.EvalSymlinks(pathOnHost); e == nil {
    30  			resolvedPathOnHost = linkedPathOnHost
    31  		}
    32  	}
    33  
    34  	device, err := coci.DeviceFromPath(resolvedPathOnHost)
    35  	// if there was no error, return the device
    36  	if err == nil {
    37  		device.Path = pathInContainer
    38  		return append(devs, *device), append(devPermissions, deviceCgroup(device, cgroupPermissions)), nil
    39  	}
    40  
    41  	// if the device is not a device node
    42  	// try to see if it's a directory holding many devices
    43  	if err == coci.ErrNotADevice {
    44  		// check if it is a directory
    45  		if src, e := os.Stat(resolvedPathOnHost); e == nil && src.IsDir() {
    46  			// mount the internal devices recursively
    47  			// TODO check if additional errors should be handled or logged
    48  			_ = filepath.WalkDir(resolvedPathOnHost, func(dpath string, f os.DirEntry, _ error) error {
    49  				childDevice, e := coci.DeviceFromPath(dpath)
    50  				if e != nil {
    51  					// ignore the device
    52  					return nil
    53  				}
    54  
    55  				// add the device to userSpecified devices
    56  				childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, pathInContainer, 1)
    57  				devs = append(devs, *childDevice)
    58  				devPermissions = append(devPermissions, deviceCgroup(childDevice, cgroupPermissions))
    59  
    60  				return nil
    61  			})
    62  		}
    63  	}
    64  
    65  	if len(devs) > 0 {
    66  		return devs, devPermissions, nil
    67  	}
    68  
    69  	return devs, devPermissions, fmt.Errorf("error gathering device information while adding custom device %q: %s", pathOnHost, err)
    70  }