fix(deps): update module github.com/shirou/gopsutil/v4 to v4.26.3

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This commit is contained in:
renovate[bot] 2026-04-01 10:03:05 +00:00 committed by GitHub
parent e1360b6f59
commit ee83454a00
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 123 additions and 85 deletions

2
go.mod
View file

@ -57,7 +57,7 @@ require (
github.com/opencontainers/selinux v1.13.1
github.com/openshift/imagebuilder v1.2.20
github.com/rootless-containers/rootlesskit/v2 v2.3.6
github.com/shirou/gopsutil/v4 v4.26.2
github.com/shirou/gopsutil/v4 v4.26.3
github.com/sirupsen/logrus v1.9.4
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10

4
go.sum
View file

@ -335,8 +335,8 @@ github.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxo
github.com/secure-systems-lab/go-securesystemslib v0.10.0/go.mod h1:MRKONWmRoFzPNQ9USRF9i1mc7MvAVvF1LlW8X5VWDvk=
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.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI=
github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc=
github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/sigstore/fulcio v1.8.5 h1:HYTD1/L5wlBp8JxsWxUf8hmfaNBBF/x3r3p5l6tZwbA=
github.com/sigstore/fulcio v1.8.5/go.mod h1:tSLYK3JsKvJpDW1BsIsVHZgHj+f8TjXARzqIUWSsSPQ=
github.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA4FIkofAY=

View file

@ -27,16 +27,16 @@ func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
ret = append(ret, *ct)
}
} else {
c, err := perfstat.CpuUtilTotalStat()
c, err := perfstat.CpuTotalStat()
if err != nil {
return nil, err
}
ct := &TimesStat{
CPU: "cpu-total",
Idle: float64(c.IdlePct),
User: float64(c.UserPct),
System: float64(c.KernPct),
Iowait: float64(c.WaitPct),
Idle: float64(c.Idle),
User: float64(c.User),
System: float64(c.Sys),
Iowait: float64(c.Wait),
}
ret = append(ret, *ct)
}
@ -48,19 +48,32 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
if err != nil {
return nil, err
}
p, err := perfstat.LparInfo()
if err != nil {
return nil, err
}
info := InfoStat{
CPU: 0,
Mhz: float64(c.ProcessorHz / 1000000),
Cores: int32(c.NCpusCfg),
CPU: 0,
ModelName: c.Description,
Mhz: float64(c.ProcessorHz / 1000000),
Cores: int32(p.OnlineVCpus),
}
result := []InfoStat{info}
return result, nil
}
func CountsWithContext(ctx context.Context, logical bool) (int, error) {
c, err := perfstat.CpuTotalStat()
if logical {
c, err := perfstat.CpuTotalStat()
if err != nil {
return 0, err
}
return c.NCpusCfg, nil
}
// For physical count, use the number of online virtual CPUs (before SMT multiplications).
p, err := perfstat.LparInfo()
if err != nil {
return 0, err
}
return c.NCpusCfg, nil
return int(p.OnlineVCpus), nil
}

View file

@ -6,24 +6,38 @@ package cpu
import (
"encoding/binary"
"fmt"
"sync"
"unsafe"
"github.com/shirou/gopsutil/v4/internal/common"
)
// Keep IOKit and CoreFoundation libraries open for the process lifetime.
// See: https://github.com/shirou/gopsutil/issues/1832
var (
cpuLibOnce sync.Once
cpuIOKit *common.IOKitLib
cpuCF *common.CoreFoundationLib
cpuLibErr error
)
func initCPULibraries() {
cpuIOKit, cpuLibErr = common.NewIOKitLib()
if cpuLibErr != nil {
return
}
cpuCF, cpuLibErr = common.NewCoreFoundationLib()
}
// https://github.com/shoenig/go-m1cpu/blob/v0.1.6/cpu.go
func getFrequency() (float64, error) {
iokit, err := common.NewIOKitLib()
if err != nil {
return 0, err
cpuLibOnce.Do(initCPULibraries)
if cpuLibErr != nil {
return 0, cpuLibErr
}
defer iokit.Close()
corefoundation, err := common.NewCoreFoundationLib()
if err != nil {
return 0, err
}
defer corefoundation.Close()
iokit := cpuIOKit
corefoundation := cpuCF
matching := iokit.IOServiceMatching("AppleARMIODevice")

View file

@ -334,7 +334,7 @@ func PathExists(filename string) bool {
// PathExistsWithContents returns the filename exists and it is not empty
func PathExistsWithContents(filename string) bool {
info, err := os.Stat(filename) //nolint:gosec // filename is constructed from system paths, not user input
info, err := os.Stat(filename)
if err != nil {
return false
}

View file

@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"math"
"sync"
"unsafe"
"github.com/ebitengine/purego"
@ -16,6 +17,7 @@ import (
type library struct {
handle uintptr
fnMap map[string]any
mu sync.RWMutex
}
// library paths
@ -41,15 +43,29 @@ func (lib *library) Dlsym(symbol string) (uintptr, error) {
return purego.Dlsym(lib.handle, symbol)
}
// getFunc resolves a function pointer from the library, caching it in fnMap.
// Thread-safe via double-checked locking to support shared library handles.
func getFunc[T any](lib *library, symbol string) T {
var dlfun *dlFunc[T]
// Fast path: read lock only
lib.mu.RLock()
if f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok {
dlfun = f
} else {
dlfun = newDlfunc[T](symbol)
dlfun.init(lib.handle)
lib.fnMap[symbol] = dlfun
lib.mu.RUnlock()
return f.fn
}
lib.mu.RUnlock()
// Slow path: write lock for first-time resolution
lib.mu.Lock()
defer lib.mu.Unlock()
// Double-check after acquiring write lock
if f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok {
return f.fn
}
dlfun := newDlfunc[T](symbol)
dlfun.init(lib.handle)
lib.fnMap[symbol] = dlfun
return dlfun.fn
}

View file

@ -18,13 +18,6 @@ import (
"github.com/shirou/gopsutil/v4/internal/common"
)
// WillBeDeletedOptOutMemAvailableCalc is a context key to opt out of calculating Mem.Used.
// This is not documented, and will be removed in Mar. 2026. This constant will be removed
// in the future, but it is currently public. The reason is that making it public allows
// developers to notice its removal when their build fails.
// See https://github.com/shirou/gopsutil/issues/1873
const WillBeDeletedOptOutMemAvailableCalc = "optOutMemAvailableCalc"
func VirtualMemory() (*VirtualMemoryStat, error) {
return VirtualMemoryWithContext(context.Background())
}
@ -325,16 +318,7 @@ func fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *ExVir
ret.Available = ret.Cached + ret.Free
}
}
// Opt-Out of calculating Mem.Used if the context has the context key set to true.
// This is used for backward compatibility with applications that expect the old calculation method.
// However, we plan to standardize on using MemAvailable in the future.
// Therefore, please avoid using this opt-out unless it is absolutely necessary.
// see https://github.com/shirou/gopsutil/issues/1873
if val, ok := ctx.Value(WillBeDeletedOptOutMemAvailableCalc).(bool); ok && val {
ret.Used = ret.Total - ret.Free - ret.Buffers - ret.Cached
} else {
ret.Used = ret.Total - ret.Available
}
ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0

View file

@ -38,19 +38,6 @@ func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {
}
p := uint64(uvmexp.Pagesize)
ret := &VirtualMemoryStat{
Total: uint64(uvmexp.Npages) * p,
Free: uint64(uvmexp.Free) * p,
Active: uint64(uvmexp.Active) * p,
Inactive: uint64(uvmexp.Inactive) * p,
Cached: 0, // not available
Wired: uint64(uvmexp.Wired) * p,
}
ret.Available = ret.Inactive + ret.Cached + ret.Free
ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
mib := []int32{CTLVfs, VfsGeneric, VfsBcacheStat}
buf, length, err := common.CallSyscall(mib)
if err != nil {
@ -64,7 +51,23 @@ func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {
if err := binary.Read(br, binary.LittleEndian, &bcs); err != nil {
return nil, err
}
ret.Buffers = uint64(bcs.Numbufpages) * p
// On OpenBSD, the buffer cache is the closest equivalent to both
// Linux's Buffers and Cached memory.
bcache := uint64(bcs.Numbufpages) * p
ret := &VirtualMemoryStat{
Total: uint64(uvmexp.Npages) * p,
Free: uint64(uvmexp.Free) * p,
Active: uint64(uvmexp.Active) * p,
Inactive: uint64(uvmexp.Inactive) * p,
Cached: bcache,
Buffers: bcache,
Wired: uint64(uvmexp.Wired) * p,
}
ret.Available = ret.Inactive + ret.Cached + ret.Free
ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
return ret, nil
}

View file

@ -23,8 +23,9 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
BytesRecv: uint64(netif.IBytes),
PacketsSent: uint64(netif.OPackets),
PacketsRecv: uint64(netif.IPackets),
Errin: uint64(netif.OErrors),
Errout: uint64(netif.IErrors),
Errin: uint64(netif.IErrors),
Errout: uint64(netif.OErrors),
Dropin: uint64(netif.IfIqDrops),
Dropout: uint64(netif.XmitDrops),
}
iocounters = append(iocounters, n)

View file

@ -54,15 +54,13 @@ func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err erro
parsed := make([]uint64, 0, 7)
vv := []string{
columns[base+3], // Ipkts == PacketsRecv
columns[base+4], // Ierrs == Errin
columns[base+5], // Ibytes == BytesRecv
columns[base+6], // Opkts == PacketsSent
columns[base+7], // Oerrs == Errout
columns[base+8], // Obytes == BytesSent
}
if len(columns) == 12 {
vv = append(vv, columns[base+10])
columns[base+3], // Ipkts == PacketsRecv
columns[base+4], // Ierrs == Errin
columns[base+5], // Ibytes == BytesRecv
columns[base+6], // Opkts == PacketsSent
columns[base+7], // Oerrs == Errout
columns[base+8], // Obytes == BytesSent
columns[base+10], // Drop == Dropout
}
for _, target := range vv {
@ -85,9 +83,7 @@ func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err erro
PacketsSent: parsed[3],
Errout: parsed[4],
BytesSent: parsed[5],
}
if len(parsed) == 7 {
stat.Dropout = parsed[6]
Dropout: parsed[6],
}
return stat, linkID, nil
}

View file

@ -348,6 +348,7 @@ type connTmp struct {
pid int32
boundPid int32
path string
inode string
}
func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
@ -405,6 +406,19 @@ func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, p
return statsFromInodesWithContext(ctx, root, pid, tmap, inodes, skipUids)
}
// connectionDedupKey builds a key to deduplicate connections.
// For inet sockets, the tuple (type, src, dst, status) is sufficient.
// For unix sockets, unnamed sockets share the same empty address,
// so pid, fd, and inode must be included to avoid incorrect deduplication.
// The inode is especially important when pid/fd are unavailable (e.g.,
// unprivileged queries where inode-to-pid mapping fails).
func connectionDedupKey(family uint32, c connTmp) string {
if family == syscall.AF_UNIX {
return fmt.Sprintf("%d-%d-%s-%d-%s:%d-%s:%d-%s", c.pid, c.fd, c.inode, c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)
}
return fmt.Sprintf("%d-%s:%d-%s:%d-%s", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)
}
func statsFromInodesWithContext(ctx context.Context, root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap, skipUids bool) ([]ConnectionStat, error) {
dupCheckMap := make(map[string]struct{})
var ret []ConnectionStat
@ -412,7 +426,6 @@ func statsFromInodesWithContext(ctx context.Context, root string, pid int32, tma
var err error
for _, t := range tmap {
var path string
var connKey string
var ls []connTmp
if pid == 0 {
path = fmt.Sprintf("%s/net/%s", root, t.filename)
@ -429,10 +442,7 @@ func statsFromInodesWithContext(ctx context.Context, root string, pid int32, tma
return nil, err
}
for _, c := range ls {
// Build TCP key to id the connection uniquely
// socket type, src ip, src port, dst ip, dst port and state should be enough
// to prevent duplications.
connKey = fmt.Sprintf("%d-%s:%d-%s:%d-%s", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)
connKey := connectionDedupKey(t.family, c)
if _, ok := dupCheckMap[connKey]; ok {
continue
}
@ -728,6 +738,7 @@ func processInet(file string, kind netConnectionKindType, inodes map[string][]in
raddr: ra,
status: status,
pid: pid,
inode: inode,
})
}
@ -785,6 +796,7 @@ func processUnix(file string, kind netConnectionKindType, inodes map[string][]in
pid: pair.pid,
status: "NONE",
path: path,
inode: inode,
})
}
}

View file

@ -133,7 +133,7 @@ func (p *Process) GidsWithContext(_ context.Context) ([]uint32, error) {
}
gids := make([]uint32, 0, 3)
gids = append(gids, uint32(k.Eproc.Pcred.P_rgid), uint32(k.Eproc.Pcred.P_rgid), uint32(k.Eproc.Pcred.P_svgid))
gids = append(gids, uint32(k.Eproc.Pcred.P_rgid), uint32(k.Eproc.Ucred.Groups[0]), uint32(k.Eproc.Pcred.P_svgid))
return gids, nil
}
@ -465,9 +465,8 @@ func (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, err
funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
ret := &MemoryInfoStat{
RSS: uint64(ti.Resident_size),
VMS: uint64(ti.Virtual_size),
Swap: uint64(ti.Pageins),
RSS: uint64(ti.Resident_size),
VMS: uint64(ti.Virtual_size),
}
return ret, nil
}

View file

@ -111,7 +111,7 @@ func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
defer proc.Release()
if isMount(common.HostProcWithContext(ctx)) { // if /<HOST_PROC>/proc exists and is mounted, check if /<HOST_PROC>/proc/<PID> folder exists
_, err := os.Stat(common.HostProcWithContext(ctx, strconv.Itoa(int(pid)))) //nolint:gosec // pid is int32, path traversal is not possible
_, err := os.Stat(common.HostProcWithContext(ctx, strconv.Itoa(int(pid))))
if os.IsNotExist(err) {
return false, nil
}

2
vendor/modules.txt vendored
View file

@ -604,7 +604,7 @@ github.com/seccomp/libseccomp-golang
# github.com/secure-systems-lab/go-securesystemslib v0.10.0
## explicit; go 1.24.0
github.com/secure-systems-lab/go-securesystemslib/encrypted
# github.com/shirou/gopsutil/v4 v4.26.2
# github.com/shirou/gopsutil/v4 v4.26.3
## explicit; go 1.24.0
github.com/shirou/gopsutil/v4/common
github.com/shirou/gopsutil/v4/cpu