Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
50d1a6f
Move libcontainer into subdirectory
crosbymichael Jun 22, 2015
2a8c639
Update import paths for new repository
crosbymichael Jun 22, 2015
f2bc9fa
Windows: Tidy libcontainer\devices
Oct 23, 2015
d781e40
Fix typo.
Dec 1, 2016
fb47539
Don't add device to list if it doesn't exist anymore
mrunalp Dec 7, 2016
5ffd140
Update devices_unix.go for LXD
CarltonSemple Feb 14, 2017
1be0004
Added comment linking to LXD issue 2825
Mar 8, 2017
5de2c86
Clean up unix vs linux usage
justincormack May 12, 2017
2e18e0b
Merge pull request #1447 from justincormack/unix-linux
crosbymichael May 12, 2017
044ebc9
Move libcontainer to x/sys/unix
clnperez May 9, 2017
38d4b67
libcontainer: one more switch from syscall to x/sys/unix
tklauser Jul 21, 2017
16cff33
Merge pull request #1530 from tklauser/devices-syscall-to-unix
dqminh Jul 23, 2017
07a2f0e
Fix condition to detect device type in DeviceFromPath
mlaventure Aug 3, 2017
058bfbb
Handle non-devices correctly in DeviceFromPath
mlaventure Aug 9, 2017
6b7a83a
libcontainer: use Major/Minor from x/sys/unix
tklauser Oct 17, 2017
1f2d284
Merge pull request #1614 from tklauser/device-numbers
crosbymichael Oct 17, 2017
e5d2517
libcontainer: drop FreeBSD support
tklauser Nov 24, 2017
3abfc15
remove placeholder for non-linux platforms
dqminh Nov 16, 2017
f983f9d
libcontainer: devices: fix mips builds
cyphar Jun 17, 2018
40bbe7b
Skip searching /dev/.udev for device nodes.
sipsma Jul 31, 2019
ecee0e2
Make get devices function public
Aug 15, 2019
e0224a6
configs: use different types for .Devices and .Resources.Devices
cyphar May 7, 2020
76f9f26
devices: correctly check device types
cyphar Jul 28, 2020
ed7efa2
merge branch 'pr-2529'
cyphar Jul 29, 2020
ee96d80
libcontainer: isolate libcontainer/devices
thaJeztah Nov 10, 2020
42edf85
libcontainer/devices: remove "Device" prefix from types
thaJeztah Nov 19, 2020
4ca3995
libcontainer: fix the file mode of the device
Iceber Feb 10, 2021
9f53744
Merge pull request #2804 from Iceber/filemode
kolyshkin Feb 22, 2021
145067b
Fix build-tags in libcontainer/devices
thaJeztah Mar 13, 2021
281830e
libcontainer/devices/device_windows.go: rm
kolyshkin Dec 3, 2020
481d3c3
Use gofumpt to format code
kolyshkin Jun 1, 2021
0d78d41
libcontainer/devices: fix godoc (golint)
thaJeztah Jun 1, 2021
1df05b1
*: use errors.As and errors.Is
kolyshkin Jun 9, 2021
7bf31be
merge branch 'pr-3011'
cyphar Jun 24, 2021
a59f0f3
ci: enable unconvert linter, fix its warnings
kolyshkin Jul 7, 2021
688bb4d
libct/devices: change devices.Type to be a string
thaJeztah Aug 12, 2021
168ec57
Revert "libct/devices: change devices.Type to be a string"
cyphar Aug 25, 2021
e690e3e
*: add go-1.17+ go:build tags
kolyshkin Aug 31, 2021
589a05a
Remove io/ioutil use
kolyshkin Oct 13, 2021
e6691ed
Drop go 1.16
kolyshkin Mar 21, 2022
63bd767
remove pre-go1.17 build-tags
thaJeztah Jun 29, 2024
80d3efa
Merge pull request #4329 from thaJeztah/rm_old_buildtags
kolyshkin Jul 1, 2024
1cca97e
libct/devices: move config to libct/cg/devices/config
kolyshkin Jan 4, 2025
873e195
Merge pull request #4577 from kolyshkin/libct-dev
kolyshkin Feb 1, 2025
dc486c6
Switch to opencontainers/cgroups
kolyshkin Feb 26, 2025
8d66c0a
merge #4638 into opencontainers/runc:main
cyphar Mar 1, 2025
902eab2
lint/revive: add package doc comments
cyphar Sep 29, 2025
2dbe85e
merge #4904 into opencontainers/runc:main
cyphar Oct 3, 2025
2506285
Replace os.Is* error checking functions with their errors.Is counterpart
curdbecker Nov 16, 2025
59c2337
subtree-merge runc/libcontainer/devices into devices
cyphar Mar 4, 2026
8a7dc36
devices: add license headers
cyphar Mar 4, 2026
4fa19e8
devices: drop deprecated aliases from runc
cyphar Mar 4, 2026
730b894
devices: fix tests on macos
cyphar Mar 5, 2026
1b36f79
devices: add github.com/moby/sys/devices package
cyphar Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PACKAGES ?= atomicwriter capability mountinfo mount reexec sequential signal symlink user userns
PACKAGES ?= atomicwriter capability devices mountinfo mount reexec sequential signal symlink user userns
CROSS ?= linux/arm linux/arm64 linux/ppc64le linux/s390x \
freebsd/amd64 openbsd/amd64 darwin/amd64 darwin/arm64 windows/amd64
SUDO ?= sudo -n
Expand Down
133 changes: 133 additions & 0 deletions devices/device_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//go:build !windows

// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2015-2026 Open Containers Initiative Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// This code originally comes from runc and was taken from this tree:
// <https://github.com/opencontainers/runc/tree/v1.4.0/libcontainer/devices>.

package devices

import (
"errors"
"os"
"path/filepath"

"github.com/opencontainers/cgroups/devices/config"
"golang.org/x/sys/unix"
)

// ErrNotADevice denotes that a file is not a valid linux device.
var ErrNotADevice = errors.New("not a device node")

// Testing dependencies
var (
unixLstat = unix.Lstat
osReadDir = os.ReadDir
)

// DeviceFromPath takes the path to a device and its cgroup_permissions (which
// cannot be easily queried) to look up the information about a linux device
// and returns that information as a Device struct.
func DeviceFromPath(path, permissions string) (*config.Device, error) {
var stat unix.Stat_t
err := unixLstat(path, &stat)
if err != nil {
return nil, err
}

var (
devType config.Type
mode = stat.Mode
devNumber = uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on e.g. MIPS.
major = unix.Major(devNumber)
minor = unix.Minor(devNumber)
)
switch mode & unix.S_IFMT {
case unix.S_IFBLK:
devType = config.BlockDevice
case unix.S_IFCHR:
devType = config.CharDevice
case unix.S_IFIFO:
devType = config.FifoDevice
default:
return nil, ErrNotADevice
}
return &config.Device{
Rule: config.Rule{
Type: devType,
Major: int64(major),
Minor: int64(minor),
Permissions: config.Permissions(permissions),
},
Path: path,
FileMode: os.FileMode(mode &^ unix.S_IFMT),
Uid: stat.Uid,
Gid: stat.Gid,
}, nil
}

// HostDevices returns all devices that can be found under /dev directory.
func HostDevices() ([]*config.Device, error) {
return GetDevices("/dev")
}

// GetDevices recursively traverses a directory specified by path
// and returns all devices found there.
func GetDevices(path string) ([]*config.Device, error) {
files, err := osReadDir(path)
if err != nil {
return nil, err
}
var out []*config.Device
for _, f := range files {
switch {
case f.IsDir():
switch f.Name() {
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
// ".udev" added to address https://github.com/opencontainers/runc/issues/2093
case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev":
continue
default:
sub, err := GetDevices(filepath.Join(path, f.Name()))
if err != nil {
return nil, err
}

out = append(out, sub...)
continue
}
case f.Name() == "console":
continue
}
device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
if err != nil {
if errors.Is(err, ErrNotADevice) {
continue
}
if errors.Is(err, os.ErrNotExist) {
continue
}
return nil, err
}
if device.Type == config.FifoDevice {
continue
}
out = append(out, device)
}
return out, nil
}
122 changes: 122 additions & 0 deletions devices/device_unix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//go:build !windows

// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2015-2026 Open Containers Initiative Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// This code originally comes from runc and was taken from this tree:
// <https://github.com/opencontainers/runc/tree/v1.4.0/libcontainer/devices>.

package devices

import (
"errors"
"io/fs"
"os"
"runtime"
"testing"

"github.com/opencontainers/cgroups/devices/config"
"golang.org/x/sys/unix"
)

func cleanupTest() {
unixLstat = unix.Lstat
osReadDir = os.ReadDir
}

func TestDeviceFromPathLstatFailure(t *testing.T) {
testError := errors.New("test error")

// Override unix.Lstat to inject error.
unixLstat = func(path string, stat *unix.Stat_t) error {
return testError
}
defer cleanupTest()

_, err := DeviceFromPath("", "")
if !errors.Is(err, testError) {
t.Fatalf("Unexpected error %v, expected %v", err, testError)
}
}

func TestHostDevicesIoutilReadDirFailure(t *testing.T) {
testError := errors.New("test error")

// Override os.ReadDir to inject error.
osReadDir = func(dirname string) ([]fs.DirEntry, error) {
return nil, testError
}
defer cleanupTest()

_, err := HostDevices()
if !errors.Is(err, testError) {
t.Fatalf("Unexpected error %v, expected %v", err, testError)
}
}

func TestHostDevicesIoutilReadDirDeepFailure(t *testing.T) {
testError := errors.New("test error")
called := false

// Override os.ReadDir to inject error after the first call.
osReadDir = func(dirname string) ([]fs.DirEntry, error) {
if called {
return nil, testError
}
called = true

// Provoke a second call.
fi, err := os.Stat("/tmp")
if err != nil {
t.Fatalf("Unexpected error %v", err)
}

return []fs.DirEntry{fs.FileInfoToDirEntry(fi)}, nil
}
defer cleanupTest()

_, err := HostDevices()
if !errors.Is(err, testError) {
t.Fatalf("Unexpected error %v, expected %v", err, testError)
}
}

func TestHostDevicesAllValid(t *testing.T) {
devices, err := HostDevices()
if err != nil {
t.Fatalf("failed to get host devices: %v", err)
}

for _, device := range devices {
// Devices can't have major number 0 on Linux.
if device.Major == 0 {
logFn := t.Logf
if runtime.GOOS == "linux" {
logFn = t.Errorf
}
logFn("device entry %+v has zero major number", device)
}
switch device.Type {
case config.BlockDevice, config.CharDevice:
case config.FifoDevice:
t.Logf("fifo devices shouldn't show up from HostDevices")
fallthrough
default:
t.Errorf("device entry %+v has unexpected type %v", device, device.Type)
}
}
}
4 changes: 4 additions & 0 deletions devices/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package devices provides some helper functions for constructing device
// configurations for runc. These are exclusively used by higher-level runtimes
// that need to configure runc's device list based on existing devices.
package devices
8 changes: 8 additions & 0 deletions devices/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/moby/sys/devices

go 1.24

require (
github.com/opencontainers/cgroups v0.0.6
golang.org/x/sys v0.30.0
)
4 changes: 4 additions & 0 deletions devices/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/opencontainers/cgroups v0.0.6 h1:tfZFWTIIGaUUFImTyuTg+Mr5x8XRiSdZESgEBW7UxuI=
github.com/opencontainers/cgroups v0.0.6/go.mod h1:oWVzJsKK0gG9SCRBfTpnn16WcGEqDI8PAcpMGbqWxcs=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
Loading