container-edits_unix.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. //go:build !windows
  2. // +build !windows
  3. /*
  4. Copyright © 2021 The CDI Authors
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. */
  15. package cdi
  16. import (
  17. "errors"
  18. "fmt"
  19. "golang.org/x/sys/unix"
  20. )
  21. const (
  22. blockDevice = "b"
  23. charDevice = "c" // or "u"
  24. fifoDevice = "p"
  25. )
  26. // deviceInfoFromPath takes the path to a device and returns its type,
  27. // major and minor device numbers.
  28. //
  29. // It was adapted from https://github.com/opencontainers/runc/blob/v1.1.9/libcontainer/devices/device_unix.go#L30-L69
  30. func deviceInfoFromPath(path string) (devType string, major, minor int64, _ error) {
  31. var stat unix.Stat_t
  32. err := unix.Lstat(path, &stat)
  33. if err != nil {
  34. return "", 0, 0, err
  35. }
  36. switch stat.Mode & unix.S_IFMT {
  37. case unix.S_IFBLK:
  38. devType = blockDevice
  39. case unix.S_IFCHR:
  40. devType = charDevice
  41. case unix.S_IFIFO:
  42. devType = fifoDevice
  43. default:
  44. return "", 0, 0, errors.New("not a device node")
  45. }
  46. devNumber := uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on e.g. MIPS.
  47. return devType, int64(unix.Major(devNumber)), int64(unix.Minor(devNumber)), nil
  48. }
  49. // fillMissingInfo fills in missing mandatory attributes from the host device.
  50. func (d *DeviceNode) fillMissingInfo() error {
  51. if d.HostPath == "" {
  52. d.HostPath = d.Path
  53. }
  54. if d.Type != "" && (d.Major != 0 || d.Type == "p") {
  55. return nil
  56. }
  57. deviceType, major, minor, err := deviceInfoFromPath(d.HostPath)
  58. if err != nil {
  59. return fmt.Errorf("failed to stat CDI host device %q: %w", d.HostPath, err)
  60. }
  61. if d.Type == "" {
  62. d.Type = deviceType
  63. } else {
  64. if d.Type != deviceType {
  65. return fmt.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)",
  66. d.Path, d.HostPath, d.Type, deviceType)
  67. }
  68. }
  69. if d.Major == 0 && d.Type != "p" {
  70. d.Major = major
  71. d.Minor = minor
  72. }
  73. return nil
  74. }