devices_unix.go 2.2 KB

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