1package internal
2
3import (
4 "fmt"
5 "html/template"
6 "io"
7 "os"
8 "path/filepath"
9)
10
11var templateFuncMap = template.FuncMap{
12 "add": func(a int, b int) int { return a + b },
13 "subtract": func(a int, b int) int { return a - b },
14 "multiply": func(a int, b int) int { return a * b },
15 "divide": func(a int, b int) int { return a / b },
16}
17
18// Read /etc/passwd and collect all it's entries..
19// It returns the collected passwd entries and any errors it encounters.
20func GetPasswd() (Passwd, error) {
21 var passwd Passwd
22 text, err := os.ReadFile("/etc/passwd")
23 if err != nil {
24 return nil, fmt.Errorf("failed to read /etc/passwd: %v", err)
25 }
26 if err := passwd.UnmarshalText(text); err != nil {
27 return nil, err
28 }
29 return passwd, nil
30}
31
32// Create an OsRelease by reading /etc/os-release.
33// It returns the resulting OsRelease or any errors it encounters.
34func GetOsRelease() (OsRelease, error) {
35 osRelease := make(OsRelease)
36 text, err := os.ReadFile("/etc/os-release")
37 if err != nil {
38 return nil, fmt.Errorf("failed to read /etc/os-release: %v", err)
39 }
40 if err := osRelease.UnmarshalText(text); err != nil {
41 return nil, err
42 }
43 return osRelease, nil
44}
45
46// Look up possible environment variables for usernames.
47// It returns the username given from the first non-empty environment variable, and any errors it encounters.
48func GetUsername() (string, error) {
49 userEnvVars := []string{"USER", "USERNAME"}
50 var ok bool
51 var val string
52 for _, envvar := range userEnvVars {
53 val, ok = os.LookupEnv(envvar)
54 if ok {
55 break
56 }
57 }
58 if !ok {
59 return "", fmt.Errorf("failed to get username")
60 }
61 return val, nil
62}
63
64// Using username and passwd, it tries to find the users shell.
65// It returns the user's shell, and any errors it encounters.
66func GetShell(username string, passwd Passwd) (string, error) {
67 pwEnt, err := passwd.Entry(username)
68 if err != nil {
69 return "", err
70 }
71 return pwEnt.Shell, nil
72}
73
74// Get the systems uptime by reading and parsing /proc/uptime
75// It returns the resulting uptime, and any errors it encounters.
76func GetUptime() (Uptime, error) {
77 var up Uptime
78 text, err := os.ReadFile("/proc/uptime")
79 if err != nil {
80 return up, fmt.Errorf("failed to read /proc/uptime: %v", err)
81 }
82 if err := up.UnmarshalText(text); err != nil {
83 return up, err
84 }
85 return up, nil
86}
87
88// Gets the users terminal by looking at given environment variables
89// It returns the given terminal, and any errors it encounters.
90func GetTerminal() (string, error) {
91 termEnvVars := []string{"TERMINAL", "TERM"}
92 var result string
93 var ok bool
94 for _, variable := range termEnvVars {
95 result, ok = os.LookupEnv(variable)
96 if ok {
97 break
98 }
99 }
100 if !ok {
101 return "", fmt.Errorf("failed to find terminal")
102 }
103 return result, nil
104}
105
106// Get memory information by reading and parsing /proc/meminfo.
107// It returns the resulting MemoryInfo, and any errors it encounters.
108func GetMemoryInfo() (MemoryInfo, error) {
109 meminfo := make(MemoryInfo)
110 text, err := os.ReadFile("/proc/meminfo")
111 if err != nil {
112 return meminfo, fmt.Errorf("failed to read /proc/meminfo: %v", err)
113 }
114 if err := meminfo.UnmarshalText(text); err != nil {
115 return meminfo, err
116 }
117 return meminfo, nil
118}
119
120// Get information about the desktop environment by looking at the XDG environment variables.
121// "Unknown" will be used in place of any environment variables which are missing.
122// It returns the desktop information.
123func GetDesktopInfo() DesktopInfo {
124 var desktopInfo DesktopInfo
125 currentDesktop, ok := os.LookupEnv("XDG_CURRENT_DESKTOP")
126 if !ok {
127 currentDesktop = "Unknown"
128 }
129 sessionType, ok := os.LookupEnv("XDG_SESSION_TYPE")
130 if !ok {
131 sessionType = "Unknown"
132 }
133 desktopInfo.CurrentDesktop = currentDesktop
134 desktopInfo.SessionType = sessionType
135 return desktopInfo
136}
137
138// Get the system locale by looking at the LANG environment variable.
139// It returns the system locale, or "Unknown" if nothing is found.
140func GetLocale() string {
141 locale, ok := os.LookupEnv("LANG")
142 if !ok {
143 locale = "Unknown"
144 }
145 return locale
146}
147
148// Builds the template found in file using sysinfo, and write it to w.
149// It returns any errors that may have happened.
150func BuildTemplate(w io.Writer, file string, sysinfo SystemInfo) error {
151 name := filepath.Base(file)
152 master, err := template.New(name).Funcs(templateFuncMap).ParseFiles(file)
153 if err != nil {
154 return fmt.Errorf("failed to parse %s: %v", file, err)
155 }
156 if err := master.ExecuteTemplate(w, name, sysinfo); err != nil {
157 return fmt.Errorf("failed to write template to writer: %v", err)
158 }
159 return nil
160}