devices_linux.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package devices
  2. import (
  3. "errors"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "github.com/opencontainers/runc/libcontainer/configs"
  8. "golang.org/x/sys/unix"
  9. )
  10. var (
  11. ErrNotADevice = errors.New("not a device node")
  12. )
  13. // Testing dependencies
  14. var (
  15. unixLstat = unix.Lstat
  16. ioutilReadDir = ioutil.ReadDir
  17. )
  18. // Given the path to a device and its cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct.
  19. func DeviceFromPath(path, permissions string) (*configs.Device, error) {
  20. var stat unix.Stat_t
  21. err := unixLstat(path, &stat)
  22. if err != nil {
  23. return nil, err
  24. }
  25. var (
  26. devNumber = int(stat.Rdev)
  27. major = Major(devNumber)
  28. )
  29. if major == 0 {
  30. return nil, ErrNotADevice
  31. }
  32. var (
  33. devType rune
  34. mode = stat.Mode
  35. )
  36. switch {
  37. case mode&unix.S_IFBLK == unix.S_IFBLK:
  38. devType = 'b'
  39. case mode&unix.S_IFCHR == unix.S_IFCHR:
  40. devType = 'c'
  41. }
  42. return &configs.Device{
  43. Type: devType,
  44. Path: path,
  45. Major: major,
  46. Minor: Minor(devNumber),
  47. Permissions: permissions,
  48. FileMode: os.FileMode(mode),
  49. Uid: stat.Uid,
  50. Gid: stat.Gid,
  51. }, nil
  52. }
  53. func HostDevices() ([]*configs.Device, error) {
  54. return getDevices("/dev")
  55. }
  56. func getDevices(path string) ([]*configs.Device, error) {
  57. files, err := ioutilReadDir(path)
  58. if err != nil {
  59. return nil, err
  60. }
  61. out := []*configs.Device{}
  62. for _, f := range files {
  63. switch {
  64. case f.IsDir():
  65. switch f.Name() {
  66. // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
  67. case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts":
  68. continue
  69. default:
  70. sub, err := getDevices(filepath.Join(path, f.Name()))
  71. if err != nil {
  72. return nil, err
  73. }
  74. out = append(out, sub...)
  75. continue
  76. }
  77. case f.Name() == "console":
  78. continue
  79. }
  80. device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
  81. if err != nil {
  82. if err == ErrNotADevice {
  83. continue
  84. }
  85. if os.IsNotExist(err) {
  86. continue
  87. }
  88. return nil, err
  89. }
  90. out = append(out, device)
  91. }
  92. return out, nil
  93. }