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