...
1
2
3
4 package devices
5
6 import (
7 "errors"
8 "os"
9 "path/filepath"
10
11 "golang.org/x/sys/unix"
12 )
13
14
15 var ErrNotADevice = errors.New("not a device node")
16
17
18 var (
19 unixLstat = unix.Lstat
20 osReadDir = os.ReadDir
21 )
22
23 func mkDev(d *Rule) (uint64, error) {
24 if d.Major == Wildcard || d.Minor == Wildcard {
25 return 0, errors.New("cannot mkdev() device with wildcards")
26 }
27 return unix.Mkdev(uint32(d.Major), uint32(d.Minor)), nil
28 }
29
30
31
32
33 func DeviceFromPath(path, permissions string) (*Device, error) {
34 var stat unix.Stat_t
35 err := unixLstat(path, &stat)
36 if err != nil {
37 return nil, err
38 }
39
40 var (
41 devType Type
42 mode = stat.Mode
43 devNumber = uint64(stat.Rdev)
44 major = unix.Major(devNumber)
45 minor = unix.Minor(devNumber)
46 )
47 switch mode & unix.S_IFMT {
48 case unix.S_IFBLK:
49 devType = BlockDevice
50 case unix.S_IFCHR:
51 devType = CharDevice
52 case unix.S_IFIFO:
53 devType = FifoDevice
54 default:
55 return nil, ErrNotADevice
56 }
57 return &Device{
58 Rule: Rule{
59 Type: devType,
60 Major: int64(major),
61 Minor: int64(minor),
62 Permissions: Permissions(permissions),
63 },
64 Path: path,
65 FileMode: os.FileMode(mode &^ unix.S_IFMT),
66 Uid: stat.Uid,
67 Gid: stat.Gid,
68 }, nil
69 }
70
71
72 func HostDevices() ([]*Device, error) {
73 return GetDevices("/dev")
74 }
75
76
77
78 func GetDevices(path string) ([]*Device, error) {
79 files, err := osReadDir(path)
80 if err != nil {
81 return nil, err
82 }
83 var out []*Device
84 for _, f := range files {
85 switch {
86 case f.IsDir():
87 switch f.Name() {
88
89
90 case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev":
91 continue
92 default:
93 sub, err := GetDevices(filepath.Join(path, f.Name()))
94 if err != nil {
95 return nil, err
96 }
97
98 out = append(out, sub...)
99 continue
100 }
101 case f.Name() == "console":
102 continue
103 }
104 device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
105 if err != nil {
106 if errors.Is(err, ErrNotADevice) {
107 continue
108 }
109 if os.IsNotExist(err) {
110 continue
111 }
112 return nil, err
113 }
114 if device.Type == FifoDevice {
115 continue
116 }
117 out = append(out, device)
118 }
119 return out, nil
120 }
121
View as plain text