mountinfo.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. package mount
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "os"
  7. "strings"
  8. )
  9. const (
  10. /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
  11. (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
  12. (1) mount ID: unique identifier of the mount (may be reused after umount)
  13. (2) parent ID: ID of parent (or of self for the top of the mount tree)
  14. (3) major:minor: value of st_dev for files on filesystem
  15. (4) root: root of the mount within the filesystem
  16. (5) mount point: mount point relative to the process's root
  17. (6) mount options: per mount options
  18. (7) optional fields: zero or more fields of the form "tag[:value]"
  19. (8) separator: marks the end of the optional fields
  20. (9) filesystem type: name of filesystem of the form "type[.subtype]"
  21. (10) mount source: filesystem specific information or "none"
  22. (11) super options: per super block options*/
  23. mountinfoFormat = "%d %d %d:%d %s %s %s "
  24. )
  25. type MountInfo struct {
  26. Id, Parent, Major, Minor int
  27. Root, Mountpoint, Opts string
  28. Fstype, Source, VfsOpts string
  29. }
  30. // Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts
  31. func parseMountTable() ([]*MountInfo, error) {
  32. f, err := os.Open("/proc/self/mountinfo")
  33. if err != nil {
  34. return nil, err
  35. }
  36. defer f.Close()
  37. return parseInfoFile(f)
  38. }
  39. func parseInfoFile(r io.Reader) ([]*MountInfo, error) {
  40. var (
  41. s = bufio.NewScanner(r)
  42. out = []*MountInfo{}
  43. )
  44. for s.Scan() {
  45. if err := s.Err(); err != nil {
  46. return nil, err
  47. }
  48. var (
  49. p = &MountInfo{}
  50. text = s.Text()
  51. )
  52. if _, err := fmt.Sscanf(text, mountinfoFormat,
  53. &p.Id, &p.Parent, &p.Major, &p.Minor,
  54. &p.Root, &p.Mountpoint, &p.Opts); err != nil {
  55. return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
  56. }
  57. // Safe as mountinfo encodes mountpoints with spaces as \040.
  58. index := strings.Index(text, " - ")
  59. postSeparatorFields := strings.Fields(text[index+3:])
  60. if len(postSeparatorFields) != 3 {
  61. return nil, fmt.Errorf("Error did not find 3 fields post '-' in '%s'", text)
  62. }
  63. p.Fstype = postSeparatorFields[0]
  64. p.Source = postSeparatorFields[1]
  65. p.VfsOpts = postSeparatorFields[2]
  66. out = append(out, p)
  67. }
  68. return out, nil
  69. }