| package mount |
| |
| import ( |
| "bufio" |
| "fmt" |
| "io" |
| "os" |
| "strings" |
| ) |
| |
| const ( |
| /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue |
| (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) |
| |
| (1) mount ID: unique identifier of the mount (may be reused after umount) |
| (2) parent ID: ID of parent (or of self for the top of the mount tree) |
| (3) major:minor: value of st_dev for files on filesystem |
| (4) root: root of the mount within the filesystem |
| (5) mount point: mount point relative to the process's root |
| (6) mount options: per mount options |
| (7) optional fields: zero or more fields of the form "tag[:value]" |
| (8) separator: marks the end of the optional fields |
| (9) filesystem type: name of filesystem of the form "type[.subtype]" |
| (10) mount source: filesystem specific information or "none" |
| (11) super options: per super block options*/ |
| mountinfoFormat = "%d %d %d:%d %s %s %s %s" |
| ) |
| |
| // Parse /proc/self/mountinfo because comparing Dev and ino does not work from |
| // bind mounts |
| func parseMountTable() ([]*Info, error) { |
| f, err := os.Open("/proc/self/mountinfo") |
| if err != nil { |
| return nil, err |
| } |
| defer f.Close() |
| |
| return parseInfoFile(f) |
| } |
| |
| func parseInfoFile(r io.Reader) ([]*Info, error) { |
| var ( |
| s = bufio.NewScanner(r) |
| out = []*Info{} |
| ) |
| |
| for s.Scan() { |
| if err := s.Err(); err != nil { |
| return nil, err |
| } |
| |
| var ( |
| p = &Info{} |
| text = s.Text() |
| optionalFields string |
| ) |
| |
| if _, err := fmt.Sscanf(text, mountinfoFormat, |
| &p.ID, &p.Parent, &p.Major, &p.Minor, |
| &p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil { |
| return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) |
| } |
| // Safe as mountinfo encodes mountpoints with spaces as \040. |
| index := strings.Index(text, " - ") |
| postSeparatorFields := strings.Fields(text[index+3:]) |
| if len(postSeparatorFields) < 3 { |
| return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text) |
| } |
| |
| if optionalFields != "-" { |
| p.Optional = optionalFields |
| } |
| |
| p.Fstype = postSeparatorFields[0] |
| p.Source = postSeparatorFields[1] |
| p.VfsOpts = strings.Join(postSeparatorFields[2:], " ") |
| out = append(out, p) |
| } |
| return out, nil |
| } |
| |
| // PidMountInfo collects the mounts for a specific process ID. If the process |
| // ID is unknown, it is better to use `GetMounts` which will inspect |
| // "/proc/self/mountinfo" instead. |
| func PidMountInfo(pid int) ([]*Info, error) { |
| f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) |
| if err != nil { |
| return nil, err |
| } |
| defer f.Close() |
| |
| return parseInfoFile(f) |
| } |