1 package host
2
3 import (
4 "bufio"
5 "bytes"
6 "context"
7 "fmt"
8 "io/ioutil"
9 "os"
10 "os/exec"
11 "regexp"
12 "strconv"
13 "strings"
14
15 "github.com/shirou/gopsutil/internal/common"
16 )
17
18 func HostIDWithContext(ctx context.Context) (string, error) {
19 platform, err := parseReleaseFile()
20 if err != nil {
21 return "", err
22 }
23
24 if platform == "SmartOS" {
25
26 zonename, err := exec.LookPath("zonename")
27 if err == nil {
28 out, err := invoke.CommandWithContext(ctx, zonename)
29 if err == nil {
30 sc := bufio.NewScanner(bytes.NewReader(out))
31 for sc.Scan() {
32 line := sc.Text()
33
34
35 if line == "global" {
36 hostname, err := os.Hostname()
37 if err == nil {
38 return hostname, nil
39 }
40 } else {
41 return strings.TrimSpace(line), nil
42 }
43 }
44 }
45 }
46 }
47
48
49
50
51 hostID, err := exec.LookPath("hostid")
52 if err == nil {
53 out, err := invoke.CommandWithContext(ctx, hostID)
54 if err == nil {
55 sc := bufio.NewScanner(bytes.NewReader(out))
56 for sc.Scan() {
57 line := sc.Text()
58 return strings.TrimSpace(line), nil
59 }
60 }
61 }
62
63 return "", nil
64 }
65
66
67 func numProcs(ctx context.Context) (uint64, error) {
68 dirs, err := ioutil.ReadDir("/proc")
69 if err != nil {
70 return 0, err
71 }
72 return uint64(len(dirs)), nil
73 }
74
75 var kstatMatch = regexp.MustCompile(`([^\s]+)[\s]+([^\s]*)`)
76
77 func BootTimeWithContext(ctx context.Context) (uint64, error) {
78 kstat, err := exec.LookPath("kstat")
79 if err != nil {
80 return 0, err
81 }
82
83 out, err := invoke.CommandWithContext(ctx, kstat, "-p", "unix:0:system_misc:boot_time")
84 if err != nil {
85 return 0, err
86 }
87
88 kstats := kstatMatch.FindAllStringSubmatch(string(out), -1)
89 if len(kstats) != 1 {
90 return 0, fmt.Errorf("expected 1 kstat, found %d", len(kstats))
91 }
92
93 return strconv.ParseUint(kstats[0][2], 10, 64)
94 }
95
96 func UptimeWithContext(ctx context.Context) (uint64, error) {
97 bootTime, err := BootTime()
98 if err != nil {
99 return 0, err
100 }
101 return timeSince(bootTime), nil
102 }
103
104 func UsersWithContext(ctx context.Context) ([]UserStat, error) {
105 return []UserStat{}, common.ErrNotImplementedError
106 }
107
108 func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
109 return []TemperatureStat{}, common.ErrNotImplementedError
110 }
111
112 func VirtualizationWithContext(ctx context.Context) (string, string, error) {
113 return "", "", common.ErrNotImplementedError
114 }
115
116
117 func parseReleaseFile() (string, error) {
118 b, err := ioutil.ReadFile("/etc/release")
119 if err != nil {
120 return "", err
121 }
122 s := string(b)
123 s = strings.TrimSpace(s)
124
125 var platform string
126
127 switch {
128 case strings.HasPrefix(s, "SmartOS"):
129 platform = "SmartOS"
130 case strings.HasPrefix(s, "OpenIndiana"):
131 platform = "OpenIndiana"
132 case strings.HasPrefix(s, "OmniOS"):
133 platform = "OmniOS"
134 case strings.HasPrefix(s, "Open Storage"):
135 platform = "NexentaStor"
136 case strings.HasPrefix(s, "Solaris"):
137 platform = "Solaris"
138 case strings.HasPrefix(s, "Oracle Solaris"):
139 platform = "Solaris"
140 default:
141 platform = strings.Fields(s)[0]
142 }
143
144 return platform, nil
145 }
146
147
148 func parseUnameOutput(ctx context.Context) (string, string, string, error) {
149 uname, err := exec.LookPath("uname")
150 if err != nil {
151 return "", "", "", err
152 }
153
154 out, err := invoke.CommandWithContext(ctx, uname, "-srv")
155 if err != nil {
156 return "", "", "", err
157 }
158
159 fields := strings.Fields(string(out))
160 if len(fields) < 3 {
161 return "", "", "", fmt.Errorf("malformed `uname` output")
162 }
163
164 return fields[0], fields[1], fields[2], nil
165 }
166
167 func KernelVersionWithContext(ctx context.Context) (string, error) {
168 _, kernelVersion, _, err := parseUnameOutput(ctx)
169 return kernelVersion, err
170 }
171
172 func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
173 platform, err := parseReleaseFile()
174 if err != nil {
175 return "", "", "", err
176 }
177
178 platformFamily, _, platformVersion, err := parseUnameOutput(ctx)
179 if err != nil {
180 return "", "", "", err
181 }
182
183 return platform, platformFamily, platformVersion, nil
184 }
185
View as plain text