github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/pkg/mount/mountinfo_linux.go (about) 1 package mount // import "github.com/docker/docker/pkg/mount" 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "os" 8 "strconv" 9 "strings" 10 ) 11 12 func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) { 13 s := bufio.NewScanner(r) 14 out := []*Info{} 15 for s.Scan() { 16 if err := s.Err(); err != nil { 17 return nil, err 18 } 19 /* 20 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue 21 (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) 22 23 (1) mount ID: unique identifier of the mount (may be reused after umount) 24 (2) parent ID: ID of parent (or of self for the top of the mount tree) 25 (3) major:minor: value of st_dev for files on filesystem 26 (4) root: root of the mount within the filesystem 27 (5) mount point: mount point relative to the process's root 28 (6) mount options: per mount options 29 (7) optional fields: zero or more fields of the form "tag[:value]" 30 (8) separator: marks the end of the optional fields 31 (9) filesystem type: name of filesystem of the form "type[.subtype]" 32 (10) mount source: filesystem specific information or "none" 33 (11) super options: per super block options 34 */ 35 36 text := s.Text() 37 fields := strings.Split(text, " ") 38 numFields := len(fields) 39 if numFields < 10 { 40 // should be at least 10 fields 41 return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields) 42 } 43 44 p := &Info{} 45 // ignore any numbers parsing errors, as there should not be any 46 p.ID, _ = strconv.Atoi(fields[0]) 47 p.Parent, _ = strconv.Atoi(fields[1]) 48 mm := strings.Split(fields[2], ":") 49 if len(mm) != 2 { 50 return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm) 51 } 52 p.Major, _ = strconv.Atoi(mm[0]) 53 p.Minor, _ = strconv.Atoi(mm[1]) 54 55 p.Root = fields[3] 56 p.Mountpoint = fields[4] 57 p.Opts = fields[5] 58 59 var skip, stop bool 60 if filter != nil { 61 // filter out entries we're not interested in 62 skip, stop = filter(p) 63 if skip { 64 continue 65 } 66 } 67 68 // one or more optional fields, when a separator (-) 69 i := 6 70 for ; i < numFields && fields[i] != "-"; i++ { 71 switch i { 72 case 6: 73 p.Optional = fields[6] 74 default: 75 /* NOTE there might be more optional fields before the such as 76 fields[7]...fields[N] (where N < sepIndex), although 77 as of Linux kernel 4.15 the only known ones are 78 mount propagation flags in fields[6]. The correct 79 behavior is to ignore any unknown optional fields. 80 */ 81 break 82 } 83 } 84 if i == numFields { 85 return nil, fmt.Errorf("Parsing '%s' failed: missing separator ('-')", text) 86 } 87 88 // There should be 3 fields after the separator... 89 if i+4 > numFields { 90 return nil, fmt.Errorf("Parsing '%s' failed: not enough fields after a separator", text) 91 } 92 // ... but in Linux <= 3.9 mounting a cifs with spaces in a share name 93 // (like "//serv/My Documents") _may_ end up having a space in the last field 94 // of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs 95 // option unc= is ignored, so a space should not appear. In here we ignore 96 // those "extra" fields caused by extra spaces. 97 p.Fstype = fields[i+1] 98 p.Source = fields[i+2] 99 p.VfsOpts = fields[i+3] 100 101 out = append(out, p) 102 if stop { 103 break 104 } 105 } 106 return out, nil 107 } 108 109 // Parse /proc/self/mountinfo because comparing Dev and ino does not work from 110 // bind mounts 111 func parseMountTable(filter FilterFunc) ([]*Info, error) { 112 f, err := os.Open("/proc/self/mountinfo") 113 if err != nil { 114 return nil, err 115 } 116 defer f.Close() 117 118 return parseInfoFile(f, filter) 119 } 120 121 // PidMountInfo collects the mounts for a specific process ID. If the process 122 // ID is unknown, it is better to use `GetMounts` which will inspect 123 // "/proc/self/mountinfo" instead. 124 func PidMountInfo(pid int) ([]*Info, error) { 125 f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) 126 if err != nil { 127 return nil, err 128 } 129 defer f.Close() 130 131 return parseInfoFile(f, nil) 132 }