github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/common/common.go (about) 1 package common 2 3 // 4 // gopsutil is a port of psutil(http://pythonhosted.org/psutil/). 5 // This covers these architectures. 6 // - linux (amd64, arm) 7 // - freebsd (amd64) 8 // - windows (amd64) 9 import ( 10 "bufio" 11 "bytes" 12 "context" 13 "errors" 14 "fmt" 15 "log" 16 "net/url" 17 "os" 18 "os/exec" 19 "path" 20 "path/filepath" 21 "reflect" 22 "runtime" 23 "strconv" 24 "strings" 25 "time" 26 ) 27 28 var ( 29 Timeout = 3 * time.Second 30 ErrTimeout = errors.New("command timed out") 31 ) 32 33 type Invoker interface { 34 Command(string, ...string) ([]byte, error) 35 CommandWithContext(context.Context, string, ...string) ([]byte, error) 36 } 37 38 type Invoke struct{} 39 40 func (i Invoke) Command(name string, arg ...string) ([]byte, error) { 41 ctx, cancel := context.WithTimeout(context.Background(), Timeout) 42 defer cancel() 43 return i.CommandWithContext(ctx, name, arg...) 44 } 45 46 func (i Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) { 47 cmd := exec.CommandContext(ctx, name, arg...) 48 49 var buf bytes.Buffer 50 cmd.Stdout = &buf 51 cmd.Stderr = &buf 52 53 if err := cmd.Start(); err != nil { 54 return buf.Bytes(), err 55 } 56 57 if err := cmd.Wait(); err != nil { 58 return buf.Bytes(), err 59 } 60 61 return buf.Bytes(), nil 62 } 63 64 type FakeInvoke struct { 65 Suffix string // Suffix species expected file name suffix such as "fail" 66 Error error // If Error specfied, return the error. 67 } 68 69 // Command in FakeInvoke returns from expected file if exists. 70 func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) { 71 if i.Error != nil { 72 return []byte{}, i.Error 73 } 74 75 arch := runtime.GOOS 76 77 commandName := filepath.Base(name) 78 79 fname := strings.Join(append([]string{commandName}, arg...), "") 80 fname = url.QueryEscape(fname) 81 fpath := path.Join("testdata", arch, fname) 82 if i.Suffix != "" { 83 fpath += "_" + i.Suffix 84 } 85 if PathExists(fpath) { 86 return os.ReadFile(fpath) 87 } 88 return []byte{}, fmt.Errorf("could not find testdata: %s", fpath) 89 } 90 91 func (i FakeInvoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) { 92 return i.Command(name, arg...) 93 } 94 95 var ErrNotImplementedError = errors.New("not implemented yet") 96 97 // ReadFile reads contents from a file 98 func ReadFile(filename string) (string, error) { 99 content, err := os.ReadFile(filename) 100 101 if err != nil { 102 return "", err 103 } 104 105 return string(content), nil 106 } 107 108 // ReadLines reads contents from a file and splits them by new lines. 109 // A convenience wrapper to ReadLinesOffsetN(filename, 0, -1). 110 func ReadLines(filename string) ([]string, error) { 111 return ReadLinesOffsetN(filename, 0, -1) 112 } 113 114 // ReadLines reads contents from file and splits them by new line. 115 // The offset tells at which line number to start. 116 // The count determines the number of lines to read (starting from offset): 117 // 118 // n >= 0: at most n lines 119 // n < 0: whole file 120 func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) { 121 f, err := os.Open(filename) 122 if err != nil { 123 return []string{""}, err 124 } 125 defer func(f *os.File) { 126 err := f.Close() 127 if err != nil { 128 log.Fatalln(err) 129 } 130 }(f) 131 132 var ret []string 133 134 r := bufio.NewReader(f) 135 for i := 0; i < n+int(offset) || n < 0; i++ { 136 line, err := r.ReadString('\n') 137 if err != nil { 138 break 139 } 140 if i < int(offset) { 141 continue 142 } 143 ret = append(ret, strings.Trim(line, "\n")) 144 } 145 146 return ret, nil 147 } 148 149 func IntToString(orig []int8) string { 150 ret := make([]byte, len(orig)) 151 size := -1 152 for i, o := range orig { 153 if o == 0 { 154 size = i 155 break 156 } 157 ret[i] = byte(o) 158 } 159 if size == -1 { 160 size = len(orig) 161 } 162 163 return string(ret[0:size]) 164 } 165 166 func UintToString(orig []uint8) string { 167 ret := make([]byte, len(orig)) 168 size := -1 169 for i, o := range orig { 170 if o == 0 { 171 size = i 172 break 173 } 174 ret[i] = byte(o) 175 } 176 if size == -1 { 177 size = len(orig) 178 } 179 180 return string(ret[0:size]) 181 } 182 183 func ByteToString(orig []byte) string { 184 n := -1 185 l := -1 186 for i, b := range orig { 187 // skip left side null 188 if l == -1 && b == 0 { 189 continue 190 } 191 if l == -1 { 192 l = i 193 } 194 195 if b == 0 { 196 break 197 } 198 n = i + 1 199 } 200 if n == -1 { 201 return string(orig) 202 } 203 return string(orig[l:n]) 204 } 205 206 // ReadInts reads contents from single line file and returns them as []int32. 207 func ReadInts(filename string) ([]int64, error) { 208 f, err := os.Open(filename) 209 if err != nil { 210 return []int64{}, err 211 } 212 defer func(f *os.File) { 213 err := f.Close() 214 if err != nil { 215 log.Fatalln(err) 216 } 217 }(f) 218 219 var ret []int64 220 221 r := bufio.NewReader(f) 222 223 // The int files that this is concerned with should only be one liners. 224 line, err := r.ReadString('\n') 225 if err != nil { 226 return []int64{}, err 227 } 228 229 i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32) 230 if err != nil { 231 return []int64{}, err 232 } 233 ret = append(ret, i) 234 235 return ret, nil 236 } 237 238 // Parse Hex to uint32 without error 239 func HexToUint32(hex string) uint32 { 240 vv, _ := strconv.ParseUint(hex, 16, 32) 241 return uint32(vv) 242 } 243 244 // Parse to int32 without error 245 func mustParseInt32(val string) int32 { 246 vv, _ := strconv.ParseInt(val, 10, 32) 247 return int32(vv) 248 } 249 250 // Parse to uint64 without error 251 func mustParseUint64(val string) uint64 { 252 vv, _ := strconv.ParseInt(val, 10, 64) 253 return uint64(vv) 254 } 255 256 // Parse to Float64 without error 257 func mustParseFloat64(val string) float64 { 258 vv, _ := strconv.ParseFloat(val, 64) 259 return vv 260 } 261 262 // StringsHas checks the target string slice contains src or not 263 func StringsHas(target []string, src string) bool { 264 for _, t := range target { 265 if strings.TrimSpace(t) == src { 266 return true 267 } 268 } 269 return false 270 } 271 272 // StringsContains checks the src in any string of the target string slice 273 func StringsContains(target []string, src string) bool { 274 for _, t := range target { 275 if strings.Contains(t, src) { 276 return true 277 } 278 } 279 return false 280 } 281 282 // IntContains checks the src in any int of the target int slice. 283 func IntContains(target []int, src int) bool { 284 for _, t := range target { 285 if src == t { 286 return true 287 } 288 } 289 return false 290 } 291 292 // get struct attributes. 293 // This method is used only for debugging platform dependent code. 294 func attributes(m interface{}) map[string]reflect.Type { 295 typ := reflect.TypeOf(m) 296 if typ.Kind() == reflect.Ptr { 297 typ = typ.Elem() 298 } 299 300 attrs := make(map[string]reflect.Type) 301 if typ.Kind() != reflect.Struct { 302 return nil 303 } 304 305 for i := 0; i < typ.NumField(); i++ { 306 p := typ.Field(i) 307 if !p.Anonymous { 308 attrs[p.Name] = p.Type 309 } 310 } 311 312 return attrs 313 } 314 315 func PathExists(filename string) bool { 316 if _, err := os.Stat(filename); err == nil { 317 return true 318 } 319 return false 320 } 321 322 // GetEnv retrieves the environment variable key. If it does not exist it returns the default. 323 func GetEnv(key string, dfault string, combineWith ...string) string { 324 value := os.Getenv(key) 325 if value == "" { 326 value = dfault 327 } 328 329 switch len(combineWith) { 330 case 0: 331 return value 332 case 1: 333 return filepath.Join(value, combineWith[0]) 334 default: 335 all := make([]string, len(combineWith)+1) 336 all[0] = value 337 copy(all[1:], combineWith) 338 return filepath.Join(all...) 339 } 340 } 341 342 func HostProc(combineWith ...string) string { 343 return GetEnv("HOST_PROC", "/proc", combineWith...) 344 } 345 346 func HostSys(combineWith ...string) string { 347 return GetEnv("HOST_SYS", "/sys", combineWith...) 348 } 349 350 func HostEtc(combineWith ...string) string { 351 return GetEnv("HOST_ETC", "/etc", combineWith...) 352 } 353 354 func HostVar(combineWith ...string) string { 355 return GetEnv("HOST_VAR", "/var", combineWith...) 356 } 357 358 func HostRun(combineWith ...string) string { 359 return GetEnv("HOST_RUN", "/run", combineWith...) 360 } 361 362 func HostDev(combineWith ...string) string { 363 return GetEnv("HOST_DEV", "/dev", combineWith...) 364 } 365 366 // getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running 367 // sysctl commands (see DoSysctrl). 368 func getSysctrlEnv(env []string) []string { 369 foundLC := false 370 for i, line := range env { 371 if strings.HasPrefix(line, "LC_ALL") { 372 env[i] = "LC_ALL=C" 373 foundLC = true 374 } 375 } 376 if !foundLC { 377 env = append(env, "LC_ALL=C") 378 } 379 return env 380 }