mount_linux.go 2.2 KB

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