pkg.re/essentialkaos/ek@v12.36.0+incompatible/system/process/process_mount.go (about) 1 // +build linux 2 3 package process 4 5 // ////////////////////////////////////////////////////////////////////////////////// // 6 // // 7 // Copyright (c) 2021 ESSENTIAL KAOS // 8 // Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0> // 9 // // 10 // ////////////////////////////////////////////////////////////////////////////////// // 11 12 import ( 13 "bufio" 14 "fmt" 15 "os" 16 "strconv" 17 "strings" 18 19 "pkg.re/essentialkaos/ek.v12/strutil" 20 ) 21 22 // ////////////////////////////////////////////////////////////////////////////////// // 23 24 // MountInfo contains information about mounts 25 // https://www.kernel.org/doc/Documentation/filesystems/proc.txt 26 type MountInfo struct { 27 MountID uint16 `json:"mount_id"` // unique identifier of the mount (may be reused after umount) 28 ParentID uint16 `json:"parent_id"` // ID of parent (or of self for the top of the mount tree) 29 StDevMajor uint16 `json:"stdev_major"` // major value of st_dev for files on filesystem 30 StDevMinor uint16 `json:"stdev_minor"` // minor value of st_dev for files on filesystem 31 Root string `json:"root"` // root of the mount within the filesystem 32 MountPoint string `json:"mount_point"` // mount point relative to the process's root 33 MountOptions []string `json:"mount_options"` // per mount options 34 OptionalFields []string `json:"optional_fields"` // zero or more fields of the form "tag[:value]" 35 FSType string `json:"fs_type"` // name of filesystem of the form "type[.subtype]" 36 MountSource string `json:"mount_source"` // filesystem specific information or "none" 37 SuperOptions []string `json:"super_options"` // per super block options 38 } 39 40 // ////////////////////////////////////////////////////////////////////////////////// // 41 42 // codebeat:disable[LOC,ABC] 43 44 // GetMountInfo returns info about process mounts 45 func GetMountInfo(pid int) ([]*MountInfo, error) { 46 fd, err := os.OpenFile(procFS+"/"+strconv.Itoa(pid)+"/mountinfo", os.O_RDONLY, 0) 47 48 if err != nil { 49 return nil, err 50 } 51 52 defer fd.Close() 53 54 r := bufio.NewReader(fd) 55 s := bufio.NewScanner(r) 56 57 var result []*MountInfo 58 59 for s.Scan() { 60 info, err := parseMountInfoLine(s.Text()) 61 62 if err != nil { 63 return nil, err 64 } 65 66 result = append(result, info) 67 } 68 69 return result, nil 70 } 71 72 // ////////////////////////////////////////////////////////////////////////////////// // 73 74 // parseMountInfoLine parses mount info from given line 75 func parseMountInfoLine(data string) (*MountInfo, error) { 76 var err error 77 78 info := &MountInfo{} 79 80 optFieldsNum := 0 81 optFieldParsed := false 82 83 for i := 0; i < 128; i++ { 84 pseudoIndex := i - optFieldsNum 85 value := strutil.ReadField(data, i, false, " ") 86 87 if i >= 6 && !optFieldParsed { 88 if value != "-" { 89 info.OptionalFields = append(info.OptionalFields, value) 90 } else { 91 optFieldParsed = true 92 } 93 94 optFieldsNum++ 95 continue 96 } 97 98 switch pseudoIndex { 99 case 0: 100 info.MountID, err = parseFieldUint16(value, "MountID") 101 case 1: 102 info.ParentID, err = parseFieldUint16(value, "MountID") 103 case 2: 104 info.StDevMajor, info.StDevMinor, err = parseStDevValue(value) 105 case 3: 106 info.Root = value 107 case 4: 108 info.MountPoint = value 109 case 5: 110 info.MountOptions = strings.Split(value, ",") 111 case 6: 112 info.FSType = value 113 case 7: 114 info.MountSource = value 115 case 8: 116 info.SuperOptions = strings.Split(value, ",") 117 default: 118 break 119 } 120 121 if err != nil { 122 return nil, err 123 } 124 } 125 126 return info, nil 127 } 128 129 // codebeat:enable[LOC,ABC] 130 131 // parseStDevValue parses st_dev major and minor values 132 func parseStDevValue(data string) (uint16, uint16, error) { 133 major, err := parseFieldUint16(strutil.ReadField(data, 0, false, ":"), "StDevMajor") 134 135 if err != nil { 136 return 0, 0, err 137 } 138 139 minor, err := parseFieldUint16(strutil.ReadField(data, 1, false, ":"), "StDevMinor") 140 141 if err != nil { 142 return 0, 0, err 143 } 144 145 return major, minor, nil 146 } 147 148 // parseFieldUint16 parses uint fields 149 func parseFieldUint16(s, field string) (uint16, error) { 150 u, err := strconv.ParseUint(s, 10, 16) 151 152 if err != nil { 153 return 0, fmt.Errorf("Can't parse field %s: %w", field, err) 154 } 155 156 return uint16(u), nil 157 }