all repos

viye @ 089144fdd711d2f3e016714c6a1a7942330a1d36

my shot at reimplementing xiki

viye/internal/osutil/osutil_linux.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
add neofetch, 2 months ago
1
//go:build linux
2
3
package osutil
4
5
import (
6
	"fmt"
7
	"os"
8
	"os/exec"
9
	"runtime"
10
	"strconv"
11
	"strings"
12
	"syscall"
13
	"time"
14
)
15
16
func Open(path string) error {
17
	cmd := exec.Command("xdg-open", path)
18
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
19
	cmd.Start()
20
	return nil
21
}
22
23
func GetKernel() (string, error) {
24
	// or read from: /proc/sys/kernel/osrelease
25
	k, err := exec.Command("uname", "-r").Output()
26
	if err != nil {
27
		return "?", nil
28
	}
29
	return strings.TrimSpace(string(k)), nil
30
}
31
32
func GetMemory() (string, error) {
33
	f, err := os.ReadFile("/proc/meminfo")
34
	if err != nil {
35
		return "", err
36
	}
37
	var totalKB, availKB int64
38
	for line := range strings.SplitSeq(string(f), "\n") {
39
		switch {
40
		case strings.HasPrefix(line, "MemTotal:"):
41
			p := strings.Fields(line)
42
			if len(p) >= 2 {
43
				totalKB, _ = strconv.ParseInt(p[1], 10, 64)
44
			}
45
		case strings.HasPrefix(line, "MemAvailable:"):
46
			lp := strings.Fields(line)
47
			if len(lp) >= 2 {
48
				availKB, _ = strconv.ParseInt(lp[1], 10, 64)
49
			}
50
		}
51
	}
52
	if totalKB == 0 {
53
		return "", fmt.Errorf("no MemTotal in /proc/meminfo")
54
	}
55
	used := float64(totalKB-availKB) / (1024 * 1024)
56
	total := float64(totalKB) / (1024 * 1024)
57
	return fmt.Sprintf("%.1f/%.1f GiB", used, total), nil
58
}
59
60
func GetCPU() (string, error) {
61
	f, err := os.ReadFile("/proc/cpuinfo")
62
	if err != nil {
63
		return "", err
64
	}
65
	for line := range strings.SplitSeq(string(f), "\n") {
66
		if !strings.HasPrefix(line, "model name") {
67
			continue
68
		}
69
		_, after, ok := strings.Cut(line, ":")
70
		if !ok {
71
			continue
72
		}
73
		return fmt.Sprintf("%s (%d)", strings.TrimSpace(after), runtime.NumCPU()), nil
74
	}
75
	return "", fmt.Errorf("no model name in /proc/cpuinfo")
76
}
77
78
func GetUptime() (string, error) {
79
	f, err := os.ReadFile("/proc/uptime")
80
	if err != nil {
81
		return "", err
82
	}
83
	p := strings.Fields(string(f))
84
	if len(p) == 0 {
85
		return "", fmt.Errorf("empty /proc/uptime")
86
	}
87
	s, err := strconv.ParseFloat(p[0], 64)
88
	if err != nil {
89
		return "", err
90
	}
91
92
	d := time.Duration(s) * time.Second
93
	days := int(d.Hours()) / 24
94
	hours := int(d.Hours()) % 24
95
	mins := int(d.Minutes()) % 60
96
97
	switch {
98
	case days > 0:
99
		return fmt.Sprintf("%dd %dh", days, hours), nil
100
	case hours > 0:
101
		return fmt.Sprintf("%dh %dm", hours, mins), nil
102
	default:
103
		return fmt.Sprintf("%dm", mins), nil
104
	}
105
}
106
107
func GetOS() (string, error) {
108
	f, err := os.ReadFile("/etc/os-release")
109
	if err != nil {
110
		return "", err
111
	}
112
	for line := range strings.SplitSeq(string(f), "\n") {
113
		if strings.HasPrefix(line, "PRETTY_NAME=") {
114
			p := strings.Split(line, "=")
115
			if len(p) != 2 {
116
				return "Linux", err
117
			}
118
			return strings.Trim(p[1], `" `), nil
119
		}
120
	}
121
	return "Linux", nil
122
}