2018-02-05 21:05:59 +00:00
|
|
|
package oci // import "github.com/docker/docker/oci"
|
2016-11-17 00:18:43 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/opencontainers/runc/libcontainer/devices"
|
2019-08-05 14:37:47 +00:00
|
|
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
2021-02-17 13:55:50 +00:00
|
|
|
"golang.org/x/sys/unix"
|
2016-11-17 00:18:43 +00:00
|
|
|
)
|
|
|
|
|
2020-12-03 15:20:30 +00:00
|
|
|
// Device transforms a libcontainer devices.Device to a specs.LinuxDevice object.
|
|
|
|
func Device(d *devices.Device) specs.LinuxDevice {
|
2017-04-27 21:52:47 +00:00
|
|
|
return specs.LinuxDevice{
|
2016-11-17 00:18:43 +00:00
|
|
|
Type: string(d.Type),
|
|
|
|
Path: d.Path,
|
|
|
|
Major: d.Major,
|
|
|
|
Minor: d.Minor,
|
2021-02-17 13:55:50 +00:00
|
|
|
FileMode: fmPtr(int64(d.FileMode &^ unix.S_IFMT)), // strip file type, as OCI spec only expects file-mode to be included
|
2016-11-17 00:18:43 +00:00
|
|
|
UID: u32Ptr(int64(d.Uid)),
|
|
|
|
GID: u32Ptr(int64(d.Gid)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-03 15:20:30 +00:00
|
|
|
func deviceCgroup(d *devices.Device) specs.LinuxDeviceCgroup {
|
2017-04-27 21:52:47 +00:00
|
|
|
return specs.LinuxDeviceCgroup{
|
2016-11-17 00:18:43 +00:00
|
|
|
Allow: true,
|
2020-07-29 12:50:56 +00:00
|
|
|
Type: string(d.Type),
|
2016-11-17 00:18:43 +00:00
|
|
|
Major: &d.Major,
|
|
|
|
Minor: &d.Minor,
|
2020-07-30 06:34:33 +00:00
|
|
|
Access: string(d.Permissions),
|
2016-11-17 00:18:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DevicesFromPath computes a list of devices and device permissions from paths (pathOnHost and pathInContainer) and cgroup permissions.
|
2017-04-27 21:52:47 +00:00
|
|
|
func DevicesFromPath(pathOnHost, pathInContainer, cgroupPermissions string) (devs []specs.LinuxDevice, devPermissions []specs.LinuxDeviceCgroup, err error) {
|
2016-11-17 00:18:43 +00:00
|
|
|
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
|
2019-08-28 17:29:19 +00:00
|
|
|
// TODO check if additional errors should be handled or logged
|
|
|
|
_ = filepath.Walk(resolvedPathOnHost, func(dpath string, f os.FileInfo, _ error) error {
|
2016-11-17 00:18:43 +00:00
|
|
|
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)
|
|
|
|
}
|