github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/system/host/host_darwin.go (about)

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