| // SPDX-License-Identifier: BSD-3-Clause |
| //go:build darwin |
| |
| package host |
| |
| import ( |
| "context" |
| "errors" |
| "io" |
| "os" |
| "strings" |
| "unsafe" |
| |
| "golang.org/x/sys/unix" |
| |
| "github.com/shirou/gopsutil/v4/internal/common" |
| "github.com/shirou/gopsutil/v4/process" |
| ) |
| |
| // from utmpx.h |
| const user_PROCESS = 7 //nolint:revive //FIXME |
| |
| func HostIDWithContext(ctx context.Context) (string, error) { |
| out, err := invoke.CommandWithContext(ctx, "ioreg", "-rd1", "-c", "IOPlatformExpertDevice") |
| if err != nil { |
| return "", err |
| } |
| |
| for _, line := range strings.Split(string(out), "\n") { |
| if strings.Contains(line, "IOPlatformUUID") { |
| parts := strings.SplitAfter(line, `" = "`) |
| if len(parts) == 2 { |
| uuid := strings.TrimRight(parts[1], `"`) |
| return strings.ToLower(uuid), nil |
| } |
| } |
| } |
| |
| return "", errors.New("cannot find host id") |
| } |
| |
| func numProcs(ctx context.Context) (uint64, error) { |
| procs, err := process.PidsWithContext(ctx) |
| if err != nil { |
| return 0, err |
| } |
| return uint64(len(procs)), nil |
| } |
| |
| func UsersWithContext(_ context.Context) ([]UserStat, error) { |
| utmpfile := "/var/run/utmpx" |
| var ret []UserStat |
| |
| file, err := os.Open(utmpfile) |
| if err != nil { |
| return ret, err |
| } |
| defer file.Close() |
| |
| buf, err := io.ReadAll(file) |
| if err != nil { |
| return ret, err |
| } |
| |
| // Skip macOS utmpx header part |
| const ut32Size = int(unsafe.Sizeof(utmpx32{})) |
| buf = buf[ut32Size:] |
| |
| count := len(buf) / ut32Size |
| |
| for i := range count { |
| b := buf[i*ut32Size : i*ut32Size+ut32Size] |
| |
| var u utmpx32 |
| copy(unsafe.Slice((*byte)(unsafe.Pointer(&u)), len(b)), b) |
| if u.Type != user_PROCESS { |
| continue |
| } |
| user := UserStat{ |
| User: common.IntToString(u.User[:]), |
| Terminal: common.IntToString(u.Line[:]), |
| Host: common.IntToString(u.Host[:]), |
| Started: int(u.Tv.Sec), |
| } |
| ret = append(ret, user) |
| } |
| |
| return ret, nil |
| } |
| |
| func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) { |
| platform := "" |
| family := "" |
| pver := "" |
| |
| p, err := unix.Sysctl("kern.ostype") |
| if err == nil { |
| platform = strings.ToLower(p) |
| } |
| |
| out, err := invoke.CommandWithContext(ctx, "sw_vers", "-productVersion") |
| if err == nil { |
| pver = strings.ToLower(strings.TrimSpace(string(out))) |
| } |
| |
| // check if the macos server version file exists |
| _, err = os.Stat("/System/Library/CoreServices/ServerVersion.plist") |
| |
| // server file doesn't exist |
| if os.IsNotExist(err) { |
| family = "Standalone Workstation" |
| } else { |
| family = "Server" |
| } |
| |
| return platform, family, pver, nil |
| } |
| |
| func VirtualizationWithContext(_ context.Context) (string, string, error) { |
| return "", "", common.ErrNotImplementedError |
| } |
| |
| func KernelVersionWithContext(_ context.Context) (string, error) { |
| version, err := unix.Sysctl("kern.osrelease") |
| return strings.ToLower(version), err |
| } |