//go:build linux

package common

import (
	
	
	
	
	
	
	
	
	
)

func ( string) ([]string, error) {
	,  := exec.LookPath("sysctl")
	if  != nil {
		return []string{}, 
	}
	 := exec.Command(, "-n", )
	.Env = getSysctrlEnv(os.Environ())
	,  := .Output()
	if  != nil {
		return []string{}, 
	}
	 := strings.Replace(string(), "{ ", "", 1)
	 = strings.Replace(string(), " }", "", 1)
	 := strings.Fields(string())

	return , nil
}

func () (uint64, error) {
	,  := os.Open(HostProc())
	if  != nil {
		return 0, 
	}
	defer func( *os.File) {
		 := .Close()
		if  != nil {
			log.Fatalln()
		}
	}()

	,  := .Readdirnames(-1)
	if  != nil {
		return 0, 
	}
	var  uint64

	for ,  := range  {
		if _,  = strconv.ParseUint(, 10, 64);  == nil {
			++
		}
	}

	return , nil
}

func ( context.Context) (uint64, error) {
	, ,  := Virtualization()
	if  != nil {
		return 0, 
	}

	 := "stat"
	if  == "lxc" &&  == "guest" {
		// if lxc, /proc/uptime is used.
		 = "uptime"
	} else if  == "docker" &&  == "guest" {
		// also docker, guest
		 = "uptime"
	}

	 := HostProc()
	,  := ReadLines()
	if  != nil {
		return 0, 
	}

	if  == "stat" {
		for ,  := range  {
			if strings.HasPrefix(, "btime") {
				 := strings.Fields()
				if len() != 2 {
					return 0, fmt.Errorf("wrong btime format")
				}
				,  := strconv.ParseInt([1], 10, 64)
				if  != nil {
					return 0, 
				}
				 := uint64()
				return , nil
			}
		}
	} else if  == "uptime" {
		if len() != 1 {
			return 0, fmt.Errorf("wrong uptime format")
		}
		 := strings.Fields([0])
		,  := strconv.ParseFloat([0], 64)
		if  != nil {
			return 0, 
		}
		 := uint64(time.Now().Unix()) - uint64()
		return , nil
	}

	return 0, fmt.Errorf("could not find btime")
}

func () (string, string, error) {
	return VirtualizationWithContext(context.Background())
}

func ( context.Context) (string, string, error) {
	var  string
	var  string

	 := HostProc("xen")
	if PathExists() {
		 = "xen"
		 = "guest" // assume guest

		if PathExists(filepath.Join(, "capabilities")) {
			,  := ReadLines(filepath.Join(, "capabilities"))
			if  == nil {
				if StringsContains(, "control_d") {
					 = "host"
				}
			}
		}
	}

	 = HostProc("modules")
	if PathExists() {
		,  := ReadLines()
		if  == nil {
			if StringsContains(, "kvm") {
				 = "kvm"
				 = "host"
			} else if StringsContains(, "vboxdrv") {
				 = "vbox"
				 = "host"
			} else if StringsContains(, "vboxguest") {
				 = "vbox"
				 = "guest"
			} else if StringsContains(, "vmware") {
				 = "vmware"
				 = "guest"
			}
		}
	}

	 = HostProc("cpuinfo")
	if PathExists() {
		,  := ReadLines()
		if  == nil {
			if StringsContains(, "QEMU Virtual CPU") ||
				StringsContains(, "Common KVM processor") ||
				StringsContains(, "Common 32-bit KVM processor") {
				 = "kvm"
				 = "guest"
			}
		}
	}

	 = HostProc("bus/pci/devices")
	if PathExists() {
		,  := ReadLines()
		if  == nil {
			if StringsContains(, "virtio-pci") {
				 = "guest"
			}
		}
	}

	 = HostProc()
	if PathExists(filepath.Join(, "bc", "0")) {
		 = "openvz"
		 = "host"
	} else if PathExists(filepath.Join(, "vz")) {
		 = "openvz"
		 = "guest"
	}

	// not use dmidecode because it requires root
	if PathExists(filepath.Join(, "self", "status")) {
		,  := ReadLines(filepath.Join(, "self", "status"))
		if  == nil {
			if StringsContains(, "s_context:") ||
				StringsContains(, "VxID:") {
				 = "linux-vserver"
			}
			// TODO: guest or host
		}
	}

	if PathExists(filepath.Join(, "1", "environ")) {
		,  := ReadFile(filepath.Join(, "1", "environ"))

		if  == nil {
			if strings.Contains(, "container=lxc") {
				 = "lxc"
				 = "guest"
			}
		}
	}

	if PathExists(filepath.Join(, "self", "cgroup")) {
		,  := ReadLines(filepath.Join(, "self", "cgroup"))
		if  == nil {
			if StringsContains(, "lxc") {
				 = "lxc"
				 = "guest"
			} else if StringsContains(, "docker") {
				 = "docker"
				 = "guest"
			} else if StringsContains(, "machine-rkt") {
				 = "rkt"
				 = "guest"
			} else if PathExists("/usr/bin/lxc-version") {
				 = "lxc"
				 = "host"
			}
		}
	}

	if PathExists(HostEtc("os-release")) {
		, ,  := GetOSRelease()
		if  == nil &&  == "coreos" {
			 = "rkt" // Is it true?
			 = "host"
		}
	}
	return , , nil
}

func () (,  string,  error) {
	,  := ReadLines(HostEtc("os-release"))
	if  != nil {
		return "", "", nil // return empty
	}
	for ,  := range  {
		 := strings.Split(, "=")
		if len() < 2 {
			continue
		}
		switch [0] {
		case "ID": // use ID for lowercase
			 = trimQuotes([1])
		case "VERSION":
			 = trimQuotes([1])
		}
	}
	return , , nil
}

// Remove quotes of the source string
func trimQuotes( string) string {
	if len() >= 2 {
		if [0] == '"' && [len()-1] == '"' {
			return [1 : len()-1]
		}
	}
	return 
}