Compare commits

..

No commits in common. 'master' and 'v4.24.12' have entirely different histories.

4
.gitattributes vendored

@ -1,4 +0,0 @@
# ensure that line endings for Windows builds are properly formatted
# see https://github.com/golangci/golangci-lint-action?tab=readme-ov-file#how-to-use
# at "Multiple OS Example" section
*.go text eol=lf

@ -1,15 +1,5 @@
on: [push, pull_request]
name: Build Test
on:
push:
branches:
- master
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
@ -22,7 +12,7 @@ jobs:
- id: versions
run: |
versions=$(curl -s 'https://go.dev/dl/?mode=json' | jq -c 'map(.version[2:])')
echo "value=${versions}" >> $GITHUB_OUTPUT
echo "::set-output name=value::${versions}"
build_test:
needs: go-versions
strategy:
@ -31,12 +21,24 @@ jobs:
go-version: ${{fromJson(needs.go-versions.outputs.versions)}}
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version: ${{ matrix.go-version }}
- name: Build Test v3
run: |
make build_test
- name: Install Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- id: cache-paths
run: |
echo "::set-output name=cache::$(go env GOCACHE)"
echo "::set-output name=mod-cache::$(go env GOMODCACHE)"
- name: Cache go modules
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: |
${{ steps.cache-paths.outputs.cache }}
${{ steps.cache-paths.outputs.mod-cache }}
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: Build Test v3
run: |
make build_test

@ -1,7 +1,6 @@
name: "Pull Request Labeler"
on:
pull_request_target:
- pull_request_target
permissions:
contents: read
@ -13,6 +12,6 @@ jobs:
pull-requests: write # for actions/labeler to add labels to PRs
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

@ -2,74 +2,28 @@ name: Golangci-lint
on:
push:
branches:
- master
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
golangci:
strategy:
fail-fast: false
matrix:
include:
- {os: macos-latest, CGO_ENABLED: "0", GOOS: darwin, GOARCH: amd64}
- {os: macos-latest, CGO_ENABLED: "1", GOOS: darwin, GOARCH: amd64}
- {os: macos-latest, CGO_ENABLED: "0", GOOS: darwin, GOARCH: arm64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: aix, GOARCH: ppc64}
# - {os: ubuntu-latest, CGO_ENABLED: "1", GOOS: aix, GOARCH: ppc64} # FIXME
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: dragonfly, GOARCH: amd64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: freebsd, GOARCH: amd64}
# - {os: ubuntu-latest, CGO_ENABLED: "1", GOOS: freebsd, GOARCH: amd64} # FIXME
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: freebsd, GOARCH: 386}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: freebsd, GOARCH: arm}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: 386}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: amd64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: arm64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: arm}
# - {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: loong64} # FIXME
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: mips64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: mips64le}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: mips}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: mipsle}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: ppc64le}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: ppc64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: riscv64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: linux, GOARCH: s390x}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: netbsd, GOARCH: amd64}
- {os: ubuntu-latest, CGO_ENABLED: "1", GOOS: netbsd, GOARCH: amd64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: openbsd, GOARCH: 386}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: openbsd, GOARCH: amd64}
# - {os: ubuntu-latest, CGO_ENABLED: "1", GOOS: openbsd, GOARCH: amd64} # FIXME
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: plan9, GOARCH: amd64}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: plan9, GOARCH: 386}
- {os: ubuntu-latest, CGO_ENABLED: "0", GOOS: solaris, GOARCH: amd64}
- {os: windows-latest, CGO_ENABLED: "0", GOOS: windows, GOARCH: amd64}
- {os: windows-latest, CGO_ENABLED: "0", GOOS: windows, GOARCH: 386}
permissions:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
name: lint
runs-on: ${{ matrix.os }}
env:
CGO_ENABLED: "${{ matrix.CGO_ENABLED }}"
GOARCH: ${{ matrix.GOARCH }}
GOOS: ${{ matrix.GOOS }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version-file: go.mod
go-version: 1.17
cache: false
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup golangci-lint
uses: golangci/golangci-lint-action@4696ba8babb6127d732c3c6dde519db15edab9ea # v6.5.1
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
with:
args: --verbose
version: latest

@ -1,9 +1,8 @@
name: Release
on:
schedule:
- cron: '0 1 1 * *' # UTC 01:00 on the first day of the Month
- cron: '0 1 1 * *' # UTC 01:00 on the first day of the Month
name: Release
permissions:
contents: write

@ -2,8 +2,8 @@ name: SBOM Generator
on:
push:
branches:
- master
branches: [ "master" ]
workflow_dispatch:
permissions: read-all
@ -11,13 +11,15 @@ permissions: read-all
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: advanced-security/sbom-generator-action@6fe43abf522b2e7a19bc769aec1e6c848614b517 # v0.0.2
- uses: advanced-security/sbom-generator-action@375dee8e6144d9fd0ec1f5667b4f6fb4faacefed # v0.0.1
id: sbom
env:
GITHUB_TOKEN: ${{ github.token }}
- uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
- uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
path: ${{steps.sbom.outputs.fileName }}
name: "SBOM"

@ -1,15 +1,5 @@
on: [push, pull_request]
name: Shellcheck
on:
push:
branches:
- master
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
@ -18,6 +8,6 @@ jobs:
name: Shellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0

@ -1,15 +1,5 @@
on: [push, pull_request]
name: Test
on:
push:
branches:
- master
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
@ -22,7 +12,7 @@ jobs:
- id: versions
run: |
versions=$(curl -s 'https://go.dev/dl/?mode=json' | jq -c 'map(.version[2:])')
echo "value=${versions}" >> $GITHUB_OUTPUT
echo "::set-output name=value::${versions}"
test:
needs: go-versions
strategy:
@ -32,12 +22,24 @@ jobs:
os: [ubuntu-22.04, ubuntu-20.04, ubuntu-24.04, windows-2022, windows-2019, macos-13, macos-14, macos-15]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version: ${{ matrix.go-version }}
- name: Test
run: |
go test -coverprofile='coverage.out' -covermode=atomic ./...
- name: Install Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- id: go-env
run: |
echo "::set-output name=cache::$(go env GOCACHE)"
echo "::set-output name=mod-cache::$(go env GOMODCACHE)"
- name: Cache go modules
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: |
${{ steps.go-env.outputs.cache }}
${{ steps.go-env.outputs.mod-cache }}
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: Test
run: |
go test -coverprofile='coverage.out' -covermode=atomic ./...

@ -1,6 +1,21 @@
issues:
max-same-issues: 0
exclude-rules: []
exclude-rules:
- linters:
- gosec
text: G115
- linters:
- revive
text: var-naming
- linters:
- revive
text: exported
- linters:
- revive
text: empty-block
- linters:
- revive
text: unused-parameter
linters:
enable:
- asciicheck
@ -22,10 +37,8 @@ linters:
- predeclared
- revive
- testifylint
- thelper
- typecheck
- unparam
- usetesting
disable:
- errcheck
- govet
@ -42,12 +55,9 @@ linters-settings:
blocked:
modules:
- io/ioutil:
recommendations:
recommandations:
- io
- os
gosec:
excludes:
- G115
perfsprint:
# Optimizes even if it requires an int or uint type cast.
int-conversion: true
@ -59,68 +69,5 @@ linters-settings:
sprintf1: true
# Optimizes into strings concatenation.
strconcat: true
revive:
rules:
- name: blank-imports
- name: context-as-argument
arguments:
- allowTypesBefore: "*testing.T"
- name: context-keys-type
- name: dot-imports
- name: duplicated-imports
- name: early-return
arguments:
- "preserveScope"
- name: empty-block
disabled: true
- name: error-naming
- name: error-return
- name: error-strings
- name: exported
disabled: true
- name: errorf
- name: increment-decrement
- name: indent-error-flow
arguments:
- "preserveScope"
- name: range
- name: receiver-naming
- name: redefines-builtin-id
- name: redundant-import-alias
- name: superfluous-else
arguments:
- "preserveScope"
- name: time-naming
- name: unexported-return
- name: unnecessary-stmt
- name: unreachable-code
- name: unused-parameter
disabled: true
- name: use-any
- name: var-declaration
- name: var-naming
disabled: true
testifylint:
enable-all: true
thelper:
test:
# Check t.Helper() begins helper function.
# Default: true
begin: false
benchmark:
# Check b.Helper() begins helper function.
# Default: true
begin: false
tb:
# Check tb.Helper() begins helper function.
# Default: true
begin: false
fuzz:
# Check f.Helper() begins helper function.
# Default: true
begin: false
usetesting:
os-create-temp: false
os-mkdir-temp: false
run:
timeout: 5m

@ -34,7 +34,6 @@ build_test: ## test only buildable
GOOS=netbsd go test ./... | $(BUILD_FAIL_PATTERN)
GOOS=openbsd go test ./... | $(BUILD_FAIL_PATTERN)
GOOS=plan9 go test ./... | $(BUILD_FAIL_PATTERN)
CGO_ENABLED=0 GOOS=aix GOARCH=ppc64 go test ./... | $(BUILD_FAIL_PATTERN)
ifeq ($(shell uname -s), Darwin)
CGO_ENABLED=1 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN)
@ -78,8 +77,6 @@ vet:
GOOS=plan9 GOARCH=amd64 go vet ./...
GOOS=plan9 GOARCH=386 go vet ./...
CGO_ENABLED=0 GOOS=aix GOARCH=ppc64 go vet ./...
macos_test:
CGO_ENABLED=0 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN)
CGO_ENABLED=1 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN)

@ -260,7 +260,7 @@ Some code is ported from Ohai. Many thanks.
|children |x |x |x |x |x |
|connections |x | |x |x | |
|is\_running | | | | | |
|page\_faults |x | | | |x |
|page\_faults |x | | | | |
### gopsutil Original Metrics

@ -148,7 +148,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
return []InfoStat{ret}, nil
}
func CountsWithContext(ctx context.Context, _ bool) (int, error) {
func CountsWithContext(ctx context.Context, logical bool) (int, error) {
info, err := InfoWithContext(ctx)
if err == nil {
return int(info[0].Cores), nil

@ -11,10 +11,9 @@ import (
"strings"
"unsafe"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/tklauser/go-sysconf"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v4/internal/common"
)
var (
@ -136,7 +135,7 @@ func parseDmesgBoot(fileName string) (InfoStat, error) {
c.VendorID = matches[1]
t, err := strconv.ParseInt(matches[2], 10, 32)
if err != nil {
return c, fmt.Errorf("unable to parse DragonflyBSD CPU stepping information from %q: %w", line, err)
return c, fmt.Errorf("unable to parse DragonflyBSD CPU stepping information from %q: %v", line, err)
}
c.Stepping = int32(t)
} else if matches := featuresMatch.FindStringSubmatch(line); matches != nil {

@ -57,7 +57,7 @@ func TimesWithContext(ctx context.Context, percpu bool) (ret []TimesStat, err er
ncpu, err := unix.SysctlUint32("hw.ncpu")
if err != nil {
return //nolint:nakedret //FIXME
return
}
var i uint32

@ -9,10 +9,9 @@ import (
"runtime"
"unsafe"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/tklauser/go-sysconf"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v4/internal/common"
)
const (
@ -75,7 +74,7 @@ func TimesWithContext(ctx context.Context, percpu bool) (ret []TimesStat, err er
ncpu, err := unix.SysctlUint32("hw.ncpu")
if err != nil {
return //nolint:nakedret //FIXME
return
}
var i uint32

@ -9,7 +9,6 @@ import (
"runtime"
stats "github.com/lufia/plan9stats"
"github.com/shirou/gopsutil/v4/internal/common"
)

@ -42,7 +42,7 @@ var kstatSplit = regexp.MustCompile(`[:\s]+`)
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-p", "cpu_stat:*:*:/^idle$|^user$|^kernel$|^iowait$|^swap$/")
if err != nil {
return nil, fmt.Errorf("cannot execute kstat: %w", err)
return nil, fmt.Errorf("cannot execute kstat: %s", err)
}
cpu := make(map[float64]float64)
idle := make(map[float64]float64)
@ -57,29 +57,29 @@ func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
}
cpuNumber, err := strconv.ParseFloat(fields[1], 64)
if err != nil {
return nil, fmt.Errorf("cannot parse cpu number: %w", err)
return nil, fmt.Errorf("cannot parse cpu number: %s", err)
}
cpu[cpuNumber] = cpuNumber
switch fields[3] {
case "idle":
idle[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
if err != nil {
return nil, fmt.Errorf("cannot parse idle: %w", err)
return nil, fmt.Errorf("cannot parse idle: %s", err)
}
case "user":
user[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
if err != nil {
return nil, fmt.Errorf("cannot parse user: %w", err)
return nil, fmt.Errorf("cannot parse user: %s", err)
}
case "kernel":
kern[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
if err != nil {
return nil, fmt.Errorf("cannot parse kernel: %w", err)
return nil, fmt.Errorf("cannot parse kernel: %s", err)
}
case "iowait":
iowt[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
if err != nil {
return nil, fmt.Errorf("cannot parse iowait: %w", err)
return nil, fmt.Errorf("cannot parse iowait: %s", err)
}
//not sure how this translates, don't report, add to kernel, something else?
/*case "swap":
@ -121,22 +121,22 @@ func Info() ([]InfoStat, error) {
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
psrInfoOut, err := invoke.CommandWithContext(ctx, "psrinfo", "-p", "-v")
if err != nil {
return nil, fmt.Errorf("cannot execute psrinfo: %w", err)
return nil, fmt.Errorf("cannot execute psrinfo: %s", err)
}
procs, err := parseProcessorInfo(string(psrInfoOut))
if err != nil {
return nil, fmt.Errorf("error parsing psrinfo output: %w", err)
return nil, fmt.Errorf("error parsing psrinfo output: %s", err)
}
isaInfoOut, err := invoke.CommandWithContext(ctx, "isainfo", "-b", "-v")
if err != nil {
return nil, fmt.Errorf("cannot execute isainfo: %w", err)
return nil, fmt.Errorf("cannot execute isainfo: %s", err)
}
flags, err := parseISAInfo(string(isaInfoOut))
if err != nil {
return nil, fmt.Errorf("error parsing isainfo output: %w", err)
return nil, fmt.Errorf("error parsing isainfo output: %s", err)
}
result := make([]InfoStat, 0, len(flags))
@ -160,7 +160,7 @@ func parseISAInfo(cmdOutput string) ([]string, error) {
}
flags := make([]string, len(words)-4)
for i, val := range words[4:] { //nolint:gosimple //FIXME
for i, val := range words[4:] {
flags[i] = val
}
sort.Strings(flags)
@ -194,7 +194,7 @@ func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {
if physicalCPU[psrStepOffset] != "" {
stepParsed, err := strconv.ParseInt(physicalCPU[psrStepOffset], 10, 32)
if err != nil {
return nil, fmt.Errorf("cannot parse value %q for step as 32-bit integer: %w", physicalCPU[9], err)
return nil, fmt.Errorf("cannot parse value %q for step as 32-bit integer: %s", physicalCPU[9], err)
}
step = int32(stepParsed)
}
@ -202,7 +202,7 @@ func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {
if physicalCPU[psrClockOffset] != "" {
clockParsed, err := strconv.ParseInt(physicalCPU[psrClockOffset], 10, 64)
if err != nil {
return nil, fmt.Errorf("cannot parse value %q for clock as 32-bit integer: %w", physicalCPU[10], err)
return nil, fmt.Errorf("cannot parse value %q for clock as 32-bit integer: %s", physicalCPU[10], err)
}
clock = float64(clockParsed)
}
@ -214,7 +214,7 @@ func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {
case physicalCPU[psrNumCoresOffset] != "":
numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresOffset], 10, 32)
if err != nil {
return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %w", physicalCPU[1], err)
return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[1], err)
}
for i := 0; i < int(numCores); i++ {
@ -235,12 +235,12 @@ func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {
case physicalCPU[psrNumCoresHTOffset] != "":
numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresHTOffset], 10, 32)
if err != nil {
return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %w", physicalCPU[3], err)
return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[3], err)
}
numHT, err = strconv.ParseInt(physicalCPU[psrNumHTOffset], 10, 32)
if err != nil {
return nil, fmt.Errorf("cannot parse value %q for hyperthread count as 32-bit integer: %w", physicalCPU[4], err)
return nil, fmt.Errorf("cannot parse value %q for hyperthread count as 32-bit integer: %s", physicalCPU[4], err)
}
for i := 0; i < int(numCores); i++ {

@ -6,13 +6,11 @@ package cpu
import (
"context"
"fmt"
"strconv"
"unsafe"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/internal/common"
)
var procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
@ -112,7 +110,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
cpu := InfoStat{
CPU: int32(i),
Family: strconv.FormatUint(uint64(l.Family), 10),
Family: fmt.Sprintf("%d", l.Family),
VendorID: l.Manufacturer,
ModelName: l.Name,
Cores: int32(l.NumberOfLogicalProcessors),

@ -11,11 +11,11 @@ import (
"github.com/shirou/gopsutil/v4/internal/common"
)
func IOCountersWithContext(_ context.Context, _ ...string) (map[string]IOCountersStat, error) {
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func LabelWithContext(_ context.Context, _ string) (string, error) {
func LabelWithContext(ctx context.Context, name string) (string, error) {
return "", common.ErrNotImplementedError
}

@ -9,9 +9,8 @@ import (
"strconv"
"strings"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/unix"
)
var startBlank = regexp.MustCompile(`^\s+`)
@ -26,7 +25,7 @@ var (
}
)
func PartitionsWithContext(ctx context.Context, _ bool) ([]PartitionStat, error) {
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
var ret []PartitionStat
out, err := invoke.CommandWithContext(ctx, "mount")

@ -222,7 +222,7 @@ func (i *ioCounters) getDriveStat(d uint32) (*IOCountersStat, error) {
defer i.ioObjectRelease(parent)
if !ioObjectConformsTo(parent, "IOBlockStorageDriver") {
// return nil, fmt.Errorf("ERROR: the object is not of the IOBlockStorageDriver class")
//return nil, fmt.Errorf("ERROR: the object is not of the IOBlockStorageDriver class")
return nil, nil
}

@ -8,9 +8,8 @@ import (
"context"
"encoding/binary"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/unix"
)
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {

@ -7,7 +7,6 @@ import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"math"
"os"
@ -17,9 +16,8 @@ import (
"strconv"
"strings"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/unix"
)
const (
@ -102,7 +100,7 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC
}
lines := strings.Split(strings.TrimSpace(string(kstatSysOut)), "\n")
if len(lines) == 0 {
return nil, errors.New("no disk class found")
return nil, fmt.Errorf("no disk class found")
}
dnamearr := make(map[string]string)
nreadarr := make(map[string]uint64)

@ -6,14 +6,13 @@ package disk
import (
"bytes"
"context"
"errors"
"fmt"
"syscall"
"unsafe"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
"github.com/shirou/gopsutil/v4/internal/common"
)
var (
@ -203,11 +202,11 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC
if typeret != windows.DRIVE_FIXED {
continue
}
szDevice := `\\.\` + path
szDevice := fmt.Sprintf(`\\.\%s`, path)
const IOCTL_DISK_PERFORMANCE = 0x70020
h, err := windows.CreateFile(syscall.StringToUTF16Ptr(szDevice), 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0)
if err != nil {
if errors.Is(err, windows.ERROR_FILE_NOT_FOUND) {
if err == windows.ERROR_FILE_NOT_FOUND {
continue
}
return drivemap, err

@ -13,7 +13,7 @@ import (
"strconv"
"strings"
"github.com/shirou/gopsutil/v4/cpu"
cpu "github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/internal/common"
)

@ -1,10 +1,10 @@
module github.com/shirou/gopsutil/v4
go 1.23
go 1.18
require (
github.com/ebitengine/purego v0.8.2
github.com/google/go-cmp v0.7.0
github.com/ebitengine/purego v0.8.1
github.com/google/go-cmp v0.6.0
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c
github.com/stretchr/testify v1.10.0

@ -1,12 +1,12 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

@ -27,7 +27,7 @@ func HostIDWithContext(ctx context.Context) (string, error) {
return strings.Split(string(out[:]), "\n")[0], nil
}
func numProcs(_ context.Context) (uint64, error) {
func numProcs(ctx context.Context) (uint64, error) {
return 0, common.ErrNotImplementedError
}
@ -38,7 +38,7 @@ func BootTimeWithContext(ctx context.Context) (btime uint64, err error) {
}
if ut <= 0 {
return 0, errors.New("uptime was not set, so cannot calculate boot time from it")
return 0, errors.New("Uptime was not set, so cannot calculate boot time from it.")
}
ut = ut * 60
@ -110,7 +110,7 @@ func parseUptime(uptime string) uint64 {
if err != nil {
return 0
}
case ut[3] == "min," || ut[3] == "mins,":
case ut[3] == "mins," || ut[3] == "mins,":
mins, err = strconv.ParseUint(ut[2], 10, 64)
if err != nil {
return 0
@ -201,6 +201,6 @@ func KernelArch() (arch string, err error) {
return arch, nil
}
func VirtualizationWithContext(_ context.Context) (string, string, error) {
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
return "", "", common.ErrNotImplementedError
}

@ -12,10 +12,9 @@ import (
"strings"
"unsafe"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/shirou/gopsutil/v4/process"
"golang.org/x/sys/unix"
)
const (

@ -7,7 +7,6 @@ import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"os"
"regexp"
@ -32,13 +31,14 @@ func HostIDWithContext(ctx context.Context) (string, error) {
line := sc.Text()
// If we're in the global zone, rely on the hostname.
if line != "global" {
if line == "global" {
hostname, err := os.Hostname()
if err == nil {
return hostname, nil
}
} else {
return strings.TrimSpace(line), nil
}
hostname, err := os.Hostname()
if err == nil {
return hostname, nil
}
}
}
}
@ -84,7 +84,7 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) {
}
func UptimeWithContext(ctx context.Context) (uint64, error) {
bootTime, err := BootTime() //nolint:contextcheck //FIXME
bootTime, err := BootTime()
if err != nil {
return 0, err
}
@ -139,7 +139,7 @@ func parseUnameOutput(ctx context.Context) (string, string, string, error) {
fields := strings.Fields(string(out))
if len(fields) < 3 {
return "", "", "", errors.New("malformed `uname` output")
return "", "", "", fmt.Errorf("malformed `uname` output")
}
return fields[0], fields[1], fields[2], nil

@ -13,10 +13,9 @@ import (
"time"
"unsafe"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/shirou/gopsutil/v4/process"
"golang.org/x/sys/windows"
)
var (
@ -80,7 +79,7 @@ func HostIDWithContext(ctx context.Context) (string, error) {
hostID := windows.UTF16ToString(regBuf[:])
hostIDLen := len(hostID)
if hostIDLen != uuidLen {
return "", fmt.Errorf("HostID incorrect: %q\n", hostID) //nolint:revive //FIXME
return "", fmt.Errorf("HostID incorrect: %q\n", hostID)
}
return strings.ToLower(hostID), nil
@ -136,15 +135,15 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) {
return t, nil
}
func PlatformInformationWithContext(_ context.Context) (platform string, family string, version string, err error) {
platform, family, _, displayVersion, err := platformInformation()
func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) {
platform, family, _, displayVersion, err := platformInformation(ctx)
if err != nil {
return "", "", "", err
}
return platform, family, displayVersion, nil
}
func platformInformation() (platform, family, version, displayVersion string, err error) {
func platformInformation(ctx context.Context) (platform, family, version, displayVersion string, err error) {
// GetVersionEx lies on Windows 8.1 and returns as Windows 8 if we don't declare compatibility in manifest
// RtlGetVersion bypasses this lying layer and returns the true Windows version
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-rtlgetversion
@ -153,26 +152,26 @@ func platformInformation() (platform, family, version, displayVersion string, er
osInfo.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osInfo))
ret, _, err := procRtlGetVersion.Call(uintptr(unsafe.Pointer(&osInfo)))
if ret != 0 {
return //nolint:nakedret //FIXME
return
}
// Platform
var h windows.Handle // like HostIDWithContext(), we query the registry using the raw windows.RegOpenKeyEx/RegQueryValueEx
err = windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Windows NT\CurrentVersion`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h)
if err != nil {
return //nolint:nakedret //FIXME
return
}
defer windows.RegCloseKey(h)
var bufLen uint32
var valType uint32
err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`ProductName`), nil, &valType, nil, &bufLen)
if err != nil {
return //nolint:nakedret //FIXME
return
}
regBuf := make([]uint16, bufLen/2+1)
err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`ProductName`), nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)
if err != nil {
return //nolint:nakedret //FIXME
return
}
platform = windows.UTF16ToString(regBuf[:])
if strings.Contains(platform, "Windows 10") { // check build number to determine whether it's actually Windows 11
@ -244,8 +243,8 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) {
return "", "", common.ErrNotImplementedError
}
func KernelVersionWithContext(_ context.Context) (string, error) {
_, _, version, _, err := platformInformation()
func KernelVersionWithContext(ctx context.Context) (string, error) {
_, _, version, _, err := platformInformation(ctx)
return version, err
}

@ -137,7 +137,7 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
// When reading into a struct, all non-blank fields must be exported.
func Read(r io.Reader, order ByteOrder, data any) error {
func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Fast path for basic types and slices.
if n := intDataSize(data); n != 0 {
var b [8]byte
@ -229,7 +229,7 @@ func Read(r io.Reader, order ByteOrder, data any) error {
// and read from successive fields of the data.
// When writing structs, zero values are written for fields
// with blank (_) field names.
func Write(w io.Writer, order ByteOrder, data any) error {
func Write(w io.Writer, order ByteOrder, data interface{}) error {
// Fast path for basic types and slices.
if n := intDataSize(data); n != 0 {
var b [8]byte
@ -339,7 +339,7 @@ func Write(w io.Writer, order ByteOrder, data any) error {
// Size returns how many bytes Write would generate to encode the value v, which
// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
// If v is neither of these, Size returns -1.
func Size(v any) int {
func Size(v interface{}) int {
return dataSize(reflect.Indirect(reflect.ValueOf(v)))
}
@ -607,7 +607,7 @@ func (e *encoder) skip(v reflect.Value) {
// intDataSize returns the size of the data required to represent the data when encoded.
// It returns zero if the type cannot be implemented by the fast path in Read or Write.
func intDataSize(data any) int {
func intDataSize(data interface{}) int {
switch data := data.(type) {
case int8, *int8, *uint8:
return 1

@ -311,7 +311,7 @@ func IntContains(target []int, src int) bool {
// get struct attributes.
// This method is used only for debugging platform dependent code.
func attributes(m any) map[string]reflect.Type {
func attributes(m interface{}) map[string]reflect.Type {
typ := reflect.TypeOf(m)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()

@ -5,7 +5,6 @@ package common
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
@ -307,7 +306,7 @@ const (
func NewSMC(ioKit *Library) (*SMC, error) {
if ioKit.path != IOKit {
return nil, errors.New("library is not IOKit")
return nil, fmt.Errorf("library is not IOKit")
}
ioServiceGetMatchingService := GetFunc[IOServiceGetMatchingServiceFunc](ioKit, IOServiceGetMatchingServiceSym)
@ -325,7 +324,7 @@ func NewSMC(ioKit *Library) (*SMC, error) {
var conn uint32
if result := ioServiceOpen(service, machTaskSelf(), 0, &conn); result != 0 {
return nil, errors.New("ERROR: IOServiceOpen failed")
return nil, fmt.Errorf("ERROR: IOServiceOpen failed")
}
ioObjectRelease(service)
@ -344,7 +343,7 @@ func (s *SMC) Close() error {
ioServiceClose := GetFunc[IOServiceCloseFunc](s.lib, IOServiceCloseSym)
if result := ioServiceClose(s.conn); result != 0 {
return errors.New("ERROR: IOServiceClose failed")
return fmt.Errorf("ERROR: IOServiceClose failed")
}
return nil
}
@ -368,8 +367,8 @@ func (s CStr) Ptr() *byte {
return &s[0]
}
func (s CStr) Addr() uintptr {
return uintptr(unsafe.Pointer(s.Ptr()))
func (c CStr) Addr() uintptr {
return uintptr(unsafe.Pointer(c.Ptr()))
}
func (s CStr) GoString() string {

@ -197,7 +197,7 @@ func ProcessorQueueLengthCounter() (*Win32PerformanceCounter, error) {
}
// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
func WMIQueryWithContext(ctx context.Context, query string, dst any, connectServerArgs ...any) error {
func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
if _, ok := ctx.Deadline(); !ok {
ctxTimeout, cancel := context.WithTimeout(ctx, Timeout)
defer cancel()
@ -273,19 +273,19 @@ type SystemExtendedHandleInformation struct {
// CallWithExpandingBuffer https://github.com/hillu/go-ntdll
func CallWithExpandingBuffer(fn func() NtStatus, buf *[]byte, resultLength *uint32) NtStatus {
for {
st := fn()
if st == STATUS_BUFFER_OVERFLOW || st == STATUS_BUFFER_TOO_SMALL || st == STATUS_INFO_LENGTH_MISMATCH {
if st := fn(); st == STATUS_BUFFER_OVERFLOW || st == STATUS_BUFFER_TOO_SMALL || st == STATUS_INFO_LENGTH_MISMATCH {
if int(*resultLength) <= cap(*buf) {
(*reflect.SliceHeader)(unsafe.Pointer(buf)).Len = int(*resultLength)
} else {
*buf = make([]byte, int(*resultLength))
}
continue
} else {
if !st.IsError() {
*buf = (*buf)[:int(*resultLength)]
}
return st
}
if !st.IsError() {
*buf = (*buf)[:int(*resultLength)]
}
return st
}
}

@ -9,9 +9,9 @@ import (
"github.com/shirou/gopsutil/v4/internal/common"
)
func skipIfNotImplementedErr(tb testing.TB, err error) {
func skipIfNotImplementedErr(t testing.TB, err error) {
if errors.Is(err, common.ErrNotImplementedError) {
tb.Skip("not implemented")
t.Skip("not implemented")
}
}
@ -72,15 +72,15 @@ func TestMiscStatString(t *testing.T) {
}
func BenchmarkLoad(b *testing.B) {
loadAvg := func(tb testing.TB) {
loadAvg := func(t testing.TB) {
v, err := Avg()
skipIfNotImplementedErr(tb, err)
skipIfNotImplementedErr(t, err)
if err != nil {
tb.Errorf("error %v", err)
t.Errorf("error %v", err)
}
empty := &AvgStat{}
if v == empty {
tb.Errorf("error load: %v", v)
t.Errorf("error load: %v", v)
}
}

@ -14,9 +14,9 @@ import (
var (
loadErr error
loadAvg1M = 0.0
loadAvg5M = 0.0
loadAvg15M = 0.0
loadAvg1M float64 = 0.0
loadAvg5M float64 = 0.0
loadAvg15M float64 = 0.0
loadAvgMutex sync.RWMutex
loadAvgGoroutineOnce sync.Once
)
@ -27,10 +27,10 @@ var (
// code https://github.com/giampaolo/psutil/blob/8415355c8badc9c94418b19bdf26e622f06f0cce/psutil/arch/windows/wmi.c
func loadAvgGoroutine(ctx context.Context) {
var (
samplingFrequency = 5 * time.Second
loadAvgFactor1M = 1 / math.Exp(samplingFrequency.Seconds()/time.Minute.Seconds())
loadAvgFactor5M = 1 / math.Exp(samplingFrequency.Seconds()/(5*time.Minute).Seconds())
loadAvgFactor15M = 1 / math.Exp(samplingFrequency.Seconds()/(15*time.Minute).Seconds())
samplingFrequency time.Duration = 5 * time.Second
loadAvgFactor1M float64 = 1 / math.Exp(samplingFrequency.Seconds()/time.Minute.Seconds())
loadAvgFactor5M float64 = 1 / math.Exp(samplingFrequency.Seconds()/(5*time.Minute).Seconds())
loadAvgFactor15M float64 = 1 / math.Exp(samplingFrequency.Seconds()/(15*time.Minute).Seconds())
currentLoad float64
)

@ -7,7 +7,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const validFreeBSD = `Device: 1kB-blocks Used:
@ -25,31 +24,33 @@ const invalid = `Device: 512-blocks Used:
`
func TestParseSwapctlOutput_FreeBSD(t *testing.T) {
assert := assert.New(t)
stats, err := parseSwapctlOutput(validFreeBSD)
require.NoError(t, err)
assert.NoError(err)
assert.Equal(t, SwapDevice{
assert.Equal(*stats[0], SwapDevice{
Name: "/dev/gpt/swapfs",
UsedBytes: 1263616,
FreeBytes: 1072478208,
}, *stats[0])
})
assert.Equal(t, SwapDevice{
assert.Equal(*stats[1], SwapDevice{
Name: "/dev/md0",
UsedBytes: 681984,
FreeBytes: 1073059840,
}, *stats[1])
})
}
func TestParseSwapctlOutput_OpenBSD(t *testing.T) {
assert := assert.New(t)
stats, err := parseSwapctlOutput(validOpenBSD)
require.NoError(t, err)
assert.NoError(err)
assert.Equal(t, SwapDevice{
assert.Equal(*stats[0], SwapDevice{
Name: "/dev/wd0b",
UsedBytes: 1234 * 1024,
FreeBytes: 653791 * 1024,
}, *stats[0])
})
}
func TestParseSwapctlOutput_Invalid(t *testing.T) {

@ -9,40 +9,39 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestVirtualMemoryDarwin(t *testing.T) {
v, err := VirtualMemory()
require.NoError(t, err)
assert.Nil(t, err)
outBytes, err := invoke.Command("/usr/sbin/sysctl", "hw.memsize")
require.NoError(t, err)
assert.Nil(t, err)
outString := string(outBytes)
outString = strings.TrimSpace(outString)
outParts := strings.Split(outString, " ")
actualTotal, err := strconv.ParseInt(outParts[1], 10, 64)
require.NoError(t, err)
assert.Nil(t, err)
assert.Equal(t, uint64(actualTotal), v.Total)
assert.Positive(t, v.Available)
assert.True(t, v.Available > 0)
assert.Equal(t, v.Available, v.Free+v.Inactive, "%v", v)
assert.Positive(t, v.Used)
assert.Less(t, v.Used, v.Total)
assert.True(t, v.Used > 0)
assert.True(t, v.Used < v.Total)
assert.Positive(t, v.UsedPercent)
assert.Less(t, v.UsedPercent, 100.0)
assert.True(t, v.UsedPercent > 0)
assert.True(t, v.UsedPercent < 100)
assert.Positive(t, v.Free)
assert.Less(t, v.Free, v.Available)
assert.True(t, v.Free > 0)
assert.True(t, v.Free < v.Available)
assert.Positive(t, v.Active)
assert.Less(t, v.Active, v.Total)
assert.True(t, v.Active > 0)
assert.True(t, v.Active < v.Total)
assert.Positive(t, v.Inactive)
assert.Less(t, v.Inactive, v.Total)
assert.True(t, v.Inactive > 0)
assert.True(t, v.Inactive < v.Total)
assert.Positive(t, v.Wired)
assert.Less(t, v.Wired, v.Total)
assert.True(t, v.Wired > 0)
assert.True(t, v.Wired < v.Total)
}

@ -151,16 +151,17 @@ const invalidFile = `INVALID Type Size Used Priority
`
func TestParseSwapsFile_ValidFile(t *testing.T) {
assert := assert.New(t)
stats, err := parseSwapsFile(context.Background(), strings.NewReader(validFile))
require.NoError(t, err)
assert.Equal(t, SwapDevice{
assert.Equal(SwapDevice{
Name: "/dev/dm-2",
UsedBytes: 502566912,
FreeBytes: 68128825344,
}, *stats[0])
assert.Equal(t, SwapDevice{
assert.Equal(SwapDevice{
Name: "/swapfile",
UsedBytes: 1024,
FreeBytes: 1024,

@ -10,9 +10,8 @@ import (
"errors"
"fmt"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/unix"
)
func GetPageSize() (uint64, error) {

@ -8,7 +8,6 @@ import (
"os"
stats "github.com/lufia/plan9stats"
"github.com/shirou/gopsutil/v4/internal/common"
)

@ -11,9 +11,8 @@ import (
"strconv"
"strings"
"github.com/tklauser/go-sysconf"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/tklauser/go-sysconf"
)
// VirtualMemory for Solaris is a minimal implementation which only returns
@ -25,17 +24,17 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
result := &VirtualMemoryStat{}
zoneName, err := zoneName() //nolint:contextcheck //FIXME
zoneName, err := zoneName()
if err != nil {
return nil, err
}
if zoneName == "global" {
capacity, err := globalZoneMemoryCapacity() //nolint:contextcheck //FIXME
cap, err := globalZoneMemoryCapacity()
if err != nil {
return nil, err
}
result.Total = capacity
result.Total = cap
freemem, err := globalZoneFreeMemory(ctx)
if err != nil {
return nil, err
@ -44,11 +43,11 @@ func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
result.Free = freemem
result.Used = result.Total - result.Free
} else {
capacity, err := nonGlobalZoneMemoryCapacity() //nolint:contextcheck //FIXME
cap, err := nonGlobalZoneMemoryCapacity()
if err != nil {
return nil, err
}
result.Total = capacity
result.Total = cap
}
return result, nil

@ -7,7 +7,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const validFile = `swapfile dev swaplo blocks free
@ -19,20 +18,21 @@ const invalidFile = `swapfile dev swaplo INVALID free
/dev/dsk/c0t0d0s1 136,1 16 1638608 1600528`
func TestParseSwapsCommandOutput_Valid(t *testing.T) {
assert := assert.New(t)
stats, err := parseSwapsCommandOutput(validFile)
require.NoError(t, err)
assert.NoError(err)
assert.Equal(t, SwapDevice{
assert.Equal(*stats[0], SwapDevice{
Name: "/dev/zvol/dsk/rpool/swap",
UsedBytes: 0,
FreeBytes: 1058800 * 512,
}, *stats[0])
})
assert.Equal(t, SwapDevice{
assert.Equal(*stats[1], SwapDevice{
Name: "/dev/dsk/c0t0d0s1",
UsedBytes: 38080 * 512,
FreeBytes: 1600528 * 512,
}, *stats[1])
})
}
func TestParseSwapsCommandOutput_Invalid(t *testing.T) {

@ -9,9 +9,8 @@ import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/windows"
)
var (

@ -255,7 +255,7 @@ func InterfacesWithContext(ctx context.Context) (InterfaceStatList, error) {
return ret, nil
}
func getIOCountersAll(n []IOCountersStat) []IOCountersStat {
func getIOCountersAll(n []IOCountersStat) ([]IOCountersStat, error) {
r := IOCountersStat{
Name: "all",
}
@ -270,7 +270,7 @@ func getIOCountersAll(n []IOCountersStat) []IOCountersStat {
r.Dropout += nic.Dropout
}
return []IOCountersStat{r}
return []IOCountersStat{r}, nil
}
// NetIOCounters returns network I/O statistics for every network

@ -15,23 +15,23 @@ import (
)
// Deprecated: use process.PidsWithContext instead
func PidsWithContext(_ context.Context) ([]int32, error) {
func PidsWithContext(ctx context.Context) ([]int32, error) {
return nil, common.ErrNotImplementedError
}
func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
return IOCountersWithContext(ctx, pernic)
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
return IOCounters(pernic)
}
func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
return nil, common.ErrNotImplementedError
}
func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
return nil, common.ErrNotImplementedError
}
func ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {
func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
return nil, common.ErrNotImplementedError
}
@ -202,7 +202,7 @@ func parseNetstatA(output string, kind string) ([]ConnectionStat, error) {
c, err := parseNetstatUnixLine(fields)
if err != nil {
return nil, fmt.Errorf("failed to parse Unix Address (%s): %w", line, err)
return nil, fmt.Errorf("failed to parse Unix Address (%s): %s", line, err)
}
ret = append(ret, c)
@ -221,7 +221,7 @@ func parseNetstatA(output string, kind string) ([]ConnectionStat, error) {
c, err := parseNetstatNetLine(line)
if err != nil {
return nil, fmt.Errorf("failed to parse Inet Address (%s): %w", line, err)
return nil, fmt.Errorf("failed to parse Inet Address (%s): %s", line, err)
}
ret = append(ret, c)
@ -294,6 +294,6 @@ func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, p
return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
}
func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {
func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int, skipUids bool) ([]ConnectionStat, error) {
return []ConnectionStat{}, common.ErrNotImplementedError
}

@ -29,8 +29,8 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
}
iocounters = append(iocounters, n)
}
if !pernic {
return getIOCountersAll(iocounters), nil
if pernic == false {
return getIOCountersAll(iocounters)
}
return iocounters, nil
}

@ -5,7 +5,7 @@ package net
import (
"context"
"errors"
"fmt"
"strconv"
"strings"
@ -19,7 +19,7 @@ func parseNetstatI(output string) ([]IOCountersStat, error) {
// Check first line is header
if len(lines) > 0 && strings.Fields(lines[0])[0] != "Name" {
return nil, errors.New("not a 'netstat -i' output")
return nil, fmt.Errorf("not a 'netstat -i' output")
}
for _, line := range lines[1:] {
@ -88,8 +88,8 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
if err != nil {
return nil, err
}
if !pernic {
return getIOCountersAll(iocounters), nil
if pernic == false {
return getIOCountersAll(iocounters)
}
return iocounters, nil
}

@ -30,14 +30,14 @@ func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err erro
if columns[0] == "Name" {
err = errNetstatHeader
return //nolint:nakedret //FIXME
return
}
// try to extract the numeric value from <Link#123>
if subMatch := netstatLinkRegexp.FindStringSubmatch(columns[2]); len(subMatch) == 2 {
numericValue, err = strconv.ParseUint(subMatch[1], 10, 64)
if err != nil {
return //nolint:nakedret //FIXME
return
}
linkIDUint := uint(numericValue)
linkID = &linkIDUint
@ -51,7 +51,7 @@ func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err erro
}
if numberColumns < 11 || numberColumns > 13 {
err = fmt.Errorf("Line %q do have an invalid number of columns %d", line, numberColumns)
return //nolint:nakedret //FIXME
return
}
parsed := make([]uint64, 0, 7)
@ -74,7 +74,7 @@ func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err erro
}
if numericValue, err = strconv.ParseUint(target, 10, 64); err != nil {
return //nolint:nakedret //FIXME
return
}
parsed = append(parsed, numericValue)
}
@ -91,7 +91,7 @@ func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err erro
if len(parsed) == 7 {
stat.Dropout = parsed[6]
}
return //nolint:nakedret //FIXME
return
}
type netstatInterface struct {
@ -249,7 +249,7 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
}
if !pernic {
return getIOCountersAll(ret), nil
return getIOCountersAll(ret)
}
return ret, nil
}

@ -137,5 +137,5 @@ func TestParseNetstatTruncated(t *testing.T) {
mapUsage := newMapInterfaceNameUsage(nsInterfaces)
assert.True(t, mapUsage.isTruncated())
assert.Len(t, mapUsage.notTruncated(), 3, "en0, gif0 and stf0")
assert.Equal(t, 3, len(mapUsage.notTruncated()), "en0, gif0 and stf0")
}

@ -85,7 +85,7 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
}
if !pernic {
return getIOCountersAll(ret), nil
return getIOCountersAll(ret)
}
return ret, nil

@ -128,7 +128,7 @@ func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename stri
}
if !pernic {
return getIOCountersAll(ret), nil
return getIOCountersAll(ret)
}
return ret, nil
@ -571,7 +571,8 @@ func (p *process) fillFromStatus(ctx context.Context) error {
continue
}
value := tabParts[1]
if strings.TrimRight(tabParts[0], ":") == "Uid" {
switch strings.TrimRight(tabParts[0], ":") {
case "Uid":
p.uids = make([]int32, 0, 4)
for _, i := range strings.Split(value, "\t") {
v, err := strconv.ParseInt(i, 10, 32)

@ -138,6 +138,8 @@ type AddrTest struct {
}
func TestDecodeAddress(t *testing.T) {
assert := assert.New(t)
addr := map[string]AddrTest{
"11111:0035": {
Error: true,
@ -180,11 +182,11 @@ func TestDecodeAddress(t *testing.T) {
}
addr, err := decodeAddress(uint32(family), src)
if dst.Error {
assert.Error(t, err, src)
assert.Error(err, src)
} else {
require.NoError(t, err, src)
assert.Equal(t, dst.IP, addr.IP, src)
assert.Equal(t, dst.Port, int(addr.Port), src)
assert.Equal(dst.IP, addr.IP, src)
assert.Equal(dst.Port, int(addr.Port), src)
}
}
}

@ -150,15 +150,15 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
ret = append(ret, ioc)
}
if !pernic {
return getIOCountersAll(ret), nil
if pernic == false {
return getIOCountersAll(ret)
}
return ret, nil
}
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
return IOCounters(pernic) //nolint:contextcheck //FIXME
return IOCounters(pernic)
}
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {

@ -5,7 +5,6 @@ package net
import (
"context"
"errors"
"fmt"
"regexp"
"runtime"
@ -30,7 +29,7 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
lines := strings.Split(strings.TrimSpace(string(kstatSysOut)), "\n")
if len(lines) == 0 {
return nil, errors.New("no interface found")
return nil, fmt.Errorf("no interface found")
}
rbytes64arr := make(map[string]uint64)
ipackets64arr := make(map[string]uint64)
@ -105,7 +104,7 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
}
if !pernic {
return getIOCountersAll(ret), nil
return getIOCountersAll(ret)
}
return ret, nil

@ -133,7 +133,11 @@ func TestGetNetIOCountersAll(t *testing.T) {
Errin: 10,
},
}
ret := getIOCountersAll(n)
ret, err := getIOCountersAll(n)
skipIfNotImplementedErr(t, err)
if err != nil {
t.Error(err)
}
if len(ret) != 1 {
t.Errorf("invalid return count")
}

@ -5,16 +5,14 @@ package net
import (
"context"
"errors"
"fmt"
"net"
"os"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/windows"
)
var (
@ -193,13 +191,13 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
}
if !pernic {
return getIOCountersAll(counters), nil
return getIOCountersAll(counters)
}
return counters, nil
}
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
return IOCounters(pernic) //nolint:contextcheck //FIXME
return IOCounters(pernic)
}
func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
@ -240,7 +238,7 @@ func getProcInet(kinds []netConnectionKindType, pid int32) ([]ConnectionStat, er
func getNetStatWithKind(kindType netConnectionKindType) ([]ConnectionStat, error) {
if kindType.filename == "" {
return nil, errors.New("kind filename must be required")
return nil, fmt.Errorf("kind filename must be required")
}
switch kindType.filename {
@ -328,7 +326,7 @@ func getTableUintptr(family uint32, buf []byte) uintptr {
return p
}
func getTableInfo(filename string, table any) (index, step, length int) {
func getTableInfo(filename string, table interface{}) (index, step, length int) {
switch filename {
case kindTCP4.filename:
index = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).DwNumEntries))
@ -362,7 +360,7 @@ func getTCPConnections(family uint32) ([]ConnectionStat, error) {
)
if family == 0 {
return nil, errors.New("faimly must be required")
return nil, fmt.Errorf("faimly must be required")
}
for {
@ -392,7 +390,7 @@ func getTCPConnections(family uint32) ([]ConnectionStat, error) {
if err == nil {
break
}
if !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {
if err != windows.ERROR_INSUFFICIENT_BUFFER {
return nil, err
}
buf = make([]byte, size)
@ -443,7 +441,7 @@ func getUDPConnections(family uint32) ([]ConnectionStat, error) {
)
if family == 0 {
return nil, errors.New("faimly must be required")
return nil, fmt.Errorf("faimly must be required")
}
for {
@ -475,7 +473,7 @@ func getUDPConnections(family uint32) ([]ConnectionStat, error) {
if err == nil {
break
}
if !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {
if err != windows.ERROR_INSUFFICIENT_BUFFER {
return nil, err
}
buf = make([]byte, size)

@ -408,11 +408,6 @@ func (p *Process) Cmdline() (string, error) {
// CmdlineSlice returns the command line arguments of the process as a slice with each
// element being an argument.
//
// On Windows, this assumes the command line is encoded according to the convention accepted by
// [golang.org/x/sys/windows.CmdlineToArgv] (the most common convention). If this is not suitable,
// you should instead use [Process.Cmdline] and parse the command line according to your specific
// requirements.
func (p *Process) CmdlineSlice() ([]string, error) {
return p.CmdlineSliceWithContext(context.Background())
}

@ -7,7 +7,6 @@ import (
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
"path/filepath"
"runtime"
@ -349,7 +348,7 @@ func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
ret := procPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize)
errno, _ := lib.Dlsym("errno")
err = *(**unix.Errno)(unsafe.Pointer(&errno))
if errors.Is(err, unix.EPERM) {
if err == unix.EPERM {
return "", ErrorNotPermitted
}
@ -374,11 +373,11 @@ func procArgs(pid int32) ([]byte, int, error) {
return procargs, int(binary.LittleEndian.Uint32(nargs)), nil
}
func (p *Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {
return p.cmdlineSlice()
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
return p.cmdlineSliceWithContext(ctx, true)
}
func (p *Process) cmdlineSlice() ([]string, error) {
func (p *Process) cmdlineSliceWithContext(ctx context.Context, fallback bool) ([]string, error) {
pargs, nargs, err := procArgs(p.Pid)
if err != nil {
return nil, err
@ -409,8 +408,8 @@ func (p *Process) cmdlineSlice() ([]string, error) {
}
// cmdNameWithContext returns the command name (including spaces) without any arguments
func (p *Process) cmdNameWithContext(_ context.Context) (string, error) {
r, err := p.cmdlineSlice()
func (p *Process) cmdNameWithContext(ctx context.Context) (string, error) {
r, err := p.cmdlineSliceWithContext(ctx, false)
if err != nil {
return "", err
}

@ -8,6 +8,7 @@ import (
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"path/filepath"
"sort"
@ -15,12 +16,11 @@ import (
"strings"
"unsafe"
"golang.org/x/sys/unix"
"github.com/shirou/gopsutil/v4/cpu"
cpu "github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/shirou/gopsutil/v4/mem"
"github.com/shirou/gopsutil/v4/net"
mem "github.com/shirou/gopsutil/v4/mem"
net "github.com/shirou/gopsutil/v4/net"
"golang.org/x/sys/unix"
)
func pidsWithContext(ctx context.Context) ([]int32, error) {
@ -130,7 +130,7 @@ func readPtr(r io.Reader) (uintptr, error) {
}
return uintptr(p), nil
default:
return 0, errors.New("unsupported pointer size")
return 0, fmt.Errorf("unsupported pointer size")
}
}

@ -247,7 +247,10 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error
return "", err
}
ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
return r == '\u0000'
if r == '\u0000' {
return true
}
return false
})
return strings.Join(ret, " "), nil

@ -59,7 +59,7 @@ func TestPid_exists(t *testing.T) {
t.Errorf("error %v", err)
}
if !ret {
if ret == false {
t.Errorf("could not get process exists: %v", ret)
}
}

@ -12,16 +12,16 @@ import (
"os"
"path/filepath"
"reflect"
"strings"
"syscall"
"time"
"unicode/utf16"
"unsafe"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/shirou/gopsutil/v4/net"
"golang.org/x/sys/windows"
)
type Signal = syscall.Signal
@ -245,7 +245,7 @@ func pidsWithContext(ctx context.Context) ([]int32, error) {
// inspired by https://gist.github.com/henkman/3083408
// and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
var ret []int32
var read uint32
var read uint32 = 0
var psSize uint32 = 1024
const dwordSize uint32 = 4
@ -288,10 +288,10 @@ func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
return false, err
}
h, err := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid))
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
if err == windows.ERROR_ACCESS_DENIED {
return true, nil
}
if errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
if err == windows.ERROR_INVALID_PARAMETER {
return false, nil
}
if err != nil {
@ -330,7 +330,7 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
exe, err := p.ExeWithContext(ctx)
if err != nil {
return "", fmt.Errorf("could not get Name: %w", err)
return "", fmt.Errorf("could not get Name: %s", err)
}
return filepath.Base(exe), nil
@ -370,7 +370,7 @@ func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
func (p *Process) CmdlineWithContext(_ context.Context) (string, error) {
cmdline, err := getProcessCommandLine(p.Pid)
if err != nil {
return "", fmt.Errorf("could not get CommandLine: %w", err)
return "", fmt.Errorf("could not get CommandLine: %s", err)
}
return cmdline, nil
}
@ -380,33 +380,13 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
if err != nil {
return nil, err
}
return parseCmdline(cmdline)
}
func parseCmdline(cmdline string) ([]string, error) {
cmdlineptr, err := windows.UTF16PtrFromString(cmdline)
if err != nil {
return nil, err
}
var argc int32
argvptr, err := windows.CommandLineToArgv(cmdlineptr, &argc)
if err != nil {
return nil, err
}
defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argvptr))))
argv := make([]string, argc)
for i, v := range (*argvptr)[:argc] {
argv[i] = windows.UTF16ToString((*v)[:])
}
return argv, nil
return strings.Split(cmdline, " "), nil
}
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
ru, err := getRusage(p.Pid)
if err != nil {
return 0, fmt.Errorf("could not get CreationDate: %w", err)
return 0, fmt.Errorf("could not get CreationDate: %s", err)
}
return ru.CreationTime.Nanoseconds() / 1000000, nil
@ -414,7 +394,7 @@ func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
func (p *Process) CwdWithContext(_ context.Context) (string, error) {
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid))
if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
return "", nil
}
if err != nil {
@ -652,17 +632,7 @@ func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExSta
}
func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
mem, err := getMemoryInfo(p.Pid)
if err != nil {
return nil, err
}
ret := &PageFaultsStat{
// Since Windows does not distinguish between Major and Minor faults, all faults are treated as Major
MajorFaults: uint64(mem.PageFaultCount),
}
return ret, nil
return nil, common.ErrNotImplementedError
}
func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
@ -852,9 +822,9 @@ func (p *Process) KillWithContext(ctx context.Context) error {
}
func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
envVars, err := getProcessEnvironmentVariables(ctx, p.Pid)
envVars, err := getProcessEnvironmentVariables(p.Pid, ctx)
if err != nil {
return nil, fmt.Errorf("could not get environment variables: %w", err)
return nil, fmt.Errorf("could not get environment variables: %s", err)
}
return envVars, nil
}
@ -874,7 +844,7 @@ func (p *Process) setPpid(ppid int32) {
p.parent = ppid
}
func getFromSnapProcess(pid int32) (int32, int32, string, error) { //nolint:unparam //FIXME
func getFromSnapProcess(pid int32) (int32, int32, string, error) {
snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid))
if err != nil {
return 0, 0, "", err
@ -902,7 +872,7 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
pids, err := PidsWithContext(ctx)
if err != nil {
return out, fmt.Errorf("could not get Processes %w", err)
return out, fmt.Errorf("could not get Processes %s", err)
}
for _, pid := range pids {
@ -993,13 +963,13 @@ func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32,
buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{})))
if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) {
return rtlUserProcessParameters32{}, errors.New("cannot read process PEB")
return rtlUserProcessParameters32{}, fmt.Errorf("cannot read process PEB")
}
peb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0]))
userProcessAddress := uint64(peb.ProcessParameters)
buf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{})))
if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) {
return rtlUserProcessParameters32{}, errors.New("cannot read user process parameters")
return rtlUserProcessParameters32{}, fmt.Errorf("cannot read user process parameters")
}
return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil
}
@ -1012,13 +982,13 @@ func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64,
buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{})))
if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) {
return rtlUserProcessParameters64{}, errors.New("cannot read process PEB")
return rtlUserProcessParameters64{}, fmt.Errorf("cannot read process PEB")
}
peb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0]))
userProcessAddress := peb.ProcessParameters
buf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{})))
if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) {
return rtlUserProcessParameters64{}, errors.New("cannot read user process parameters")
return rtlUserProcessParameters64{}, fmt.Errorf("cannot read user process parameters")
}
return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil
}
@ -1068,9 +1038,9 @@ func is32BitProcess(h windows.Handle) bool {
return procIs32Bits
}
func getProcessEnvironmentVariables(ctx context.Context, pid int32) ([]string, error) {
func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, error) {
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
return nil, nil
}
if err != nil {
@ -1154,7 +1124,7 @@ func (p *processReader) Read(buf []byte) (int, error) {
func getProcessCommandLine(pid int32) (string, error) {
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
return "", nil
}
if err != nil {

@ -8,9 +8,8 @@ import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/windows"
)
type PROCESS_MEMORY_COUNTERS struct {
@ -40,27 +39,30 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, er
)
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return uint64(info.PebBaseAddress), nil
} else {
return 0, windows.NTStatus(ret)
}
return 0, windows.NTStatus(ret)
}
// we are on a 32-bit process reading an external 64-bit process
if common.ProcNtWow64QueryInformationProcess64.Find() != nil {
return 0, errors.New("can't find API to query 64 bit process from 32 bit")
}
// avoid panic
var info processBasicInformation64
} else {
// we are on a 32-bit process reading an external 64-bit process
if common.ProcNtWow64QueryInformationProcess64.Find() == nil { // avoid panic
var info processBasicInformation64
ret, _, _ := common.ProcNtWow64QueryInformationProcess64.Call(
uintptr(procHandle),
uintptr(common.ProcessBasicInformation),
uintptr(unsafe.Pointer(&info)),
uintptr(unsafe.Sizeof(info)),
uintptr(0),
)
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return info.PebBaseAddress, nil
ret, _, _ := common.ProcNtWow64QueryInformationProcess64.Call(
uintptr(procHandle),
uintptr(common.ProcessBasicInformation),
uintptr(unsafe.Pointer(&info)),
uintptr(unsafe.Sizeof(info)),
uintptr(0),
)
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return info.PebBaseAddress, nil
} else {
return 0, windows.NTStatus(ret)
}
} else {
return 0, errors.New("can't find API to query 64 bit process from 32 bit")
}
}
return 0, windows.NTStatus(ret)
}
func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, size uint) []byte {

@ -7,9 +7,8 @@ import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"github.com/shirou/gopsutil/v4/internal/common"
"golang.org/x/sys/windows"
)
type PROCESS_MEMORY_COUNTERS struct {
@ -39,23 +38,26 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, er
)
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return uint64(wow64), nil
} else {
return 0, windows.NTStatus(ret)
}
return 0, windows.NTStatus(ret)
}
// we are on a 64-bit process reading an external 64-bit process
var info processBasicInformation64
} else {
// we are on a 64-bit process reading an external 64-bit process
var info processBasicInformation64
ret, _, _ := common.ProcNtQueryInformationProcess.Call(
uintptr(procHandle),
uintptr(common.ProcessBasicInformation),
uintptr(unsafe.Pointer(&info)),
uintptr(unsafe.Sizeof(info)),
uintptr(0),
)
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return info.PebBaseAddress, nil
ret, _, _ := common.ProcNtQueryInformationProcess.Call(
uintptr(procHandle),
uintptr(common.ProcessBasicInformation),
uintptr(unsafe.Pointer(&info)),
uintptr(unsafe.Sizeof(info)),
uintptr(0),
)
if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
return info.PebBaseAddress, nil
} else {
return 0, windows.NTStatus(ret)
}
}
return 0, windows.NTStatus(ret)
}
func readProcessMemory(procHandle syscall.Handle, _ bool, address uint64, size uint) []byte {

@ -13,10 +13,10 @@ const (
hostTemperatureScale = 1000.0 // Not part of the linked file, but kept just in case it becomes relevant
)
func VirtualizationWithContext(_ context.Context) (string, string, error) {
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
return "", "", common.ErrNotImplementedError
}
func TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {
func TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
return []TemperatureStat{}, common.ErrNotImplementedError
}

@ -5,7 +5,7 @@ package sensors
import (
"context"
"errors"
"fmt"
"unsafe"
"github.com/shirou/gopsutil/v4/internal/common"
@ -129,7 +129,7 @@ func readSMC(smc *common.SMC, key string) (*smcReturn, error) {
resultSmc.kSMC = result.result
if err != nil || result.result != common.KSMCSuccess {
return resultSmc, errors.New("ERROR: IOConnectCallStructMethod failed")
return resultSmc, fmt.Errorf("ERROR: IOConnectCallStructMethod failed")
}
resultSmc.dataSize = uint32(result.keyInfo.dataSize)
@ -158,7 +158,7 @@ func callSMC(smc *common.SMC, input *smcParamStruct) (*smcParamStruct, error) {
uintptr(unsafe.Pointer(input)), inputCnt, uintptr(unsafe.Pointer(output)), &outputCnt)
if result != 0 {
return output, errors.New("ERROR: IOConnectCallStructMethod failed")
return output, fmt.Errorf("ERROR: IOConnectCallStructMethod failed")
}
return output, nil
@ -169,7 +169,7 @@ func toUint32(key string) uint32 {
return 0
}
var ans uint32
var ans uint32 = 0
var shift uint32 = 24
for i := 0; i < smcKeySize; i++ {

@ -6,7 +6,6 @@ package sensors
import (
"context"
"encoding/csv"
"errors"
"io"
"strconv"
"strings"
@ -25,7 +24,7 @@ func TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
r.FieldsPerRecord = -1
for {
record, err := r.Read()
if errors.Is(err, io.EOF) {
if err == io.EOF {
break
}
if err != nil {

@ -7,9 +7,8 @@ import (
"context"
"math"
"github.com/yusufpapurcu/wmi"
"github.com/shirou/gopsutil/v4/internal/common"
"github.com/yusufpapurcu/wmi"
)
type msAcpi_ThermalZoneTemperature struct {

@ -5,7 +5,6 @@ package winservices
import (
"context"
"errors"
"unsafe"
"golang.org/x/sys/windows"
@ -87,7 +86,7 @@ func (s *Service) QueryStatusWithContext(ctx context.Context) (ServiceStatus, er
var bytesNeeded uint32
var buf []byte
if err := windows.QueryServiceStatusEx(s.srv.Handle, windows.SC_STATUS_PROCESS_INFO, nil, 0, &bytesNeeded); !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {
if err := windows.QueryServiceStatusEx(s.srv.Handle, windows.SC_STATUS_PROCESS_INFO, nil, 0, &bytesNeeded); err != windows.ERROR_INSUFFICIENT_BUFFER {
return ServiceStatus{}, err
}

Loading…
Cancel
Save