github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/common/common_linux.go (about) 1 //go:build linux 2 // +build linux 3 4 package common 5 6 import ( 7 "context" 8 "fmt" 9 "log" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "strconv" 14 "strings" 15 "time" 16 ) 17 18 func DoSysctrl(mib string) ([]string, error) { 19 sysctl, err := exec.LookPath("sysctl") 20 if err != nil { 21 return []string{}, err 22 } 23 cmd := exec.Command(sysctl, "-n", mib) 24 cmd.Env = getSysctrlEnv(os.Environ()) 25 out, err := cmd.Output() 26 if err != nil { 27 return []string{}, err 28 } 29 v := strings.Replace(string(out), "{ ", "", 1) 30 v = strings.Replace(string(v), " }", "", 1) 31 values := strings.Fields(string(v)) 32 33 return values, nil 34 } 35 36 func NumProcs() (uint64, error) { 37 f, err := os.Open(HostProc()) 38 if err != nil { 39 return 0, err 40 } 41 defer func(f *os.File) { 42 err := f.Close() 43 if err != nil { 44 log.Fatalln(err) 45 } 46 }(f) 47 48 list, err := f.Readdirnames(-1) 49 if err != nil { 50 return 0, err 51 } 52 var cnt uint64 53 54 for _, v := range list { 55 if _, err = strconv.ParseUint(v, 10, 64); err == nil { 56 cnt++ 57 } 58 } 59 60 return cnt, nil 61 } 62 63 func BootTimeWithContext(ctx context.Context) (uint64, error) { 64 65 system, role, err := Virtualization() 66 if err != nil { 67 return 0, err 68 } 69 70 statFile := "stat" 71 if system == "lxc" && role == "guest" { 72 // if lxc, /proc/uptime is used. 73 statFile = "uptime" 74 } else if system == "docker" && role == "guest" { 75 // also docker, guest 76 statFile = "uptime" 77 } 78 79 filename := HostProc(statFile) 80 lines, err := ReadLines(filename) 81 if err != nil { 82 return 0, err 83 } 84 85 if statFile == "stat" { 86 for _, line := range lines { 87 if strings.HasPrefix(line, "btime") { 88 f := strings.Fields(line) 89 if len(f) != 2 { 90 return 0, fmt.Errorf("wrong btime format") 91 } 92 b, err := strconv.ParseInt(f[1], 10, 64) 93 if err != nil { 94 return 0, err 95 } 96 t := uint64(b) 97 return t, nil 98 } 99 } 100 } else if statFile == "uptime" { 101 if len(lines) != 1 { 102 return 0, fmt.Errorf("wrong uptime format") 103 } 104 f := strings.Fields(lines[0]) 105 b, err := strconv.ParseFloat(f[0], 64) 106 if err != nil { 107 return 0, err 108 } 109 t := uint64(time.Now().Unix()) - uint64(b) 110 return t, nil 111 } 112 113 return 0, fmt.Errorf("could not find btime") 114 } 115 116 func Virtualization() (string, string, error) { 117 return VirtualizationWithContext(context.Background()) 118 } 119 120 func VirtualizationWithContext(ctx context.Context) (string, string, error) { 121 var system string 122 var role string 123 124 filename := HostProc("xen") 125 if PathExists(filename) { 126 system = "xen" 127 role = "guest" // assume guest 128 129 if PathExists(filepath.Join(filename, "capabilities")) { 130 contents, err := ReadLines(filepath.Join(filename, "capabilities")) 131 if err == nil { 132 if StringsContains(contents, "control_d") { 133 role = "host" 134 } 135 } 136 } 137 } 138 139 filename = HostProc("modules") 140 if PathExists(filename) { 141 contents, err := ReadLines(filename) 142 if err == nil { 143 if StringsContains(contents, "kvm") { 144 system = "kvm" 145 role = "host" 146 } else if StringsContains(contents, "vboxdrv") { 147 system = "vbox" 148 role = "host" 149 } else if StringsContains(contents, "vboxguest") { 150 system = "vbox" 151 role = "guest" 152 } else if StringsContains(contents, "vmware") { 153 system = "vmware" 154 role = "guest" 155 } 156 } 157 } 158 159 filename = HostProc("cpuinfo") 160 if PathExists(filename) { 161 contents, err := ReadLines(filename) 162 if err == nil { 163 if StringsContains(contents, "QEMU Virtual CPU") || 164 StringsContains(contents, "Common KVM processor") || 165 StringsContains(contents, "Common 32-bit KVM processor") { 166 system = "kvm" 167 role = "guest" 168 } 169 } 170 } 171 172 filename = HostProc("bus/pci/devices") 173 if PathExists(filename) { 174 contents, err := ReadLines(filename) 175 if err == nil { 176 if StringsContains(contents, "virtio-pci") { 177 role = "guest" 178 } 179 } 180 } 181 182 filename = HostProc() 183 if PathExists(filepath.Join(filename, "bc", "0")) { 184 system = "openvz" 185 role = "host" 186 } else if PathExists(filepath.Join(filename, "vz")) { 187 system = "openvz" 188 role = "guest" 189 } 190 191 // not use dmidecode because it requires root 192 if PathExists(filepath.Join(filename, "self", "status")) { 193 contents, err := ReadLines(filepath.Join(filename, "self", "status")) 194 if err == nil { 195 196 if StringsContains(contents, "s_context:") || 197 StringsContains(contents, "VxID:") { 198 system = "linux-vserver" 199 } 200 // TODO: guest or host 201 } 202 } 203 204 if PathExists(filepath.Join(filename, "1", "environ")) { 205 contents, err := ReadFile(filepath.Join(filename, "1", "environ")) 206 207 if err == nil { 208 if strings.Contains(contents, "container=lxc") { 209 system = "lxc" 210 role = "guest" 211 } 212 } 213 } 214 215 if PathExists(filepath.Join(filename, "self", "cgroup")) { 216 contents, err := ReadLines(filepath.Join(filename, "self", "cgroup")) 217 if err == nil { 218 if StringsContains(contents, "lxc") { 219 system = "lxc" 220 role = "guest" 221 } else if StringsContains(contents, "docker") { 222 system = "docker" 223 role = "guest" 224 } else if StringsContains(contents, "machine-rkt") { 225 system = "rkt" 226 role = "guest" 227 } else if PathExists("/usr/bin/lxc-version") { 228 system = "lxc" 229 role = "host" 230 } 231 } 232 } 233 234 if PathExists(HostEtc("os-release")) { 235 p, _, err := GetOSRelease() 236 if err == nil && p == "coreos" { 237 system = "rkt" // Is it true? 238 role = "host" 239 } 240 } 241 return system, role, nil 242 } 243 244 func GetOSRelease() (platform string, version string, err error) { 245 contents, err := ReadLines(HostEtc("os-release")) 246 if err != nil { 247 return "", "", nil // return empty 248 } 249 for _, line := range contents { 250 field := strings.Split(line, "=") 251 if len(field) < 2 { 252 continue 253 } 254 switch field[0] { 255 case "ID": // use ID for lowercase 256 platform = trimQuotes(field[1]) 257 case "VERSION": 258 version = trimQuotes(field[1]) 259 } 260 } 261 return platform, version, nil 262 } 263 264 // Remove quotes of the source string 265 func trimQuotes(s string) string { 266 if len(s) >= 2 { 267 if s[0] == '"' && s[len(s)-1] == '"' { 268 return s[1 : len(s)-1] 269 } 270 } 271 return s 272 }