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