1package host 2 3import ( 4 "bufio" 5 "bytes" 6 "context" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "os/exec" 11 "regexp" 12 "runtime" 13 "strconv" 14 "strings" 15 "time" 16 17 "github.com/shirou/gopsutil/internal/common" 18) 19 20func Info() (*InfoStat, error) { 21 return InfoWithContext(context.Background()) 22} 23 24func InfoWithContext(ctx context.Context) (*InfoStat, error) { 25 result := &InfoStat{ 26 OS: runtime.GOOS, 27 } 28 29 hostname, err := os.Hostname() 30 if err != nil { 31 return nil, err 32 } 33 result.Hostname = hostname 34 35 // Parse versions from output of `uname(1)` 36 uname, err := exec.LookPath("uname") 37 if err != nil { 38 return nil, err 39 } 40 41 out, err := invoke.CommandWithContext(ctx, uname, "-srv") 42 if err != nil { 43 return nil, err 44 } 45 46 fields := strings.Fields(string(out)) 47 if len(fields) >= 1 { 48 result.PlatformFamily = fields[0] 49 } 50 if len(fields) >= 2 { 51 result.KernelVersion = fields[1] 52 } 53 if len(fields) == 3 { 54 result.PlatformVersion = fields[2] 55 } 56 57 kernelArch, err := kernelArch() 58 if err == nil { 59 result.KernelArch = kernelArch 60 } 61 62 // Find distribution name from /etc/release 63 fh, err := os.Open("/etc/release") 64 if err != nil { 65 return nil, err 66 } 67 defer fh.Close() 68 69 sc := bufio.NewScanner(fh) 70 if sc.Scan() { 71 line := strings.TrimSpace(sc.Text()) 72 switch { 73 case strings.HasPrefix(line, "SmartOS"): 74 result.Platform = "SmartOS" 75 case strings.HasPrefix(line, "OpenIndiana"): 76 result.Platform = "OpenIndiana" 77 case strings.HasPrefix(line, "OmniOS"): 78 result.Platform = "OmniOS" 79 case strings.HasPrefix(line, "Open Storage"): 80 result.Platform = "NexentaStor" 81 case strings.HasPrefix(line, "Solaris"): 82 result.Platform = "Solaris" 83 case strings.HasPrefix(line, "Oracle Solaris"): 84 result.Platform = "Solaris" 85 default: 86 result.Platform = strings.Fields(line)[0] 87 } 88 } 89 90 switch result.Platform { 91 case "SmartOS": 92 // If everything works, use the current zone ID as the HostID if present. 93 zonename, err := exec.LookPath("zonename") 94 if err == nil { 95 out, err := invoke.CommandWithContext(ctx, zonename) 96 if err == nil { 97 sc := bufio.NewScanner(bytes.NewReader(out)) 98 for sc.Scan() { 99 line := sc.Text() 100 101 // If we're in the global zone, rely on the hostname. 102 if line == "global" { 103 hostname, err := os.Hostname() 104 if err == nil { 105 result.HostID = hostname 106 } 107 } else { 108 result.HostID = strings.TrimSpace(line) 109 break 110 } 111 } 112 } 113 } 114 } 115 116 // If HostID is still empty, use hostid(1), which can lie to callers but at 117 // this point there are no hardware facilities available. This behavior 118 // matches that of other supported OSes. 119 if result.HostID == "" { 120 hostID, err := exec.LookPath("hostid") 121 if err == nil { 122 out, err := invoke.CommandWithContext(ctx, hostID) 123 if err == nil { 124 sc := bufio.NewScanner(bytes.NewReader(out)) 125 for sc.Scan() { 126 line := sc.Text() 127 result.HostID = strings.TrimSpace(line) 128 break 129 } 130 } 131 } 132 } 133 134 // Find the boot time and calculate uptime relative to it 135 bootTime, err := BootTime() 136 if err != nil { 137 return nil, err 138 } 139 result.BootTime = bootTime 140 result.Uptime = uptimeSince(bootTime) 141 142 // Count number of processes based on the number of entries in /proc 143 dirs, err := ioutil.ReadDir("/proc") 144 if err != nil { 145 return nil, err 146 } 147 result.Procs = uint64(len(dirs)) 148 149 return result, nil 150} 151 152var kstatMatch = regexp.MustCompile(`([^\s]+)[\s]+([^\s]*)`) 153 154func BootTime() (uint64, error) { 155 return BootTimeWithContext(context.Background()) 156} 157 158func BootTimeWithContext(ctx context.Context) (uint64, error) { 159 kstat, err := exec.LookPath("kstat") 160 if err != nil { 161 return 0, err 162 } 163 164 out, err := invoke.CommandWithContext(ctx, kstat, "-p", "unix:0:system_misc:boot_time") 165 if err != nil { 166 return 0, err 167 } 168 169 kstats := kstatMatch.FindAllStringSubmatch(string(out), -1) 170 if len(kstats) != 1 { 171 return 0, fmt.Errorf("expected 1 kstat, found %d", len(kstats)) 172 } 173 174 return strconv.ParseUint(kstats[0][2], 10, 64) 175} 176 177func Uptime() (uint64, error) { 178 return UptimeWithContext(context.Background()) 179} 180 181func UptimeWithContext(ctx context.Context) (uint64, error) { 182 bootTime, err := BootTime() 183 if err != nil { 184 return 0, err 185 } 186 return uptimeSince(bootTime), nil 187} 188 189func uptimeSince(since uint64) uint64 { 190 return uint64(time.Now().Unix()) - since 191} 192 193func Users() ([]UserStat, error) { 194 return UsersWithContext(context.Background()) 195} 196 197func UsersWithContext(ctx context.Context) ([]UserStat, error) { 198 return []UserStat{}, common.ErrNotImplementedError 199} 200 201func SensorsTemperatures() ([]TemperatureStat, error) { 202 return SensorsTemperaturesWithContext(context.Background()) 203} 204 205func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { 206 return []TemperatureStat{}, common.ErrNotImplementedError 207} 208 209func Virtualization() (string, string, error) { 210 return VirtualizationWithContext(context.Background()) 211} 212 213func VirtualizationWithContext(ctx context.Context) (string, string, error) { 214 return "", "", common.ErrNotImplementedError 215} 216 217func KernelVersion() (string, error) { 218 return KernelVersionWithContext(context.Background()) 219} 220 221func KernelVersionWithContext(ctx context.Context) (string, error) { 222 // Parse versions from output of `uname(1)` 223 uname, err := exec.LookPath("uname") 224 if err != nil { 225 return "", err 226 } 227 228 out, err := invoke.CommandWithContext(ctx, uname, "-srv") 229 if err != nil { 230 return "", err 231 } 232 233 fields := strings.Fields(string(out)) 234 if len(fields) >= 2 { 235 return fields[1], nil 236 } 237 return "", fmt.Errorf("could not get kernel version") 238} 239 240func PlatformInformation() (platform string, family string, version string, err error) { 241 return PlatformInformationWithContext(context.Background()) 242} 243 244func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) { 245 /* This is not finished yet at all. Please contribute! */ 246 247 version, err = KernelVersion() 248 if err != nil { 249 return "", "", "", err 250 } 251 252 return "solaris", "solaris", version, nil 253} 254