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  }