diff --git a/go.mod b/go.mod index fd7ca5ee2f5..d88eb7ff639 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/containers/psgo v1.10.0 github.com/containers/winquit v1.1.0 github.com/coreos/go-systemd/v22 v22.6.0 - github.com/crc-org/vfkit v0.6.1 + github.com/crc-org/vfkit v0.6.3 github.com/cyphar/filepath-securejoin v0.6.1 github.com/digitalocean/go-qemu v0.0.0-20250212194115-ee9b0668d242 github.com/docker/distribution v2.8.3+incompatible @@ -57,7 +57,7 @@ require ( github.com/opencontainers/selinux v1.13.1 github.com/openshift/imagebuilder v1.2.19 github.com/rootless-containers/rootlesskit/v2 v2.3.5 - github.com/shirou/gopsutil/v4 v4.25.11 + github.com/shirou/gopsutil/v4 v4.25.12 github.com/sirupsen/logrus v1.9.4-0.20251023124752-b61f268f75b6 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 @@ -70,7 +70,7 @@ require ( golang.org/x/crypto v0.46.0 golang.org/x/net v0.48.0 golang.org/x/sync v0.19.0 - golang.org/x/sys v0.39.0 + golang.org/x/sys v0.40.0 golang.org/x/term v0.38.0 google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.11 @@ -99,7 +99,7 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/containernetworking/cni v1.3.0 // indirect - github.com/containers/common v0.62.2 // indirect + github.com/containers/common v0.64.2 // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect github.com/containers/luksy v0.0.0-20250910190358-2cf5bc928957 // indirect github.com/coreos/go-oidc/v3 v3.16.0 // indirect @@ -182,7 +182,7 @@ require ( go.opentelemetry.io/otel/trace v1.38.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.30.0 // indirect + golang.org/x/mod v0.31.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect diff --git a/go.sum b/go.sum index 5ca6b647a1e..fee0b88183a 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,8 @@ github.com/containernetworking/plugins v1.8.0 h1:WjGbV/0UQyo8A4qBsAh6GaDAtu1hevx github.com/containernetworking/plugins v1.8.0/go.mod h1:JG3BxoJifxxHBhG3hFyxyhid7JgRVBu/wtooGEvWf1c= github.com/containers/buildah v1.42.0 h1:hS+/sq6g74wNNYvX6d5/jx4awkwqibBxUxJ/P2oOETk= github.com/containers/buildah v1.42.0/go.mod h1:azIYkIUVSEiVVQi4hPm9ZsxuVNqb8HdSMlvaBzr8MtU= -github.com/containers/common v0.62.2 h1:xO45OOoeq17EZMIDZoSyRqg7GXGcRHa9sXlrr75zH+U= -github.com/containers/common v0.62.2/go.mod h1:veFiR9iq2j3CHXtB4YnPHuOkSRdhIQ3bAY8AFMP/5bE= +github.com/containers/common v0.64.2 h1:1xepE7QwQggUXxmyQ1Dbh6Cn0yd7ktk14sN3McSWf5I= +github.com/containers/common v0.64.2/go.mod h1:o29GfYy4tefUuShm8mOn2AiL5Mpzdio+viHI7n24KJ4= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/gvisor-tap-vsock v0.8.7 h1:mFMMU5CIXO9sbtsgECc90loUHx15km3AN6Zuhg3X4qM= @@ -84,8 +84,8 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7 github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/crc-org/vfkit v0.6.1 h1:JepqPrgzKBuM/jximOcwA5ZnQPMcdarPRCrF4jHFau8= -github.com/crc-org/vfkit v0.6.1/go.mod h1:M3UMhDHg4d9/KzcslwG4Zay8EUMe7Pv6vxG/++vJ//4= +github.com/crc-org/vfkit v0.6.3 h1:X6pHxDWx0jQRV6TpzCmI4tfPyW/2R03HEEiS5vNnsBU= +github.com/crc-org/vfkit v0.6.3/go.mod h1:jp0CkOQW5BAvSdJSV7OHUuTGRUo7+/fwaFHd+92pqR8= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q= @@ -345,8 +345,8 @@ github.com/secure-systems-lab/go-securesystemslib v0.9.1 h1:nZZaNz4DiERIQguNy0cL github.com/secure-systems-lab/go-securesystemslib v0.9.1/go.mod h1:np53YzT0zXGMv6x4iEWc9Z59uR+x+ndLwCLqPYpLXVU= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY= -github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= +github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY= +github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= github.com/sigstore/fulcio v1.8.1 h1:PmoQv3XmhjR2BWFWw5LcMUXJPmhyizOIL7HeYnpio58= github.com/sigstore/fulcio v1.8.1/go.mod h1:7tP3KW9eCGlPYRj5N4MSuUOat7CkeIHuXZ2jAUQ+Rwc= github.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA4FIkofAY= @@ -477,8 +477,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -531,8 +531,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/vendor/github.com/crc-org/vfkit/pkg/config/config.go b/vendor/github.com/crc-org/vfkit/pkg/config/config.go index a72c9d9a2fb..842e1693605 100644 --- a/vendor/github.com/crc-org/vfkit/pkg/config/config.go +++ b/vendor/github.com/crc-org/vfkit/pkg/config/config.go @@ -16,7 +16,6 @@ import ( "math" "os" "os/exec" - "path/filepath" "strconv" "strings" @@ -32,6 +31,7 @@ type VirtualMachine struct { Devices []VirtioDevice `json:"devices,omitempty"` Timesync *TimeSync `json:"timesync,omitempty"` Ignition *Ignition `json:"ignition,omitempty"` + Nested bool `json:"nested,omitempty"` } // TimeSync enables synchronization of the host time to the linux guest after the host was suspended. @@ -42,7 +42,8 @@ type TimeSync struct { type Ignition struct { ConfigPath string `json:"configPath"` - SocketPath string `json:"socketPath"` + SocketPath string `json:"socketPath,omitempty"` + VsockPort uint32 `json:"-"` } // The VMComponent interface represents a VM element (device, bootloader, ...) @@ -53,8 +54,9 @@ type VMComponent interface { } const ( - ignitionVsockPort uint = 1024 - ignitionSocketName string = "ignition.sock" + // the ignition vsock port is hardcoded to 1024 in ignition source code: + // https://github.com/coreos/ignition/blob/d4ff84b2c28a28ad828b974befe3575563faacdd/internal/providers/applehv/applehv.go#L59-L68 + ignitionVsockPort uint32 = 1024 ) // NewVirtualMachine creates a new VirtualMachine instance. The virtual machine @@ -112,6 +114,10 @@ func (vm *VirtualMachine) ToCmdLine() ([]string, error) { args = append(args, "--ignition", vm.Ignition.ConfigPath) } + if vm.Nested { + args = append(args, "--nested") + } + return args, nil } @@ -156,26 +162,30 @@ func (vm *VirtualMachine) AddDevicesFromCmdLine(cmdlineOpts []string) error { return nil } -func (vm *VirtualMachine) VirtioGPUDevices() []*VirtioGPU { - gpuDevs := []*VirtioGPU{} +func FilterDevices[V VMComponent](vm *VirtualMachine) []V { + devs := []V{} for _, dev := range vm.Devices { - if gpuDev, isVirtioGPU := dev.(*VirtioGPU); isVirtioGPU { - gpuDevs = append(gpuDevs, gpuDev) + if dev, isV := dev.(V); isV { + devs = append(devs, dev) } } + return devs +} - return gpuDevs +func (vm *VirtualMachine) VirtioGPUDevices() []*VirtioGPU { + return FilterDevices[*VirtioGPU](vm) } func (vm *VirtualMachine) VirtioVsockDevices() []*VirtioVsock { - vsockDevs := []*VirtioVsock{} - for _, dev := range vm.Devices { - if vsockDev, isVirtioVsock := dev.(*VirtioVsock); isVirtioVsock { - vsockDevs = append(vsockDevs, vsockDev) - } - } + return FilterDevices[*VirtioVsock](vm) +} + +func (vm *VirtualMachine) VirtioInputDevices() []*VirtioInput { + return FilterDevices[*VirtioInput](vm) +} - return vsockDevs +func (vm *VirtualMachine) VirtioNetDevices() []*VirtioNet { + return FilterDevices[*VirtioNet](vm) } func (vm *VirtualMachine) NetworkBlockDevice(deviceID string) *NetworkBlockDevice { @@ -217,13 +227,13 @@ func (vm *VirtualMachine) TimeSync() *TimeSync { return vm.Timesync } -func IgnitionNew(configPath string, socketPath string) (*Ignition, error) { - if configPath == "" || socketPath == "" { - return nil, fmt.Errorf("config path and socket path cannot be empty") +func IgnitionNew(configPath string, _ string) (*Ignition, error) { + if configPath == "" { + return nil, fmt.Errorf("config path cannot be empty") } return &Ignition{ ConfigPath: configPath, - SocketPath: socketPath, + VsockPort: ignitionVsockPort, }, nil } @@ -233,16 +243,10 @@ func (vm *VirtualMachine) AddIgnitionFileFromCmdLine(cmdlineOpts string) error { } opts := strings.Split(cmdlineOpts, ",") if len(opts) != 1 { - return fmt.Errorf("ignition only accept one option in command line argument") + return fmt.Errorf("ignition only accepts one option in command line argument") } - socketPath := filepath.Join(os.TempDir(), ignitionSocketName) - dev, err := VirtioVsockNew(ignitionVsockPort, socketPath, true) - if err != nil { - return err - } - vm.Devices = append(vm.Devices, dev) - ignition, err := IgnitionNew(opts[0], socketPath) + ignition, err := IgnitionNew(opts[0], "") if err != nil { return err } @@ -256,7 +260,7 @@ func TimeSyncNew(vsockPort uint) (VMComponent, error) { return nil, fmt.Errorf("invalid vsock port: %d", vsockPort) } return &TimeSync{ - VsockPort: uint32(vsockPort), //#nosec G115 -- was compared to math.MaxUint32 + VsockPort: uint32(vsockPort), }, nil } @@ -276,7 +280,7 @@ func (ts *TimeSync) FromOptions(options []option) error { if err != nil { return err } - ts.VsockPort = uint32(vsockPort) //#nosec G115 -- ParseUint(_, _, 32) guarantees no overflow + ts.VsockPort = uint32(vsockPort) default: return fmt.Errorf("unknown option for timesync parameter: %s", option.key) } diff --git a/vendor/github.com/crc-org/vfkit/pkg/config/json.go b/vendor/github.com/crc-org/vfkit/pkg/config/json.go index c16d98ebe7c..5c54cc03277 100644 --- a/vendor/github.com/crc-org/vfkit/pkg/config/json.go +++ b/vendor/github.com/crc-org/vfkit/pkg/config/json.go @@ -110,6 +110,9 @@ func unmarshalIgnition(rawMsg json.RawMessage) (Ignition, error) { func unmarshalVirtioNet(rawMsg json.RawMessage) (*VirtioNet, error) { var dev virtioNetForMarshalling + // defaults to true for backwards compatibility with vfkit versions which did not have this field + dev.VfkitMagic = true + err := json.Unmarshal(rawMsg, &dev) if err != nil { return nil, err @@ -121,6 +124,10 @@ func unmarshalVirtioNet(rawMsg json.RawMessage) (*VirtioNet, error) { } dev.VirtioNet.MacAddress = macAddr } + // vfkitMagic is only useful in combination with unixSocketPath + if dev.UnixSocketPath == "" { + dev.VfkitMagic = false + } return &dev.VirtioNet, nil } diff --git a/vendor/github.com/crc-org/vfkit/pkg/config/virtio.go b/vendor/github.com/crc-org/vfkit/pkg/config/virtio.go index 757ebd892ec..1287afb2ff7 100644 --- a/vendor/github.com/crc-org/vfkit/pkg/config/virtio.go +++ b/vendor/github.com/crc-org/vfkit/pkg/config/virtio.go @@ -1,10 +1,12 @@ package config import ( + "bytes" "fmt" "math" "net" "os" + "slices" "strconv" "strings" "time" @@ -25,6 +27,7 @@ const ( // Default VirtioGPU Resolution defaultVirtioGPUResolutionWidth = 800 defaultVirtioGPUResolutionHeight = 600 + qcow2Header = "QFI\xfb" ) // VirtioInput configures an input device, such as a keyboard or pointing device @@ -101,12 +104,17 @@ type VirtioNet struct { Socket *os.File `json:"socket,omitempty"` UnixSocketPath string `json:"unixSocketPath,omitempty"` + VfkitMagic bool `json:"vfkitMagic,omitempty"` } // VirtioSerial configures the virtual machine serial ports. type VirtioSerial struct { LogFile string `json:"logFile,omitempty"` UsesStdio bool `json:"usesStdio,omitempty"` + UsesPty bool `json:"usesPty,omitempty"` + // PtyName must not be set when creating the VM, from a user perspective, it's read-only, + // vfkit will set it during VM startup. + PtyName string `json:"ptyName,omitempty"` } type NBDSynchronizationMode string @@ -230,12 +238,24 @@ func VirtioSerialNewStdio() (VirtioDevice, error) { }, nil } +func VirtioSerialNewPty() (VirtioDevice, error) { + return &VirtioSerial{ + UsesPty: true, + }, nil +} + func (dev *VirtioSerial) validate() error { if dev.LogFile != "" && dev.UsesStdio { return fmt.Errorf("'logFilePath' and 'stdio' cannot be set at the same time") } - if dev.LogFile == "" && !dev.UsesStdio { - return fmt.Errorf("one of 'logFilePath' or 'stdio' must be set") + if dev.LogFile != "" && dev.UsesPty { + return fmt.Errorf("'logFilePath' and 'pty' cannot be set at the same time") + } + if dev.UsesStdio && dev.UsesPty { + return fmt.Errorf("'stdio' and 'pty' cannot be set at the same time") + } + if dev.LogFile == "" && !dev.UsesStdio && !dev.UsesPty { + return fmt.Errorf("one of 'logFilePath', 'stdio' or 'pty' must be set") } return nil @@ -245,11 +265,16 @@ func (dev *VirtioSerial) ToCmdLine() ([]string, error) { if err := dev.validate(); err != nil { return nil, err } - if dev.UsesStdio { + switch { + case dev.UsesStdio: return []string{"--device", "virtio-serial,stdio"}, nil + case dev.UsesPty: + return []string{"--device", "virtio-serial,pty"}, nil + case dev.LogFile != "": + fallthrough + default: + return []string{"--device", fmt.Sprintf("virtio-serial,logFilePath=%s", dev.LogFile)}, nil } - - return []string{"--device", fmt.Sprintf("virtio-serial,logFilePath=%s", dev.LogFile)}, nil } func (dev *VirtioSerial) FromOptions(options []option) error { @@ -262,6 +287,8 @@ func (dev *VirtioSerial) FromOptions(options []option) error { return fmt.Errorf("unexpected value for virtio-serial 'stdio' option: %s", option.value) } dev.UsesStdio = true + case "pty": + dev.UsesPty = true default: return fmt.Errorf("unknown option for virtio-serial devices: %s", option.key) } @@ -350,14 +377,14 @@ func (dev *VirtioGPU) FromOptions(options []option) error { case VirtioGPUResolutionHeight: height, err := strconv.Atoi(option.value) if err != nil || height < 1 { - return fmt.Errorf("Invalid value for virtio-gpu %s: %s", option.key, option.value) + return fmt.Errorf("invalid value for virtio-gpu %s: %s", option.key, option.value) } dev.Height = height case VirtioGPUResolutionWidth: width, err := strconv.Atoi(option.value) if err != nil || width < 1 { - return fmt.Errorf("Invalid value for virtio-gpu %s: %s", option.key, option.value) + return fmt.Errorf("invalid value for virtio-gpu %s: %s", option.key, option.value) } dev.Width = width @@ -405,6 +432,7 @@ func (dev *VirtioNet) SetSocket(file *os.File) { func (dev *VirtioNet) SetUnixSocketPath(path string) { dev.UnixSocketPath = path dev.Nat = false + dev.VfkitMagic = true // Enable vfkit magic by default for unix sockets } func (dev *VirtioNet) validate() error { @@ -435,19 +463,40 @@ func (dev *VirtioNet) ToCmdLine() ([]string, error) { case dev.Nat: builder.WriteString(",nat") case dev.UnixSocketPath != "": - fmt.Fprintf(&builder, ",unixSocketPath=%s", dev.UnixSocketPath) + if dev.VfkitMagic { + // Use the old commandline syntax for backwards compatibility + // The pkg/config code is used by other projects as a go module to + // generate the command line to start vfkit. There is no guarantee + // that the `vfkit` binary these projects are using is the latest + // one with support for the new syntax. + // https://github.com/containers/podman/issues/27873 + fmt.Fprintf(&builder, ",unixSocketPath=%s", dev.UnixSocketPath) + } else { + builder.WriteString(",type=unixgram") + fmt.Fprintf(&builder, ",path=%s", dev.UnixSocketPath) + builder.WriteString(",vfkitMagic=off") + } default: fmt.Fprintf(&builder, ",fd=%d", dev.Socket.Fd()) } if len(dev.MacAddress) != 0 { - builder.WriteString(fmt.Sprintf(",mac=%s", dev.MacAddress)) + fmt.Fprintf(&builder, ",mac=%s", dev.MacAddress) } return []string{"--device", builder.String()}, nil } func (dev *VirtioNet) FromOptions(options []option) error { + var hasType bool + var typeOnlyOptions []string // Options that require type to be specified + + if slices.ContainsFunc(options, func(opt option) bool { + return opt.key == "path" || opt.key == "unixSocketPath" + }) { + dev.VfkitMagic = true + } + for _, option := range options { switch option.key { case "nat": @@ -469,11 +518,38 @@ func (dev *VirtioNet) FromOptions(options []option) error { dev.Socket = os.NewFile(uintptr(fd), "vfkit virtio-net socket") case "unixSocketPath": dev.UnixSocketPath = option.value + case "type": + if option.value != "unixgram" { + return fmt.Errorf("unsupported virtio-net type: %s (only 'unixgram' is supported)", option.value) + } + hasType = true + case "path": + dev.UnixSocketPath = option.value + typeOnlyOptions = append(typeOnlyOptions, option.key) + case "vfkitMagic": + if option.value != "on" && option.value != "off" { + return fmt.Errorf("invalid value for vfkitMagic: %s (expected on/off)", option.value) + } + dev.VfkitMagic = option.value == "on" + case "offloading": + if option.value != "off" { + return fmt.Errorf("invalid value for offloading: %s (only 'off' is supported)", option.value) + } + typeOnlyOptions = append(typeOnlyOptions, option.key) default: return fmt.Errorf("unknown option for virtio-net devices: %s", option.key) } } + // Validate type+path dependency and type-only options + if hasType && dev.UnixSocketPath == "" { + return fmt.Errorf("'type' option requires 'path' to be specified") + } + + if !hasType && len(typeOnlyOptions) > 0 { + return fmt.Errorf("'%s' option requires 'type' to be specified", typeOnlyOptions[0]) + } + return dev.validate() } @@ -548,7 +624,10 @@ func (dev *VirtioBlk) FromOptions(options []option) error { } } - return dev.DiskStorageConfig.FromOptions(unhandledOpts) + if err := dev.DiskStorageConfig.FromOptions(unhandledOpts); err != nil { + return err + } + return dev.validate() } func (dev *VirtioBlk) ToCmdLine() ([]string, error) { @@ -565,6 +644,24 @@ func (dev *VirtioBlk) ToCmdLine() ([]string, error) { return cmdLine, nil } +func (dev *VirtioBlk) validate() error { + imgPath := dev.ImagePath + file, err := os.Open(imgPath) + if err != nil { + return fmt.Errorf("failed to open file %s: %v", imgPath, err) + } + defer file.Close() + header := make([]byte, 4) + _, err = file.Read(header) + if err != nil { + return fmt.Errorf("failed to read the header of file %s: %v", imgPath, err) + } + if bytes.Equal(header, []byte(qcow2Header)) { + return fmt.Errorf("vfkit does not support qcow2 image format") + } + return nil +} + // VirtioVsockNew creates a new virtio-vsock device for 2-way communication // between the host and the virtual machine. The communication will happen on // vsock port, and on the host it will use the unix socket at socketURL. @@ -575,7 +672,7 @@ func VirtioVsockNew(port uint, socketURL string, listen bool) (VirtioDevice, err return nil, fmt.Errorf("invalid vsock port: %d", port) } return &VirtioVsock{ - Port: uint32(port), //#nosec G115 -- was compared to math.MaxUint32 + Port: uint32(port), SocketURL: socketURL, Listen: listen, }, nil @@ -606,7 +703,7 @@ func (dev *VirtioVsock) FromOptions(options []option) error { if err != nil { return err } - dev.Port = uint32(port) //#nosec G115 -- ParseUint(_, _, 32) guarantees no overflow + dev.Port = uint32(port) case "listen": dev.Listen = true case "connect": @@ -802,7 +899,7 @@ func USBMassStorageNew(imagePath string) (*USBMassStorage, error) { } func (dev *USBMassStorage) SetReadOnly(readOnly bool) { - dev.StorageConfig.ReadOnly = readOnly + dev.ReadOnly = readOnly } // StorageConfig configures a disk device. @@ -811,9 +908,32 @@ type StorageConfig struct { ReadOnly bool `json:"readOnly,omitempty"` } +type DiskBackendType string + +const ( + /// Normal disk images, like .img + DiskBackendImage DiskBackendType = "image" + + /// Real block devices, like /dev/disk1s1 + DiskBackendBlockDevice DiskBackendType = "dev" + + /// If the value is empty, it defaults to image + DiskBackendDefault DiskBackendType = "" +) + +func (typ DiskBackendType) IsValid() bool { + switch typ { + case DiskBackendImage, DiskBackendBlockDevice, DiskBackendDefault: + return true + default: + return false + } +} + type DiskStorageConfig struct { StorageConfig - ImagePath string `json:"imagePath,omitempty"` + ImagePath string `json:"imagePath,omitempty"` + Type DiskBackendType `json:"type,omitempty"` } type NetworkBlockStorageConfig struct { @@ -828,6 +948,10 @@ func (config *DiskStorageConfig) ToCmdLine() ([]string, error) { value := fmt.Sprintf("%s,path=%s", config.DevName, config.ImagePath) + if config.Type != DiskBackendDefault { + value += fmt.Sprintf(",type=%s", string(config.Type)) + } + if config.ReadOnly { value += ",readonly" } @@ -839,6 +963,12 @@ func (config *DiskStorageConfig) FromOptions(options []option) error { switch option.key { case "path": config.ImagePath = option.value + case "type": + typ := DiskBackendType(option.value) + if !typ.IsValid() { + return fmt.Errorf("unexpected value for disk 'type' option: %s", option.value) + } + config.Type = typ case "readonly": if option.value != "" { return fmt.Errorf("unexpected value for virtio-blk 'readonly' option: %s", option.value) diff --git a/vendor/github.com/crc-org/vfkit/pkg/util/exithandler.go b/vendor/github.com/crc-org/vfkit/pkg/util/exithandler.go index dd4c30a6f3a..f23dde78c94 100644 --- a/vendor/github.com/crc-org/vfkit/pkg/util/exithandler.go +++ b/vendor/github.com/crc-org/vfkit/pkg/util/exithandler.go @@ -28,22 +28,24 @@ func RegisterExitHandler(handler func()) { // SetupExitSignalHandling sets up a signal channel to listen for termination or interruption signals. // When one of these signals is received, all the registered exit handlers will be invoked, just // before terminating the program. -func SetupExitSignalHandling() { - setupExitSignalHandling(true) +func SetupExitSignalHandling(shutdownFunc func()) { + setupExitSignalHandling(shutdownFunc) } // setupExitSignalHandling sets up a signal channel to listen for termination or interruption signals. // When one of these signals is received, all the registered exit handlers will be invoked. // It is possible to prevent the program from exiting by setting the doExit param to false (used for testing) -func setupExitSignalHandling(doExit bool) { +func setupExitSignalHandling(shutdownFunc func()) { sigChan := make(chan os.Signal, 2) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) go func() { + defer func() { + signal.Stop(sigChan) + }() for sig := range sigChan { log.Printf("captured %v, calling exit handlers and exiting..", sig) - ExecuteExitHandlers() - if doExit { - os.Exit(1) + if shutdownFunc != nil { + shutdownFunc() } } }() diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go index c61a470fba8..d3b6dbc5329 100644 --- a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go +++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go @@ -61,17 +61,17 @@ func Times(percpu bool) ([]TimesStat, error) { } func TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) { - lib, err := common.NewLibrary(common.System) + sys, err := common.NewSystemLib() if err != nil { return nil, err } - defer lib.Close() + defer sys.Close() if percpu { - return perCPUTimes(lib) + return perCPUTimes(sys) } - return allCPUTimes(lib) + return allCPUTimes(sys) } // Returns only one CPUInfoStat on FreeBSD @@ -138,16 +138,12 @@ func CountsWithContext(_ context.Context, logical bool) (int, error) { return int(count), nil } -func perCPUTimes(machLib *common.Library) ([]TimesStat, error) { - machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym) - machTaskSelf := common.GetFunc[common.MachTaskSelfFunc](machLib, common.MachTaskSelfSym) - hostProcessorInfo := common.GetFunc[common.HostProcessorInfoFunc](machLib, common.HostProcessorInfoSym) - vmDeallocate := common.GetFunc[common.VMDeallocateFunc](machLib, common.VMDeallocateSym) - +func perCPUTimes(sys *common.SystemLib) ([]TimesStat, error) { var count, ncpu uint32 var cpuload *hostCpuLoadInfoData - status := hostProcessorInfo(machHostSelf(), processorCpuLoadInfo, &ncpu, uintptr(unsafe.Pointer(&cpuload)), &count) + status := sys.HostProcessorInfo(sys.MachHostSelf(), processorCpuLoadInfo, + &ncpu, uintptr(unsafe.Pointer(&cpuload)), &count) if status != common.KERN_SUCCESS { return nil, fmt.Errorf("host_processor_info error=%d", status) @@ -157,7 +153,7 @@ func perCPUTimes(machLib *common.Library) ([]TimesStat, error) { return nil, errors.New("host_processor_info returned nil cpuload") } - defer vmDeallocate(machTaskSelf(), uintptr(unsafe.Pointer(cpuload)), uintptr(ncpu)) + defer sys.VMDeallocate(sys.MachTaskSelf(), uintptr(unsafe.Pointer(cpuload)), uintptr(ncpu)) ret := []TimesStat{} loads := unsafe.Slice(cpuload, ncpu) @@ -170,21 +166,17 @@ func perCPUTimes(machLib *common.Library) ([]TimesStat, error) { Nice: float64(loads[i].cpuTicks[cpuStateNice]) / ClocksPerSec, Idle: float64(loads[i].cpuTicks[cpuStateIdle]) / ClocksPerSec, } - ret = append(ret, c) } return ret, nil } -func allCPUTimes(machLib *common.Library) ([]TimesStat, error) { - machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym) - hostStatistics := common.GetFunc[common.HostStatisticsFunc](machLib, common.HostStatisticsSym) - +func allCPUTimes(sys *common.SystemLib) ([]TimesStat, error) { var cpuload hostCpuLoadInfoData count := uint32(cpuStateMax) - status := hostStatistics(machHostSelf(), common.HOST_CPU_LOAD_INFO, + status := sys.HostStatistics(sys.MachHostSelf(), common.HOST_CPU_LOAD_INFO, uintptr(unsafe.Pointer(&cpuload)), &count) if status != common.KERN_SUCCESS { diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go index 8e69d7cb138..2effcadf8da 100644 --- a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go +++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go @@ -13,55 +13,43 @@ import ( // https://github.com/shoenig/go-m1cpu/blob/v0.1.6/cpu.go func getFrequency() (float64, error) { - ioKit, err := common.NewLibrary(common.IOKit) + iokit, err := common.NewIOKitLib() if err != nil { return 0, err } - defer ioKit.Close() + defer iokit.Close() - coreFoundation, err := common.NewLibrary(common.CoreFoundation) + corefoundation, err := common.NewCoreFoundationLib() if err != nil { return 0, err } - defer coreFoundation.Close() + defer corefoundation.Close() - ioServiceMatching := common.GetFunc[common.IOServiceMatchingFunc](ioKit, common.IOServiceMatchingSym) - ioServiceGetMatchingServices := common.GetFunc[common.IOServiceGetMatchingServicesFunc](ioKit, common.IOServiceGetMatchingServicesSym) - ioIteratorNext := common.GetFunc[common.IOIteratorNextFunc](ioKit, common.IOIteratorNextSym) - ioRegistryEntryGetName := common.GetFunc[common.IORegistryEntryGetNameFunc](ioKit, common.IORegistryEntryGetNameSym) - ioRegistryEntryCreateCFProperty := common.GetFunc[common.IORegistryEntryCreateCFPropertyFunc](ioKit, common.IORegistryEntryCreateCFPropertySym) - ioObjectRelease := common.GetFunc[common.IOObjectReleaseFunc](ioKit, common.IOObjectReleaseSym) - - cfStringCreateWithCString := common.GetFunc[common.CFStringCreateWithCStringFunc](coreFoundation, common.CFStringCreateWithCStringSym) - cfDataGetLength := common.GetFunc[common.CFDataGetLengthFunc](coreFoundation, common.CFDataGetLengthSym) - cfDataGetBytePtr := common.GetFunc[common.CFDataGetBytePtrFunc](coreFoundation, common.CFDataGetBytePtrSym) - cfRelease := common.GetFunc[common.CFReleaseFunc](coreFoundation, common.CFReleaseSym) - - matching := ioServiceMatching("AppleARMIODevice") + matching := iokit.IOServiceMatching("AppleARMIODevice") var iterator uint32 - if status := ioServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(matching), &iterator); status != common.KERN_SUCCESS { + if status := iokit.IOServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(matching), &iterator); status != common.KERN_SUCCESS { return 0.0, fmt.Errorf("IOServiceGetMatchingServices error=%d", status) } - defer ioObjectRelease(iterator) + defer iokit.IOObjectRelease(iterator) - pCorekey := cfStringCreateWithCString(common.KCFAllocatorDefault, "voltage-states5-sram", common.KCFStringEncodingUTF8) - defer cfRelease(uintptr(pCorekey)) + pCorekey := corefoundation.CFStringCreateWithCString(common.KCFAllocatorDefault, "voltage-states5-sram", common.KCFStringEncodingUTF8) + defer corefoundation.CFRelease(uintptr(pCorekey)) var pCoreHz uint32 for { - service := ioIteratorNext(iterator) + service := iokit.IOIteratorNext(iterator) if service <= 0 { break } buf := common.NewCStr(512) - ioRegistryEntryGetName(service, buf) + iokit.IORegistryEntryGetName(service, buf) if buf.GoString() == "pmgr" { - pCoreRef := ioRegistryEntryCreateCFProperty(service, uintptr(pCorekey), common.KCFAllocatorDefault, common.KNilOptions) - length := cfDataGetLength(uintptr(pCoreRef)) - data := cfDataGetBytePtr(uintptr(pCoreRef)) + pCoreRef := iokit.IORegistryEntryCreateCFProperty(service, uintptr(pCorekey), common.KCFAllocatorDefault, common.KNilOptions) + length := corefoundation.CFDataGetLength(uintptr(pCoreRef)) + data := corefoundation.CFDataGetBytePtr(uintptr(pCoreRef)) // composite uint32 from the byte array buf := unsafe.Slice((*byte)(data), length) @@ -69,11 +57,12 @@ func getFrequency() (float64, error) { // combine the bytes into a uint32 value b := buf[length-8 : length-4] pCoreHz = binary.LittleEndian.Uint32(b) - ioObjectRelease(service) + corefoundation.CFRelease(uintptr(pCoreRef)) + iokit.IOObjectRelease(service) break } - ioObjectRelease(service) + iokit.IOObjectRelease(service) } return float64(pCoreHz / 1_000_000), nil diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go index 0897dfa3e78..4072f19cf2f 100644 --- a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go +++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go @@ -195,7 +195,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { c := InfoStat{CPU: -1, Cores: 1} for _, line := range lines { - fields := strings.Split(line, ":") + fields := strings.SplitN(line, ":", 2) if len(fields) < 2 { continue } @@ -221,6 +221,25 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { if strings.Contains(value, "S390") { processorName = "S390" } + case "mvendorid": + if !strings.HasPrefix(value, "0x") { + continue + } + + if v, err := strconv.ParseUint(value[2:], 16, 32); err == nil { + switch v { + case 0x31e: + c.VendorID = "Andes" + case 0x029: + c.VendorID = "Microchip" + case 0x127: + c.VendorID = "MIPS" + case 0x489: + c.VendorID = "SiFive" + case 0x5b7: + c.VendorID = "T-Head" + } + } case "CPU implementer": if v, err := strconv.ParseUint(value, 0, 8); err == nil { switch v { @@ -256,9 +275,9 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { c.VendorID = "Ampere" } } - case "cpu family": + case "cpu family", "marchid": c.Family = value - case "model", "CPU part": + case "model", "CPU part", "mimpid": c.Model = value // if CPU is arm based, model name is found via model number. refer to: arch/arm64/kernel/cpuinfo.c if c.VendorID == "ARM" { @@ -271,7 +290,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { } } } - case "Model Name", "model name", "cpu": + case "Model Name", "model name", "cpu", "uarch": c.ModelName = value if strings.Contains(value, "POWER") { c.Model = strings.Split(value, " ")[0] @@ -305,7 +324,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { return ret, err } c.CacheSize = int32(t) - case "physical id": + case "physical id", "hart": c.PhysicalID = value case "core id": c.CoreID = value @@ -313,6 +332,11 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { c.Flags = strings.FieldsFunc(value, func(r rune) bool { return r == ',' || r == ' ' }) + case "isa", "hart isa": + if len(c.Flags) != 0 || !strings.HasPrefix(value, "rv64") { + continue + } + c.Flags = riscvISAParse(value) case "microcode": c.Microcode = value } @@ -476,7 +500,7 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) { currentInfo = make(map[string]int) continue } - fields := strings.Split(line, ":") + fields := strings.SplitN(line, ":", 2) if len(fields) < 2 { continue } @@ -495,3 +519,13 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) { } return ret, nil } + +func riscvISAParse(s string) []string { + ext := strings.Split(s, "_") + if len(ext[0]) <= 4 { + return nil + } + // the base extensions must "rv64" prefix + base := strings.Split(ext[0][4:], "") + return append(base, ext[1:]...) +} diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go index 8b756a11d46..0c9747b790d 100644 --- a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go +++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go @@ -9,90 +9,314 @@ import ( "unsafe" "github.com/ebitengine/purego" - "golang.org/x/sys/unix" ) -func CallSyscall(mib []int32) ([]byte, uint64, error) { - miblen := uint64(len(mib)) - - // get required buffer size - length := uint64(0) - _, _, err := unix.Syscall6( - 202, // unix.SYS___SYSCTL https://github.com/golang/sys/blob/76b94024e4b621e672466e8db3d7f084e7ddcad2/unix/zsysnum_darwin_amd64.go#L146 - uintptr(unsafe.Pointer(&mib[0])), - uintptr(miblen), - 0, - uintptr(unsafe.Pointer(&length)), - 0, - 0) - if err != 0 { - var b []byte - return b, length, err +// Library represents a dynamic library loaded by purego. +type library struct { + handle uintptr + fnMap map[string]any +} + +// library paths +const ( + IOKitLibPath = "/System/Library/Frameworks/IOKit.framework/IOKit" + CoreFoundationLibPath = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" + SystemLibPath = "/usr/lib/libSystem.B.dylib" +) + +func newLibrary(path string) (*library, error) { + lib, err := purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL) + if err != nil { + return nil, err } - if length == 0 { - var b []byte - return b, length, err + + return &library{ + handle: lib, + fnMap: make(map[string]any), + }, nil +} + +func (lib *library) Dlsym(symbol string) (uintptr, error) { + return purego.Dlsym(lib.handle, symbol) +} + +func getFunc[T any](lib *library, symbol string) T { + var dlfun *dlFunc[T] + if f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok { + dlfun = f + } else { + dlfun = newDlfunc[T](symbol) + dlfun.init(lib.handle) + lib.fnMap[symbol] = dlfun } - // get proc info itself - buf := make([]byte, length) - _, _, err = unix.Syscall6( - 202, // unix.SYS___SYSCTL https://github.com/golang/sys/blob/76b94024e4b621e672466e8db3d7f084e7ddcad2/unix/zsysnum_darwin_amd64.go#L146 - uintptr(unsafe.Pointer(&mib[0])), - uintptr(miblen), - uintptr(unsafe.Pointer(&buf[0])), - uintptr(unsafe.Pointer(&length)), - 0, - 0) - if err != 0 { - return buf, length, err + return dlfun.fn +} + +func (lib *library) Close() { + purego.Dlclose(lib.handle) +} + +type dlFunc[T any] struct { + sym string + fn T +} + +func (d *dlFunc[T]) init(handle uintptr) { + purego.RegisterLibFunc(&d.fn, handle, d.sym) +} + +func newDlfunc[T any](sym string) *dlFunc[T] { + return &dlFunc[T]{sym: sym} +} + +type CoreFoundationLib struct { + *library +} + +func NewCoreFoundationLib() (*CoreFoundationLib, error) { + library, err := newLibrary(CoreFoundationLibPath) + if err != nil { + return nil, err } + return &CoreFoundationLib{library}, nil +} - return buf, length, nil +func (c *CoreFoundationLib) CFGetTypeID(cf uintptr) int32 { + fn := getFunc[CFGetTypeIDFunc](c.library, "CFGetTypeID") + return fn(cf) } -// Library represents a dynamic library loaded by purego. -type Library struct { - addr uintptr - path string - close func() +func (c *CoreFoundationLib) CFNumberCreate(allocator uintptr, theType int32, valuePtr uintptr) unsafe.Pointer { + fn := getFunc[CFNumberCreateFunc](c.library, "CFNumberCreate") + return fn(allocator, theType, valuePtr) } -// library paths -const ( - IOKit = "/System/Library/Frameworks/IOKit.framework/IOKit" - CoreFoundation = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" - System = "/usr/lib/libSystem.B.dylib" -) +func (c *CoreFoundationLib) CFNumberGetValue(num uintptr, theType int32, valuePtr uintptr) bool { + fn := getFunc[CFNumberGetValueFunc](c.library, "CFNumberGetValue") + return fn(num, theType, valuePtr) +} -func NewLibrary(path string) (*Library, error) { - lib, err := purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL) +func (c *CoreFoundationLib) CFDictionaryCreate(allocator uintptr, keys, values *unsafe.Pointer, numValues int32, + keyCallBacks, valueCallBacks uintptr, +) unsafe.Pointer { + fn := getFunc[CFDictionaryCreateFunc](c.library, "CFDictionaryCreate") + return fn(allocator, keys, values, numValues, keyCallBacks, valueCallBacks) +} + +func (c *CoreFoundationLib) CFDictionaryAddValue(theDict, key, value uintptr) { + fn := getFunc[CFDictionaryAddValueFunc](c.library, "CFDictionaryAddValue") + fn(theDict, key, value) +} + +func (c *CoreFoundationLib) CFDictionaryGetValue(theDict, key uintptr) unsafe.Pointer { + fn := getFunc[CFDictionaryGetValueFunc](c.library, "CFDictionaryGetValue") + return fn(theDict, key) +} + +func (c *CoreFoundationLib) CFArrayGetCount(theArray uintptr) int32 { + fn := getFunc[CFArrayGetCountFunc](c.library, "CFArrayGetCount") + return fn(theArray) +} + +func (c *CoreFoundationLib) CFArrayGetValueAtIndex(theArray uintptr, index int32) unsafe.Pointer { + fn := getFunc[CFArrayGetValueAtIndexFunc](c.library, "CFArrayGetValueAtIndex") + return fn(theArray, index) +} + +func (c *CoreFoundationLib) CFStringCreateMutable(alloc uintptr, maxLength int32) unsafe.Pointer { + fn := getFunc[CFStringCreateMutableFunc](c.library, "CFStringCreateMutable") + return fn(alloc, maxLength) +} + +func (c *CoreFoundationLib) CFStringGetLength(theString uintptr) int32 { + fn := getFunc[CFStringGetLengthFunc](c.library, "CFStringGetLength") + return fn(theString) +} + +func (c *CoreFoundationLib) CFStringGetCString(theString uintptr, buffer CStr, bufferSize int32, encoding uint32) { + fn := getFunc[CFStringGetCStringFunc](c.library, "CFStringGetCString") + fn(theString, buffer, bufferSize, encoding) +} + +func (c *CoreFoundationLib) CFStringCreateWithCString(alloc uintptr, cStr string, encoding uint32) unsafe.Pointer { + fn := getFunc[CFStringCreateWithCStringFunc](c.library, "CFStringCreateWithCString") + return fn(alloc, cStr, encoding) +} + +func (c *CoreFoundationLib) CFDataGetLength(theData uintptr) int32 { + fn := getFunc[CFDataGetLengthFunc](c.library, "CFDataGetLength") + return fn(theData) +} + +func (c *CoreFoundationLib) CFDataGetBytePtr(theData uintptr) unsafe.Pointer { + fn := getFunc[CFDataGetBytePtrFunc](c.library, "CFDataGetBytePtr") + return fn(theData) +} + +func (c *CoreFoundationLib) CFRelease(cf uintptr) { + fn := getFunc[CFReleaseFunc](c.library, "CFRelease") + fn(cf) +} + +type IOKitLib struct { + *library +} + +func NewIOKitLib() (*IOKitLib, error) { + library, err := newLibrary(IOKitLibPath) if err != nil { return nil, err } + return &IOKitLib{library}, nil +} - closeFunc := func() { - purego.Dlclose(lib) +func (l *IOKitLib) IOServiceGetMatchingService(mainPort uint32, matching uintptr) uint32 { + fn := getFunc[IOServiceGetMatchingServiceFunc](l.library, "IOServiceGetMatchingService") + return fn(mainPort, matching) +} + +func (l *IOKitLib) IOServiceGetMatchingServices(mainPort uint32, matching uintptr, existing *uint32) int { + fn := getFunc[IOServiceGetMatchingServicesFunc](l.library, "IOServiceGetMatchingServices") + return fn(mainPort, matching, existing) +} + +func (l *IOKitLib) IOServiceMatching(name string) unsafe.Pointer { + fn := getFunc[IOServiceMatchingFunc](l.library, "IOServiceMatching") + return fn(name) +} + +func (l *IOKitLib) IOServiceOpen(service, owningTask, connType uint32, connect *uint32) int { + fn := getFunc[IOServiceOpenFunc](l.library, "IOServiceOpen") + return fn(service, owningTask, connType, connect) +} + +func (l *IOKitLib) IOServiceClose(connect uint32) int { + fn := getFunc[IOServiceCloseFunc](l.library, "IOServiceClose") + return fn(connect) +} + +func (l *IOKitLib) IOIteratorNext(iterator uint32) uint32 { + fn := getFunc[IOIteratorNextFunc](l.library, "IOIteratorNext") + return fn(iterator) +} + +func (l *IOKitLib) IORegistryEntryGetName(entry uint32, name CStr) int { + fn := getFunc[IORegistryEntryGetNameFunc](l.library, "IORegistryEntryGetName") + return fn(entry, name) +} + +func (l *IOKitLib) IORegistryEntryGetParentEntry(entry uint32, plane string, parent *uint32) int { + fn := getFunc[IORegistryEntryGetParentEntryFunc](l.library, "IORegistryEntryGetParentEntry") + return fn(entry, plane, parent) +} + +func (l *IOKitLib) IORegistryEntryCreateCFProperty(entry uint32, key, allocator uintptr, options uint32) unsafe.Pointer { + fn := getFunc[IORegistryEntryCreateCFPropertyFunc](l.library, "IORegistryEntryCreateCFProperty") + return fn(entry, key, allocator, options) +} + +func (l *IOKitLib) IORegistryEntryCreateCFProperties(entry uint32, properties unsafe.Pointer, allocator uintptr, options uint32) int { + fn := getFunc[IORegistryEntryCreateCFPropertiesFunc](l.library, "IORegistryEntryCreateCFProperties") + return fn(entry, properties, allocator, options) +} + +func (l *IOKitLib) IOObjectConformsTo(object uint32, className string) bool { + fn := getFunc[IOObjectConformsToFunc](l.library, "IOObjectConformsTo") + return fn(object, className) +} + +func (l *IOKitLib) IOObjectRelease(object uint32) int { + fn := getFunc[IOObjectReleaseFunc](l.library, "IOObjectRelease") + return fn(object) +} + +func (l *IOKitLib) IOConnectCallStructMethod(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int { + fn := getFunc[IOConnectCallStructMethodFunc](l.library, "IOConnectCallStructMethod") + return fn(connection, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt) +} + +func (l *IOKitLib) IOHIDEventSystemClientCreate(allocator uintptr) unsafe.Pointer { + fn := getFunc[IOHIDEventSystemClientCreateFunc](l.library, "IOHIDEventSystemClientCreate") + return fn(allocator) +} + +func (l *IOKitLib) IOHIDEventSystemClientSetMatching(client, match uintptr) int { + fn := getFunc[IOHIDEventSystemClientSetMatchingFunc](l.library, "IOHIDEventSystemClientSetMatching") + return fn(client, match) +} + +func (l *IOKitLib) IOHIDServiceClientCopyEvent(service uintptr, eventType int64, options int32, timeout int64) unsafe.Pointer { + fn := getFunc[IOHIDServiceClientCopyEventFunc](l.library, "IOHIDServiceClientCopyEvent") + return fn(service, eventType, options, timeout) +} + +func (l *IOKitLib) IOHIDServiceClientCopyProperty(service, property uintptr) unsafe.Pointer { + fn := getFunc[IOHIDServiceClientCopyPropertyFunc](l.library, "IOHIDServiceClientCopyProperty") + return fn(service, property) +} + +func (l *IOKitLib) IOHIDEventGetFloatValue(event uintptr, field int32) float64 { + fn := getFunc[IOHIDEventGetFloatValueFunc](l.library, "IOHIDEventGetFloatValue") + return fn(event, field) +} + +func (l *IOKitLib) IOHIDEventSystemClientCopyServices(client uintptr) unsafe.Pointer { + fn := getFunc[IOHIDEventSystemClientCopyServicesFunc](l.library, "IOHIDEventSystemClientCopyServices") + return fn(client) +} + +type SystemLib struct { + *library +} + +func NewSystemLib() (*SystemLib, error) { + library, err := newLibrary(SystemLibPath) + if err != nil { + return nil, err } + return &SystemLib{library}, nil +} - return &Library{ - addr: lib, - path: path, - close: closeFunc, - }, nil +func (s *SystemLib) HostProcessorInfo(host uint32, flavor int32, outProcessorCount *uint32, outProcessorInfo uintptr, + outProcessorInfoCnt *uint32, +) int { + fn := getFunc[HostProcessorInfoFunc](s.library, "host_processor_info") + return fn(host, flavor, outProcessorCount, outProcessorInfo, outProcessorInfoCnt) +} + +func (s *SystemLib) HostStatistics(host uint32, flavor int32, hostInfoOut uintptr, hostInfoOutCnt *uint32) int { + fn := getFunc[HostStatisticsFunc](s.library, "host_statistics") + return fn(host, flavor, hostInfoOut, hostInfoOutCnt) +} + +func (s *SystemLib) MachHostSelf() uint32 { + fn := getFunc[MachHostSelfFunc](s.library, "mach_host_self") + return fn() } -func (lib *Library) Dlsym(symbol string) (uintptr, error) { - return purego.Dlsym(lib.addr, symbol) +func (s *SystemLib) MachTaskSelf() uint32 { + fn := getFunc[MachTaskSelfFunc](s.library, "mach_task_self") + return fn() } -func GetFunc[T any](lib *Library, symbol string) T { - var fptr T - purego.RegisterLibFunc(&fptr, lib.addr, symbol) - return fptr +func (s *SystemLib) MachTimeBaseInfo(info uintptr) int { + fn := getFunc[MachTimeBaseInfoFunc](s.library, "mach_timebase_info") + return fn(info) } -func (lib *Library) Close() { - lib.close() +func (s *SystemLib) VMDeallocate(targetTask uint32, vmAddress, vmSize uintptr) int { + fn := getFunc[VMDeallocateFunc](s.library, "vm_deallocate") + return fn(targetTask, vmAddress, vmSize) +} + +func (s *SystemLib) ProcPidPath(pid int32, buffer uintptr, bufferSize uint32) int32 { + fn := getFunc[ProcPidPathFunc](s.library, "proc_pidpath") + return fn(pid, buffer, bufferSize) +} + +func (s *SystemLib) ProcPidInfo(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32 { + fn := getFunc[ProcPidInfoFunc](s.library, "proc_pidinfo") + return fn(pid, flavor, arg, buffer, bufferSize) } // status codes @@ -100,7 +324,7 @@ const ( KERN_SUCCESS = 0 ) -// IOKit functions and symbols. +// IOKit types and constants. type ( IOServiceGetMatchingServiceFunc func(mainPort uint32, matching uintptr) uint32 IOServiceGetMatchingServicesFunc func(mainPort uint32, matching uintptr, existing *uint32) int @@ -125,29 +349,6 @@ type ( IOHIDEventSystemClientCopyServicesFunc func(client uintptr) unsafe.Pointer ) -const ( - IOServiceGetMatchingServiceSym = "IOServiceGetMatchingService" - IOServiceGetMatchingServicesSym = "IOServiceGetMatchingServices" - IOServiceMatchingSym = "IOServiceMatching" - IOServiceOpenSym = "IOServiceOpen" - IOServiceCloseSym = "IOServiceClose" - IOIteratorNextSym = "IOIteratorNext" - IORegistryEntryGetNameSym = "IORegistryEntryGetName" - IORegistryEntryGetParentEntrySym = "IORegistryEntryGetParentEntry" - IORegistryEntryCreateCFPropertySym = "IORegistryEntryCreateCFProperty" - IORegistryEntryCreateCFPropertiesSym = "IORegistryEntryCreateCFProperties" - IOObjectConformsToSym = "IOObjectConformsTo" - IOObjectReleaseSym = "IOObjectRelease" - IOConnectCallStructMethodSym = "IOConnectCallStructMethod" - - IOHIDEventSystemClientCreateSym = "IOHIDEventSystemClientCreate" - IOHIDEventSystemClientSetMatchingSym = "IOHIDEventSystemClientSetMatching" - IOHIDServiceClientCopyEventSym = "IOHIDServiceClientCopyEvent" - IOHIDServiceClientCopyPropertySym = "IOHIDServiceClientCopyProperty" - IOHIDEventGetFloatValueSym = "IOHIDEventGetFloatValue" - IOHIDEventSystemClientCopyServicesSym = "IOHIDEventSystemClientCopyServices" -) - const ( KIOMainPortDefault = 0 @@ -161,7 +362,7 @@ const ( KIOServicePlane = "IOService" ) -// CoreFoundation functions and symbols. +// CoreFoundation types and constants. type ( CFGetTypeIDFunc func(cf uintptr) int32 CFNumberCreateFunc func(allocator uintptr, theType int32, valuePtr uintptr) unsafe.Pointer @@ -181,24 +382,6 @@ type ( CFReleaseFunc func(cf uintptr) ) -const ( - CFGetTypeIDSym = "CFGetTypeID" - CFNumberCreateSym = "CFNumberCreate" - CFNumberGetValueSym = "CFNumberGetValue" - CFDictionaryCreateSym = "CFDictionaryCreate" - CFDictionaryAddValueSym = "CFDictionaryAddValue" - CFDictionaryGetValueSym = "CFDictionaryGetValue" - CFArrayGetCountSym = "CFArrayGetCount" - CFArrayGetValueAtIndexSym = "CFArrayGetValueAtIndex" - CFStringCreateMutableSym = "CFStringCreateMutable" - CFStringGetLengthSym = "CFStringGetLength" - CFStringGetCStringSym = "CFStringGetCString" - CFStringCreateWithCStringSym = "CFStringCreateWithCString" - CFDataGetLengthSym = "CFDataGetLength" - CFDataGetBytePtrSym = "CFDataGetBytePtr" - CFReleaseSym = "CFRelease" -) - const ( KCFStringEncodingUTF8 = 0x08000100 KCFNumberSInt64Type = 4 @@ -206,7 +389,7 @@ const ( KCFAllocatorDefault = 0 ) -// Kernel functions and symbols. +// libSystem types and constants. type MachTimeBaseInfo struct { Numer uint32 Denom uint32 @@ -232,17 +415,12 @@ const ( ) const ( - CTL_KERN = 1 - KERN_ARGMAX = 8 - KERN_PROCARGS2 = 49 - HOST_VM_INFO = 2 HOST_CPU_LOAD_INFO = 3 HOST_VM_INFO_COUNT = 0xf ) -// System functions and symbols. type ( ProcPidPathFunc func(pid int32, buffer uintptr, bufferSize uint32) int32 ProcPidInfoFunc func(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32 @@ -256,6 +434,7 @@ const ( const ( MAXPATHLEN = 1024 + PROC_PIDLISTFDS = 1 PROC_PIDPATHINFO_MAXSIZE = 4 * MAXPATHLEN PROC_PIDTASKINFO = 4 PROC_PIDVNODEPATHINFO = 9 @@ -263,9 +442,8 @@ const ( // SMC represents a SMC instance. type SMC struct { - lib *Library - conn uint32 - callStruct IOConnectCallStructMethodFunc + lib *IOKitLib + conn uint32 } const ioServiceSMC = "AppleSMC" @@ -287,47 +465,39 @@ const ( KSMCKeyNotFound = 132 ) -func NewSMC(ioKit *Library) (*SMC, error) { - if ioKit.path != IOKit { - return nil, errors.New("library is not IOKit") +func NewSMC() (*SMC, error) { + iokit, err := NewIOKitLib() + if err != nil { + return nil, err } - ioServiceGetMatchingService := GetFunc[IOServiceGetMatchingServiceFunc](ioKit, IOServiceGetMatchingServiceSym) - ioServiceMatching := GetFunc[IOServiceMatchingFunc](ioKit, IOServiceMatchingSym) - ioServiceOpen := GetFunc[IOServiceOpenFunc](ioKit, IOServiceOpenSym) - ioObjectRelease := GetFunc[IOObjectReleaseFunc](ioKit, IOObjectReleaseSym) - machTaskSelf := GetFunc[MachTaskSelfFunc](ioKit, MachTaskSelfSym) - - ioConnectCallStructMethod := GetFunc[IOConnectCallStructMethodFunc](ioKit, IOConnectCallStructMethodSym) - - service := ioServiceGetMatchingService(0, uintptr(ioServiceMatching(ioServiceSMC))) + service := iokit.IOServiceGetMatchingService(0, uintptr(iokit.IOServiceMatching(ioServiceSMC))) if service == 0 { return nil, fmt.Errorf("ERROR: %s NOT FOUND", ioServiceSMC) } var conn uint32 - if result := ioServiceOpen(service, machTaskSelf(), 0, &conn); result != 0 { + machTaskSelf := getFunc[MachTaskSelfFunc](iokit.library, "mach_task_self") + if result := iokit.IOServiceOpen(service, machTaskSelf(), 0, &conn); result != 0 { return nil, errors.New("ERROR: IOServiceOpen failed") } - ioObjectRelease(service) + iokit.IOObjectRelease(service) return &SMC{ - lib: ioKit, - conn: conn, - callStruct: ioConnectCallStructMethod, + lib: iokit, + conn: conn, }, nil } func (s *SMC) CallStruct(selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int { - return s.callStruct(s.conn, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt) + return s.lib.IOConnectCallStructMethod(s.conn, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt) } func (s *SMC) Close() error { - ioServiceClose := GetFunc[IOServiceCloseFunc](s.lib, IOServiceCloseSym) - - if result := ioServiceClose(s.conn); result != 0 { + if result := s.lib.IOServiceClose(s.conn); result != 0 { return errors.New("ERROR: IOServiceClose failed") } + s.lib.Close() return nil } diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go b/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go index 659b65575bc..fd483dd09b8 100644 --- a/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go +++ b/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go @@ -14,6 +14,7 @@ type ExVirtualMemory struct { ActiveAnon uint64 `json:"activeanon"` InactiveAnon uint64 `json:"inactiveanon"` Unevictable uint64 `json:"unevictable"` + Percpu uint64 `json:"percpu"` } func (v ExVirtualMemory) String() string { diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem.go index 01932ddfda1..f4f46f0d2f9 100644 --- a/vendor/github.com/shirou/gopsutil/v4/mem/mem.go +++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem.go @@ -48,10 +48,11 @@ type VirtualMemoryStat struct { Laundry uint64 `json:"laundry"` // Linux specific numbers - // https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/6/html/deployment_guide/s2-proc-meminfo + // https://blogs.oracle.com/linux/understanding-linux-kernel-memory-statistics // https://www.kernel.org/doc/Documentation/filesystems/proc.txt // https://www.kernel.org/doc/Documentation/vm/overcommit-accounting // https://www.kernel.org/doc/Documentation/vm/transhuge.txt + // Buffers uint64 `json:"buffers"` Cached uint64 `json:"cached"` WriteBack uint64 `json:"writeBack"` diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go index 7d96a3bb098..1b3e9f21beb 100644 --- a/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go +++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go @@ -85,26 +85,23 @@ func VirtualMemory() (*VirtualMemoryStat, error) { } func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) { - machLib, err := common.NewLibrary(common.System) + sys, err := common.NewSystemLib() if err != nil { return nil, err } - defer machLib.Close() - - hostStatistics := common.GetFunc[common.HostStatisticsFunc](machLib, common.HostStatisticsSym) - machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym) + defer sys.Close() count := uint32(common.HOST_VM_INFO_COUNT) var vmstat vmStatisticsData - status := hostStatistics(machHostSelf(), common.HOST_VM_INFO, + status := sys.HostStatistics(sys.MachHostSelf(), common.HOST_VM_INFO, uintptr(unsafe.Pointer(&vmstat)), &count) if status != common.KERN_SUCCESS { return nil, fmt.Errorf("host_statistics error=%d", status) } - pageSizeAddr, _ := machLib.Dlsym("vm_kernel_page_size") + pageSizeAddr, _ := sys.Dlsym("vm_kernel_page_size") pageSize := **(**uint64)(unsafe.Pointer(&pageSizeAddr)) total, err := getHwMemsize() if err != nil { diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go index 4b53b4a004e..413fc3e9162 100644 --- a/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go +++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go @@ -138,6 +138,12 @@ func fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *ExVir return ret, retEx, err } retEx.Unevictable = t * 1024 + case "Percpu": + t, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return ret, retEx, err + } + retEx.Percpu = t * 1024 case "Writeback": t, err := strconv.ParseUint(value, 10, 64) if err != nil { diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go index e591e2d157d..d094d389d4d 100644 --- a/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go +++ b/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go @@ -36,10 +36,6 @@ func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesSta return nil, common.ErrNotImplementedError } -func (*Process) NumFDsWithContext(_ context.Context) (int32, error) { - return 0, common.ErrNotImplementedError -} - func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go index d0bba150883..d7fb921cbf4 100644 --- a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go +++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go @@ -280,31 +280,21 @@ func callPsWithContext(ctx context.Context, arg string, pid int32, threadOption, } type dlFuncs struct { - lib *common.Library - - procPidPath common.ProcPidPathFunc - procPidInfo common.ProcPidInfoFunc - machTimeBaseInfo common.MachTimeBaseInfoFunc + lib *common.SystemLib } func loadProcFuncs() (*dlFuncs, error) { - lib, err := common.NewLibrary(common.System) + lib, err := common.NewSystemLib() if err != nil { return nil, err } - - return &dlFuncs{ - lib: lib, - procPidPath: common.GetFunc[common.ProcPidPathFunc](lib, common.ProcPidPathSym), - procPidInfo: common.GetFunc[common.ProcPidInfoFunc](lib, common.ProcPidInfoSym), - machTimeBaseInfo: common.GetFunc[common.MachTimeBaseInfoFunc](lib, common.MachTimeBaseInfoSym), - }, nil + return &dlFuncs{lib}, err } func (f *dlFuncs) getTimeScaleToNanoSeconds() float64 { var timeBaseInfo common.MachTimeBaseInfo - f.machTimeBaseInfo(uintptr(unsafe.Pointer(&timeBaseInfo))) + f.lib.MachTimeBaseInfo(uintptr(unsafe.Pointer(&timeBaseInfo))) return float64(timeBaseInfo.Numer) / float64(timeBaseInfo.Denom) } @@ -321,7 +311,7 @@ func (p *Process) ExeWithContext(_ context.Context) (string, error) { defer funcs.Close() buf := common.NewCStr(common.PROC_PIDPATHINFO_MAXSIZE) - ret := funcs.procPidPath(p.Pid, buf.Addr(), common.PROC_PIDPATHINFO_MAXSIZE) + ret := funcs.lib.ProcPidPath(p.Pid, buf.Addr(), common.PROC_PIDPATHINFO_MAXSIZE) if ret <= 0 { return "", fmt.Errorf("unknown error: proc_pidpath returned %d", ret) @@ -330,13 +320,6 @@ func (p *Process) ExeWithContext(_ context.Context) (string, error) { return buf.GoString(), nil } -// sys/proc_info.h -type vnodePathInfo struct { - _ [152]byte - vipPath [common.MAXPATHLEN]byte - _ [1176]byte -} - // CwdWithContext retrieves the Current Working Directory for the given process. // It uses the proc_pidinfo from libproc and will only work for processes the // EUID can access. Otherwise "operation not permitted" will be returned as the @@ -355,7 +338,7 @@ func (p *Process) CwdWithContext(_ context.Context) (string, error) { var vpi vnodePathInfo const vpiSize = int32(unsafe.Sizeof(vpi)) - ret := funcs.procPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize) + ret := funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize) errno, _ := funcs.lib.Dlsym("errno") err = *(**unix.Errno)(unsafe.Pointer(&errno)) if errors.Is(err, unix.EPERM) { @@ -369,11 +352,11 @@ func (p *Process) CwdWithContext(_ context.Context) (string, error) { if ret != vpiSize { return "", fmt.Errorf("too few bytes; expected %d, got %d", vpiSize, ret) } - return common.GoString(&vpi.vipPath[0]), nil + return common.GoString((*byte)(unsafe.Pointer(&vpi.Cdir.Path[0]))), nil } func procArgs(pid int32) ([]byte, int, error) { - procargs, _, err := common.CallSyscall([]int32{common.CTL_KERN, common.KERN_PROCARGS2, pid}) + procargs, err := unix.SysctlRaw("kern.procargs2", int(pid)) if err != nil { return nil, 0, err } @@ -447,7 +430,7 @@ func (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) { defer funcs.Close() var ti ProcTaskInfo - funcs.procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) + funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) return int32(ti.Threadnum), nil } @@ -460,7 +443,7 @@ func (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) { defer funcs.Close() var ti ProcTaskInfo - funcs.procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) + funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) timescaleToNanoSeconds := funcs.getTimeScaleToNanoSeconds() ret := &cpu.TimesStat{ @@ -479,7 +462,7 @@ func (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, err defer funcs.Close() var ti ProcTaskInfo - funcs.procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) + funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) ret := &MemoryInfoStat{ RSS: uint64(ti.Resident_size), @@ -488,3 +471,54 @@ func (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, err } return ret, nil } + +// procFDInfo represents a file descriptor entry from sys/proc_info.h +type procFDInfo struct { + ProcFd int32 + ProcFdtype uint32 +} + +// NumFDsWithContext returns the number of file descriptors used by the process. +// It uses proc_pidinfo with PROC_PIDLISTFDS to query the kernel for the count +// of open file descriptors. The method makes a single syscall and calculates +// the count from the buffer size returned by the kernel. +func (p *Process) NumFDsWithContext(_ context.Context) (int32, error) { + funcs, err := loadProcFuncs() + if err != nil { + return 0, err + } + defer funcs.Close() + + // First call: get required buffer size + bufferSize := funcs.lib.ProcPidInfo( + p.Pid, + common.PROC_PIDLISTFDS, + 0, + 0, // NULL buffer + 0, // 0 size + ) + if bufferSize <= 0 { + return 0, fmt.Errorf("unknown error: proc_pidinfo returned %d", bufferSize) + } + + // Allocate buffer of the required size + const sizeofProcFDInfo = int32(unsafe.Sizeof(procFDInfo{})) + numEntries := bufferSize / sizeofProcFDInfo + buf := make([]procFDInfo, numEntries) + + // Second call: get actual data + ret := funcs.lib.ProcPidInfo( + p.Pid, + common.PROC_PIDLISTFDS, + 0, + uintptr(unsafe.Pointer(&buf[0])), // Real buffer + bufferSize, // Size from first call + ) + if ret <= 0 { + return 0, fmt.Errorf("unknown error: proc_pidinfo returned %d", ret) + } + + // Calculate actual number of FDs returned + numFDs := ret / sizeofProcFDInfo + return numFDs, nil +} diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go index 890a5d5331a..a40f96195d8 100644 --- a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go +++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go @@ -233,6 +233,51 @@ type ProcTaskInfo struct { Priority int32 } +type vinfoStat struct { + Dev uint32 + Mode uint16 + Nlink uint16 + Ino uint64 + Uid uint32 + Gid uint32 + Atime int64 + Atimensec int64 + Mtime int64 + Mtimensec int64 + Ctime int64 + Ctimensec int64 + Birthtime int64 + Birthtimensec int64 + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint32 + Rdev uint32 + Qspare [2]int64 +} + +type fsid struct { + Val [2]int32 +} + +type vnodeInfo struct { + Stat vinfoStat + Type int32 + Pad int32 + Fsid fsid +} + +type vnodeInfoPath struct { + Vi vnodeInfo + Path [1024]int8 +} + +type vnodePathInfo struct { + Cdir vnodeInfoPath + Rdir vnodeInfoPath +} + type AuditinfoAddr struct { Auid uint32 Mask AuMask diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go index 8075cf227d1..7ab1afb1170 100644 --- a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go +++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go @@ -211,6 +211,51 @@ type ProcTaskInfo struct { Priority int32 } +type vinfoStat struct { + Dev uint32 + Mode uint16 + Nlink uint16 + Ino uint64 + Uid uint32 + Gid uint32 + Atime int64 + Atimensec int64 + Mtime int64 + Mtimensec int64 + Ctime int64 + Ctimensec int64 + Birthtime int64 + Birthtimensec int64 + Size int64 + Blocks int64 + Blksize int32 + Flags uint32 + Gen uint32 + Rdev uint32 + Qspare [2]int64 +} + +type fsid struct { + Val [2]int32 +} + +type vnodeInfo struct { + Stat vinfoStat + Type int32 + Pad int32 + Fsid fsid +} + +type vnodeInfoPath struct { + Vi vnodeInfo + Path [1024]int8 +} + +type vnodePathInfo struct { + Cdir vnodeInfoPath + Rdir vnodeInfoPath +} + type AuditinfoAddr struct { Auid uint32 Mask AuMask diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go index ae173ff1de1..283af9bb3fd 100644 --- a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go +++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go @@ -344,6 +344,10 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) { return results, nil } +func (*Process) NumFDsWithContext(_ context.Context) (int32, error) { + return 0, common.ErrNotImplementedError +} + func (p *Process) getKProc() (*KinfoProc, error) { mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid} diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go index 11bc5c18d22..31fdb85bc9d 100644 --- a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go +++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go @@ -342,6 +342,10 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) { return results, nil } +func (*Process) NumFDsWithContext(_ context.Context) (int32, error) { + return 0, common.ErrNotImplementedError +} + func (p *Process) getKProc() (*KinfoProc, error) { buf, length, err := callKernProcSyscall(KernProcPID, p.Pid) if err != nil { diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go index 1e642f3304f..f5723d4f7e5 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_x86.go +++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -64,6 +64,80 @@ func initOptions() { func archInit() { + // From internal/cpu + const ( + // eax bits + cpuid_AVXVNNI = 1 << 4 + + // ecx bits + cpuid_SSE3 = 1 << 0 + cpuid_PCLMULQDQ = 1 << 1 + cpuid_AVX512VBMI = 1 << 1 + cpuid_AVX512VBMI2 = 1 << 6 + cpuid_SSSE3 = 1 << 9 + cpuid_AVX512GFNI = 1 << 8 + cpuid_AVX512VAES = 1 << 9 + cpuid_AVX512VNNI = 1 << 11 + cpuid_AVX512BITALG = 1 << 12 + cpuid_FMA = 1 << 12 + cpuid_AVX512VPOPCNTDQ = 1 << 14 + cpuid_SSE41 = 1 << 19 + cpuid_SSE42 = 1 << 20 + cpuid_POPCNT = 1 << 23 + cpuid_AES = 1 << 25 + cpuid_OSXSAVE = 1 << 27 + cpuid_AVX = 1 << 28 + + // "Extended Feature Flag" bits returned in EBX for CPUID EAX=0x7 ECX=0x0 + cpuid_BMI1 = 1 << 3 + cpuid_AVX2 = 1 << 5 + cpuid_BMI2 = 1 << 8 + cpuid_ERMS = 1 << 9 + cpuid_AVX512F = 1 << 16 + cpuid_AVX512DQ = 1 << 17 + cpuid_ADX = 1 << 19 + cpuid_AVX512CD = 1 << 28 + cpuid_SHA = 1 << 29 + cpuid_AVX512BW = 1 << 30 + cpuid_AVX512VL = 1 << 31 + + // "Extended Feature Flag" bits returned in ECX for CPUID EAX=0x7 ECX=0x0 + cpuid_AVX512_VBMI = 1 << 1 + cpuid_AVX512_VBMI2 = 1 << 6 + cpuid_GFNI = 1 << 8 + cpuid_AVX512VPCLMULQDQ = 1 << 10 + cpuid_AVX512_BITALG = 1 << 12 + + // edx bits + cpuid_FSRM = 1 << 4 + // edx bits for CPUID 0x80000001 + cpuid_RDTSCP = 1 << 27 + ) + // Additional constants not in internal/cpu + const ( + // eax=1: edx + cpuid_SSE2 = 1 << 26 + // eax=1: ecx + cpuid_CX16 = 1 << 13 + cpuid_RDRAND = 1 << 30 + // eax=7,ecx=0: ebx + cpuid_RDSEED = 1 << 18 + cpuid_AVX512IFMA = 1 << 21 + cpuid_AVX512PF = 1 << 26 + cpuid_AVX512ER = 1 << 27 + // eax=7,ecx=0: edx + cpuid_AVX5124VNNIW = 1 << 2 + cpuid_AVX5124FMAPS = 1 << 3 + cpuid_AMXBF16 = 1 << 22 + cpuid_AMXTile = 1 << 24 + cpuid_AMXInt8 = 1 << 25 + // eax=7,ecx=1: eax + cpuid_AVX512BF16 = 1 << 5 + cpuid_AVXIFMA = 1 << 23 + // eax=7,ecx=1: edx + cpuid_AVXVNNIInt8 = 1 << 4 + ) + Initialized = true maxID, _, _, _ := cpuid(0, 0) @@ -73,90 +147,90 @@ func archInit() { } _, _, ecx1, edx1 := cpuid(1, 0) - X86.HasSSE2 = isSet(26, edx1) - - X86.HasSSE3 = isSet(0, ecx1) - X86.HasPCLMULQDQ = isSet(1, ecx1) - X86.HasSSSE3 = isSet(9, ecx1) - X86.HasFMA = isSet(12, ecx1) - X86.HasCX16 = isSet(13, ecx1) - X86.HasSSE41 = isSet(19, ecx1) - X86.HasSSE42 = isSet(20, ecx1) - X86.HasPOPCNT = isSet(23, ecx1) - X86.HasAES = isSet(25, ecx1) - X86.HasOSXSAVE = isSet(27, ecx1) - X86.HasRDRAND = isSet(30, ecx1) + X86.HasSSE2 = isSet(edx1, cpuid_SSE2) + + X86.HasSSE3 = isSet(ecx1, cpuid_SSE3) + X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ) + X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3) + X86.HasFMA = isSet(ecx1, cpuid_FMA) + X86.HasCX16 = isSet(ecx1, cpuid_CX16) + X86.HasSSE41 = isSet(ecx1, cpuid_SSE41) + X86.HasSSE42 = isSet(ecx1, cpuid_SSE42) + X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT) + X86.HasAES = isSet(ecx1, cpuid_AES) + X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE) + X86.HasRDRAND = isSet(ecx1, cpuid_RDRAND) var osSupportsAVX, osSupportsAVX512 bool // For XGETBV, OSXSAVE bit is required and sufficient. if X86.HasOSXSAVE { eax, _ := xgetbv() // Check if XMM and YMM registers have OS support. - osSupportsAVX = isSet(1, eax) && isSet(2, eax) + osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2) if runtime.GOOS == "darwin" { // Darwin requires special AVX512 checks, see cpu_darwin_x86.go osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512() } else { // Check if OPMASK and ZMM registers have OS support. - osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) + osSupportsAVX512 = osSupportsAVX && isSet(eax, 1<<5) && isSet(eax, 1<<6) && isSet(eax, 1<<7) } } - X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX if maxID < 7 { return } eax7, ebx7, ecx7, edx7 := cpuid(7, 0) - X86.HasBMI1 = isSet(3, ebx7) - X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX - X86.HasBMI2 = isSet(8, ebx7) - X86.HasERMS = isSet(9, ebx7) - X86.HasRDSEED = isSet(18, ebx7) - X86.HasADX = isSet(19, ebx7) - - X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension + X86.HasBMI1 = isSet(ebx7, cpuid_BMI1) + X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX + X86.HasBMI2 = isSet(ebx7, cpuid_BMI2) + X86.HasERMS = isSet(ebx7, cpuid_ERMS) + X86.HasRDSEED = isSet(ebx7, cpuid_RDSEED) + X86.HasADX = isSet(ebx7, cpuid_ADX) + + X86.HasAVX512 = isSet(ebx7, cpuid_AVX512F) && osSupportsAVX512 // Because avx-512 foundation is the core required extension if X86.HasAVX512 { X86.HasAVX512F = true - X86.HasAVX512CD = isSet(28, ebx7) - X86.HasAVX512ER = isSet(27, ebx7) - X86.HasAVX512PF = isSet(26, ebx7) - X86.HasAVX512VL = isSet(31, ebx7) - X86.HasAVX512BW = isSet(30, ebx7) - X86.HasAVX512DQ = isSet(17, ebx7) - X86.HasAVX512IFMA = isSet(21, ebx7) - X86.HasAVX512VBMI = isSet(1, ecx7) - X86.HasAVX5124VNNIW = isSet(2, edx7) - X86.HasAVX5124FMAPS = isSet(3, edx7) - X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7) - X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7) - X86.HasAVX512VNNI = isSet(11, ecx7) - X86.HasAVX512GFNI = isSet(8, ecx7) - X86.HasAVX512VAES = isSet(9, ecx7) - X86.HasAVX512VBMI2 = isSet(6, ecx7) - X86.HasAVX512BITALG = isSet(12, ecx7) + X86.HasAVX512CD = isSet(ebx7, cpuid_AVX512CD) + X86.HasAVX512ER = isSet(ebx7, cpuid_AVX512ER) + X86.HasAVX512PF = isSet(ebx7, cpuid_AVX512PF) + X86.HasAVX512VL = isSet(ebx7, cpuid_AVX512VL) + X86.HasAVX512BW = isSet(ebx7, cpuid_AVX512BW) + X86.HasAVX512DQ = isSet(ebx7, cpuid_AVX512DQ) + X86.HasAVX512IFMA = isSet(ebx7, cpuid_AVX512IFMA) + X86.HasAVX512VBMI = isSet(ecx7, cpuid_AVX512_VBMI) + X86.HasAVX5124VNNIW = isSet(edx7, cpuid_AVX5124VNNIW) + X86.HasAVX5124FMAPS = isSet(edx7, cpuid_AVX5124FMAPS) + X86.HasAVX512VPOPCNTDQ = isSet(ecx7, cpuid_AVX512VPOPCNTDQ) + X86.HasAVX512VPCLMULQDQ = isSet(ecx7, cpuid_AVX512VPCLMULQDQ) + X86.HasAVX512VNNI = isSet(ecx7, cpuid_AVX512VNNI) + X86.HasAVX512GFNI = isSet(ecx7, cpuid_AVX512GFNI) + X86.HasAVX512VAES = isSet(ecx7, cpuid_AVX512VAES) + X86.HasAVX512VBMI2 = isSet(ecx7, cpuid_AVX512VBMI2) + X86.HasAVX512BITALG = isSet(ecx7, cpuid_AVX512BITALG) } - X86.HasAMXTile = isSet(24, edx7) - X86.HasAMXInt8 = isSet(25, edx7) - X86.HasAMXBF16 = isSet(22, edx7) + X86.HasAMXTile = isSet(edx7, cpuid_AMXTile) + X86.HasAMXInt8 = isSet(edx7, cpuid_AMXInt8) + X86.HasAMXBF16 = isSet(edx7, cpuid_AMXBF16) // These features depend on the second level of extended features. if eax7 >= 1 { eax71, _, _, edx71 := cpuid(7, 1) if X86.HasAVX512 { - X86.HasAVX512BF16 = isSet(5, eax71) + X86.HasAVX512BF16 = isSet(eax71, cpuid_AVX512BF16) } if X86.HasAVX { - X86.HasAVXIFMA = isSet(23, eax71) - X86.HasAVXVNNI = isSet(4, eax71) - X86.HasAVXVNNIInt8 = isSet(4, edx71) + X86.HasAVXIFMA = isSet(eax71, cpuid_AVXIFMA) + X86.HasAVXVNNI = isSet(eax71, cpuid_AVXVNNI) + X86.HasAVXVNNIInt8 = isSet(edx71, cpuid_AVXVNNIInt8) } } } -func isSet(bitpos uint, value uint32) bool { - return value&(1<