host_darwin.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // +build darwin
  2. package host
  3. import (
  4. "bytes"
  5. "context"
  6. "encoding/binary"
  7. "errors"
  8. "io/ioutil"
  9. "os"
  10. "os/exec"
  11. "strings"
  12. "unsafe"
  13. "github.com/shirou/gopsutil/internal/common"
  14. "github.com/shirou/gopsutil/process"
  15. "golang.org/x/sys/unix"
  16. )
  17. // from utmpx.h
  18. const USER_PROCESS = 7
  19. func HostIDWithContext(ctx context.Context) (string, error) {
  20. ioreg, err := exec.LookPath("ioreg")
  21. if err != nil {
  22. return "", err
  23. }
  24. out, err := invoke.CommandWithContext(ctx, ioreg, "-rd1", "-c", "IOPlatformExpertDevice")
  25. if err != nil {
  26. return "", err
  27. }
  28. for _, line := range strings.Split(string(out), "\n") {
  29. if strings.Contains(line, "IOPlatformUUID") {
  30. parts := strings.SplitAfter(line, `" = "`)
  31. if len(parts) == 2 {
  32. uuid := strings.TrimRight(parts[1], `"`)
  33. return strings.ToLower(uuid), nil
  34. }
  35. }
  36. }
  37. return "", errors.New("cannot find host id")
  38. }
  39. func numProcs(ctx context.Context) (uint64, error) {
  40. procs, err := process.PidsWithContext(ctx)
  41. if err != nil {
  42. return 0, err
  43. }
  44. return uint64(len(procs)), nil
  45. }
  46. func UsersWithContext(ctx context.Context) ([]UserStat, error) {
  47. utmpfile := "/var/run/utmpx"
  48. var ret []UserStat
  49. file, err := os.Open(utmpfile)
  50. if err != nil {
  51. return ret, err
  52. }
  53. defer file.Close()
  54. buf, err := ioutil.ReadAll(file)
  55. if err != nil {
  56. return ret, err
  57. }
  58. u := Utmpx{}
  59. entrySize := int(unsafe.Sizeof(u))
  60. count := len(buf) / entrySize
  61. for i := 0; i < count; i++ {
  62. b := buf[i*entrySize : i*entrySize+entrySize]
  63. var u Utmpx
  64. br := bytes.NewReader(b)
  65. err := binary.Read(br, binary.LittleEndian, &u)
  66. if err != nil {
  67. continue
  68. }
  69. if u.Type != USER_PROCESS {
  70. continue
  71. }
  72. user := UserStat{
  73. User: common.IntToString(u.User[:]),
  74. Terminal: common.IntToString(u.Line[:]),
  75. Host: common.IntToString(u.Host[:]),
  76. Started: int(u.Tv.Sec),
  77. }
  78. ret = append(ret, user)
  79. }
  80. return ret, nil
  81. }
  82. func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
  83. platform := ""
  84. family := ""
  85. pver := ""
  86. sw_vers, err := exec.LookPath("sw_vers")
  87. if err != nil {
  88. return "", "", "", err
  89. }
  90. p, err := unix.Sysctl("kern.ostype")
  91. if err == nil {
  92. platform = strings.ToLower(p)
  93. }
  94. out, err := invoke.CommandWithContext(ctx, sw_vers, "-productVersion")
  95. if err == nil {
  96. pver = strings.ToLower(strings.TrimSpace(string(out)))
  97. }
  98. // check if the macos server version file exists
  99. _, err = os.Stat("/System/Library/CoreServices/ServerVersion.plist")
  100. // server file doesn't exist
  101. if os.IsNotExist(err) {
  102. family = "Standalone Workstation"
  103. } else {
  104. family = "Server"
  105. }
  106. return platform, family, pver, nil
  107. }
  108. func VirtualizationWithContext(ctx context.Context) (string, string, error) {
  109. return "", "", common.ErrNotImplementedError
  110. }
  111. func KernelVersionWithContext(ctx context.Context) (string, error) {
  112. version, err := unix.Sysctl("kern.osrelease")
  113. return strings.ToLower(version), err
  114. }