Merge remote-tracking branch 'downstream/master' into elfrucool/fix-windows-load-avg

pull/1358/head
elfrucool 1 year ago
commit e787f1a2b3

@ -22,17 +22,17 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Install Go - name: Install Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with: with:
go-version: ${{ matrix.go-version }} go-version: ${{ matrix.go-version }}
- name: Checkout code - name: Checkout code
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: cache-paths - id: cache-paths
run: | run: |
echo "::set-output name=cache::$(go env GOCACHE)" echo "::set-output name=cache::$(go env GOCACHE)"
echo "::set-output name=mod-cache::$(go env GOMODCACHE)" echo "::set-output name=mod-cache::$(go env GOMODCACHE)"
- name: Cache go modules - name: Cache go modules
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
with: with:
path: | path: |
${{ steps.cache-paths.outputs.cache }} ${{ steps.cache-paths.outputs.cache }}

@ -16,13 +16,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Setup go - name: Setup go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with: with:
go-version: 1.17 go-version: 1.17
cache: false
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Setup golangci-lint - name: Setup golangci-lint
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0
with: with:
args: --verbose args: --verbose
version: latest version: latest

@ -10,6 +10,6 @@ jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Release - name: Release
run: make release run: make release

@ -13,13 +13,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: advanced-security/sbom-generator-action@375dee8e6144d9fd0ec1f5667b4f6fb4faacefed # v0.0.1 - uses: advanced-security/sbom-generator-action@375dee8e6144d9fd0ec1f5667b4f6fb4faacefed # v0.0.1
id: sbom id: sbom
env: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}
- uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with: with:
path: ${{steps.sbom.outputs.fileName }} path: ${{steps.sbom.outputs.fileName }}
name: "SBOM" name: "SBOM"

@ -8,6 +8,6 @@ jobs:
name: Shellcheck name: Shellcheck
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Run ShellCheck - name: Run ShellCheck
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0

@ -19,21 +19,21 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
go-version: ${{fromJson(needs.go-versions.outputs.versions)}} go-version: ${{fromJson(needs.go-versions.outputs.versions)}}
os: [ubuntu-22.04, ubuntu-20.04, windows-2022, windows-2019, macos-11, macos-12] os: [ubuntu-22.04, ubuntu-20.04, windows-2022, windows-2019, macos-11, macos-12, macos-13, macos-14]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Install Go - name: Install Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with: with:
go-version: ${{ matrix.go-version }} go-version: ${{ matrix.go-version }}
- name: Checkout code - name: Checkout code
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: go-env - id: go-env
run: | run: |
echo "::set-output name=cache::$(go env GOCACHE)" echo "::set-output name=cache::$(go env GOCACHE)"
echo "::set-output name=mod-cache::$(go env GOMODCACHE)" echo "::set-output name=mod-cache::$(go env GOMODCACHE)"
- name: Cache go modules - name: Cache go modules
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
with: with:
path: | path: |
${{ steps.go-env.outputs.cache }} ${{ steps.go-env.outputs.cache }}

@ -1,21 +1,21 @@
issues: issues:
max-same-issues: 0 max-same-issues: 0
exclude-rules: exclude-rules:
- linters: - linters:
- gosec - gosec
text: "G204" text: "G204"
- linters: - linters:
- revive - revive
text: "var-naming" text: "var-naming"
- linters: - linters:
- revive - revive
text: "exported" text: "exported"
- linters: - linters:
- revive - revive
text: "empty-block" text: "empty-block"
- linters: - linters:
- revive - revive
text: "unused-parameter" text: "unused-parameter"
linters: linters:
enable: enable:
- asciicheck - asciicheck
@ -26,6 +26,7 @@ linters:
- gofmt - gofmt
- gofumpt - gofumpt
- goimports - goimports
- gomodguard
- gosec - gosec
- gosimple - gosimple
- importas - importas
@ -46,10 +47,16 @@ linters:
- structcheck - structcheck
- unused - unused
- varcheck - varcheck
linters-settings: linters-settings:
gci: gci:
sections: sections:
- standard - standard
- default - default
- prefix(github.com/shirou) - prefix(github.com/shirou)
gomodguard:
blocked:
modules:
- io/ioutil:
recommandations:
- io
- os

@ -20,6 +20,7 @@ build_test: ## test only buildable
GOOS=linux GOARCH=loong64 go test ./... | $(BUILD_FAIL_PATTERN) GOOS=linux GOARCH=loong64 go test ./... | $(BUILD_FAIL_PATTERN)
GOOS=linux GOARCH=riscv64 go test ./... | $(BUILD_FAIL_PATTERN) GOOS=linux GOARCH=riscv64 go test ./... | $(BUILD_FAIL_PATTERN)
GOOS=linux GOARCH=s390x go test ./... | $(BUILD_FAIL_PATTERN) GOOS=linux GOARCH=s390x go test ./... | $(BUILD_FAIL_PATTERN)
GOOS=linux GOARCH=mips go test ./... | $(BUILD_FAIL_PATTERN)
GOOS=freebsd GOARCH=amd64 go test ./... | $(BUILD_FAIL_PATTERN) GOOS=freebsd GOARCH=amd64 go test ./... | $(BUILD_FAIL_PATTERN)
GOOS=freebsd GOARCH=386 go test ./... | $(BUILD_FAIL_PATTERN) GOOS=freebsd GOARCH=386 go test ./... | $(BUILD_FAIL_PATTERN)
GOOS=freebsd GOARCH=arm go test ./... | $(BUILD_FAIL_PATTERN) GOOS=freebsd GOARCH=arm go test ./... | $(BUILD_FAIL_PATTERN)

@ -32,7 +32,7 @@ can be skipped.
- Linux i386/amd64/arm(raspberry pi) - Linux i386/amd64/arm(raspberry pi)
- Windows i386/amd64/arm/arm64 - Windows i386/amd64/arm/arm64
- Darwin amd64/arm64 - Darwin amd64/arm64
- OpenBSD amd64 (Thank you @mpfz0r!) - OpenBSD i386/amd64/armv7/arm64/riscv64 (Thank you @mpfz0r!)
- Solaris amd64 (developed and tested on SmartOS/Illumos, Thank you - Solaris amd64 (developed and tested on SmartOS/Illumos, Thank you
@jen20!) @jen20!)
@ -109,6 +109,17 @@ As of v3.23.6, it is now possible to pass a path location using `context`: impor
First priority is given to the value set in `context`, then the value from the environment variable, and finally the default location. First priority is given to the value set in `context`, then the value from the environment variable, and finally the default location.
### Caching
As of v3.24.1, it is now possible to cached some values. These values default to false, not cached.
Be very careful that enabling the cache may cause inconsistencies. For example, if you enable caching of boottime on Linux, be aware that unintended values may be returned if [the boottime is changed by NTP after booted](https://github.com/shirou/gopsutil/issues/1070#issuecomment-842512782).
- `host`
- EnableBootTimeCache
- `process`
- EnableBootTimeCache
## Documentation ## Documentation
See https://pkg.go.dev/github.com/shirou/gopsutil/v3 or https://godocs.io/github.com/shirou/gopsutil/v3 See https://pkg.go.dev/github.com/shirou/gopsutil/v3 or https://godocs.io/github.com/shirou/gopsutil/v3
@ -190,7 +201,7 @@ Some code is ported from Ohai. Many thanks.
|users |x |x |x |x |x | | | |users |x |x |x |x |x | | |
|pids |x |x |x |x |x | | | |pids |x |x |x |x |x | | |
|pid\_exists |x |x |x |x |x | | | |pid\_exists |x |x |x |x |x | | |
|net\_connections |x | |x |x | | | | |net\_connections |x |x |x |x | | | |
|net\_protocols |x | | | | | | | |net\_protocols |x | | | | | | |
|net\_if\_addrs | | | | | | | | |net\_if\_addrs | | | | | | | |
|net\_if\_stats | | | | | | | | |net\_if\_stats | | | | | | | |
@ -207,7 +218,7 @@ Some code is ported from Ohai. Many thanks.
|cmdline |x |x | |x |x | |cmdline |x |x | |x |x |
|create\_time |x | | |x |x | |create\_time |x | | |x |x |
|status |x |x |x |x | | |status |x |x |x |x | |
|cwd |x | | |x | | |cwd |x | | |x |x |
|exe |x |x |x | |x | |exe |x |x |x | |x |
|uids |x |x |x |x | | |uids |x |x |x |x | |
|gids |x |x |x |x | | |gids |x |x |x |x | |

@ -5,15 +5,12 @@ package cpu
import ( import (
"context" "context"
"regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/internal/common"
) )
var whiteSpaces = regexp.MustCompile(`\s+`)
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
if percpu { if percpu {
return []TimesStat{}, common.ErrNotImplementedError return []TimesStat{}, common.ErrNotImplementedError
@ -28,8 +25,8 @@ func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
} }
ret := TimesStat{CPU: "cpu-total"} ret := TimesStat{CPU: "cpu-total"}
h := whiteSpaces.Split(lines[len(lines)-3], -1) // headers h := strings.Fields(lines[len(lines)-3]) // headers
v := whiteSpaces.Split(lines[len(lines)-2], -1) // values v := strings.Fields(lines[len(lines)-2]) // values
for i, header := range h { for i, header := range h {
if t, err := strconv.ParseFloat(v[i], 64); err == nil { if t, err := strconv.ParseFloat(v[i], 64); err == nil {
switch header { switch header {
@ -58,14 +55,14 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
ret := InfoStat{} ret := InfoStat{}
for _, line := range strings.Split(string(out), "\n") { for _, line := range strings.Split(string(out), "\n") {
if strings.HasPrefix(line, "Number Of Processors:") { if strings.HasPrefix(line, "Number Of Processors:") {
p := whiteSpaces.Split(line, 4) p := strings.Fields(line)
if len(p) > 3 { if len(p) > 3 {
if t, err := strconv.ParseUint(p[3], 10, 64); err == nil { if t, err := strconv.ParseUint(p[3], 10, 64); err == nil {
ret.Cores = int32(t) ret.Cores = int32(t)
} }
} }
} else if strings.HasPrefix(line, "Processor Clock Speed:") { } else if strings.HasPrefix(line, "Processor Clock Speed:") {
p := whiteSpaces.Split(line, 5) p := strings.Fields(line)
if len(p) > 4 { if len(p) > 4 {
if t, err := strconv.ParseFloat(p[3], 64); err == nil { if t, err := strconv.ParseFloat(p[3], 64); err == nil {
switch strings.ToUpper(p[4]) { switch strings.ToUpper(p[4]) {

@ -4,6 +4,7 @@
package cpu package cpu
import ( import (
"os"
"testing" "testing"
"github.com/shoenig/go-m1cpu" "github.com/shoenig/go-m1cpu"
@ -23,7 +24,7 @@ func Test_CpuInfo_AppleSilicon(t *testing.T) {
if vv.ModelName == "" { if vv.ModelName == "" {
t.Errorf("could not get CPU info: %v", vv) t.Errorf("could not get CPU info: %v", vv)
} }
if vv.Mhz <= 0 { if vv.Mhz <= 0 && os.Getenv("CI") != "true" {
t.Errorf("could not get frequency of: %s", vv.ModelName) t.Errorf("could not get frequency of: %s", vv.ModelName)
} }
if vv.Mhz > 6000 { if vv.Mhz > 6000 {

@ -1,5 +1,5 @@
//go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !dragonfly && !plan9 && !aix //go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows && !dragonfly && !plan9 && !aix
// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows,!dragonfly,!plan9,!aix // +build !darwin,!linux,!freebsd,!openbsd,!netbsd,!solaris,!windows,!dragonfly,!plan9,!aix
package cpu package cpu

@ -309,7 +309,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
func parseStatLine(line string) (*TimesStat, error) { func parseStatLine(line string) (*TimesStat, error) {
fields := strings.Fields(line) fields := strings.Fields(line)
if len(fields) == 0 { if len(fields) < 8 {
return nil, errors.New("stat does not contain cpu info") return nil, errors.New("stat does not contain cpu info")
} }

@ -0,0 +1,119 @@
//go:build netbsd
// +build netbsd
package cpu
import (
"context"
"fmt"
"runtime"
"unsafe"
"github.com/shirou/gopsutil/v3/internal/common"
"github.com/tklauser/go-sysconf"
"golang.org/x/sys/unix"
)
const (
// sys/sysctl.h
ctlKern = 1 // "high kernel": proc, limits
ctlHw = 6 // CTL_HW
kernCpTime = 51 // KERN_CPTIME
)
var ClocksPerSec = float64(100)
func init() {
clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
// ignore errors
if err == nil {
ClocksPerSec = float64(clkTck)
}
}
func Times(percpu bool) ([]TimesStat, error) {
return TimesWithContext(context.Background(), percpu)
}
func TimesWithContext(ctx context.Context, percpu bool) (ret []TimesStat, err error) {
if !percpu {
mib := []int32{ctlKern, kernCpTime}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return ret, err
}
times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
stat := TimesStat{
CPU: "cpu-total",
User: float64(times.User),
Nice: float64(times.Nice),
System: float64(times.Sys),
Idle: float64(times.Idle),
Irq: float64(times.Intr),
}
return []TimesStat{stat}, nil
}
ncpu, err := unix.SysctlUint32("hw.ncpu")
if err != nil {
return
}
var i uint32
for i = 0; i < ncpu; i++ {
mib := []int32{ctlKern, kernCpTime, int32(i)}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return ret, err
}
stats := (*cpuTimes)(unsafe.Pointer(&buf[0]))
ret = append(ret, TimesStat{
CPU: fmt.Sprintf("cpu%d", i),
User: float64(stats.User),
Nice: float64(stats.Nice),
System: float64(stats.Sys),
Idle: float64(stats.Idle),
Irq: float64(stats.Intr),
})
}
return ret, nil
}
// Returns only one (minimal) CPUInfoStat on NetBSD
func Info() ([]InfoStat, error) {
return InfoWithContext(context.Background())
}
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
var ret []InfoStat
var err error
c := InfoStat{}
mhz, err := unix.Sysctl("machdep.dmi.processor-frequency")
if err != nil {
return nil, err
}
_, err = fmt.Sscanf(mhz, "%f", &c.Mhz)
if err != nil {
return nil, err
}
ncpu, err := unix.SysctlUint32("hw.ncpuonline")
if err != nil {
return nil, err
}
c.Cores = int32(ncpu)
if c.ModelName, err = unix.Sysctl("machdep.dmi.processor-version"); err != nil {
return nil, err
}
return append(ret, c), nil
}
func CountsWithContext(ctx context.Context, logical bool) (int, error) {
return runtime.NumCPU(), nil
}

@ -0,0 +1,9 @@
package cpu
type cpuTimes struct {
User uint64
Nice uint64
Sys uint64
Intr uint64
Idle uint64
}

@ -0,0 +1,9 @@
package cpu
type cpuTimes struct {
User uint64
Nice uint64
Sys uint64
Intr uint64
Idle uint64
}

@ -0,0 +1,10 @@
package cpu
type cpuTimes struct {
User uint64
Nice uint64
Sys uint64
Spin uint64
Intr uint64
Idle uint64
}

@ -36,6 +36,8 @@ func Times(percpu bool) ([]TimesStat, error) {
return TimesWithContext(context.Background(), percpu) return TimesWithContext(context.Background(), percpu)
} }
var kstatSplit = regexp.MustCompile(`[:\s]+`)
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-p", "cpu_stat:*:*:/^idle$|^user$|^kernel$|^iowait$|^swap$/") kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-p", "cpu_stat:*:*:/^idle$|^user$|^kernel$|^iowait$|^swap$/")
if err != nil { if err != nil {
@ -47,9 +49,8 @@ func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
kern := make(map[float64]float64) kern := make(map[float64]float64)
iowt := make(map[float64]float64) iowt := make(map[float64]float64)
// swap := make(map[float64]float64) // swap := make(map[float64]float64)
re := regexp.MustCompile(`[:\s]+`)
for _, line := range strings.Split(string(kstatSysOut), "\n") { for _, line := range strings.Split(string(kstatSysOut), "\n") {
fields := re.Split(line, -1) fields := kstatSplit.Split(line, -1)
if fields[0] != "cpu_stat" { if fields[0] != "cpu_stat" {
continue continue
} }

@ -1,7 +1,7 @@
package cpu package cpu
import ( import (
"io/ioutil" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"sort" "sort"
@ -49,7 +49,7 @@ func TestParseISAInfo(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
content, err := ioutil.ReadFile(filepath.Join("testdata", "solaris", tc.filename)) content, err := os.ReadFile(filepath.Join("testdata", "solaris", tc.filename))
if err != nil { if err != nil {
t.Errorf("cannot read test case: %s", err) t.Errorf("cannot read test case: %s", err)
} }
@ -138,7 +138,7 @@ func TestParseProcessorInfo(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
content, err := ioutil.ReadFile(filepath.Join("testdata", "solaris", tc.filename)) content, err := os.ReadFile(filepath.Join("testdata", "solaris", tc.filename))
if err != nil { if err != nil {
t.Errorf("cannot read test case: %s", err) t.Errorf("cannot read test case: %s", err)
} }

@ -12,7 +12,6 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
var whiteSpaces = regexp.MustCompile(`\s+`)
var startBlank = regexp.MustCompile(`^\s+`) var startBlank = regexp.MustCompile(`^\s+`)
var ignoreFSType = map[string]bool{"procfs": true} var ignoreFSType = map[string]bool{"procfs": true}
@ -60,7 +59,7 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro
if startBlank.MatchString(line) { if startBlank.MatchString(line) {
line = "localhost" + line line = "localhost" + line
} }
p := whiteSpaces.Split(lines[idx], 6) p := strings.Fields(lines[idx])
if len(p) < 5 || ignoreFSType[p[colidx["vfs"]]] { if len(p) < 5 || ignoreFSType[p[colidx["vfs"]]] {
continue continue
} }

@ -1,5 +1,5 @@
//go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !aix //go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !windows && !solaris && !aix
// +build !darwin,!linux,!freebsd,!openbsd,!windows,!solaris,!aix // +build !darwin,!linux,!freebsd,!openbsd,!netbsd,!windows,!solaris,!aix
package disk package disk

@ -5,11 +5,9 @@ package disk
import ( import (
"bufio" "bufio"
"bytes"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -486,32 +484,42 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC
return ret, nil return ret, nil
} }
func udevData(ctx context.Context, major uint32, minor uint32, name string) (string, error) {
udevDataPath := common.HostRunWithContext(ctx, fmt.Sprintf("udev/data/b%d:%d", major, minor))
if f, err := os.Open(udevDataPath); err == nil {
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
values := strings.SplitN(scanner.Text(), "=", 3)
if len(values) == 2 && values[0] == name {
return values[1], nil
}
}
return "", scanner.Err()
} else if !os.IsNotExist(err) {
return "", err
}
return "", nil
}
func SerialNumberWithContext(ctx context.Context, name string) (string, error) { func SerialNumberWithContext(ctx context.Context, name string) (string, error) {
var stat unix.Stat_t var stat unix.Stat_t
err := unix.Stat(name, &stat) if err := unix.Stat(name, &stat); err != nil {
if err != nil {
return "", err return "", err
} }
major := unix.Major(uint64(stat.Rdev)) major := unix.Major(uint64(stat.Rdev))
minor := unix.Minor(uint64(stat.Rdev)) minor := unix.Minor(uint64(stat.Rdev))
// Try to get the serial from udev data sserial, _ := udevData(ctx, major, minor, "E:ID_SERIAL")
udevDataPath := common.HostRunWithContext(ctx, fmt.Sprintf("udev/data/b%d:%d", major, minor)) if sserial != "" {
if udevdata, err := ioutil.ReadFile(udevDataPath); err == nil { return sserial, nil
scanner := bufio.NewScanner(bytes.NewReader(udevdata))
for scanner.Scan() {
values := strings.Split(scanner.Text(), "=")
if len(values) == 2 && values[0] == "E:ID_SERIAL" {
return values[1], nil
}
}
} }
// Try to get the serial from sysfs, look at the disk device (minor 0) directly // Try to get the serial from sysfs, look at the disk device (minor 0) directly
// because if it is a partition it is not going to contain any device information // because if it is a partition it is not going to contain any device information
devicePath := common.HostSysWithContext(ctx, fmt.Sprintf("dev/block/%d:0/device", major)) devicePath := common.HostSysWithContext(ctx, fmt.Sprintf("dev/block/%d:0/device", major))
model, _ := ioutil.ReadFile(filepath.Join(devicePath, "model")) model, _ := os.ReadFile(filepath.Join(devicePath, "model"))
serial, _ := ioutil.ReadFile(filepath.Join(devicePath, "serial")) serial, _ := os.ReadFile(filepath.Join(devicePath, "serial"))
if len(model) > 0 && len(serial) > 0 { if len(model) > 0 && len(serial) > 0 {
return fmt.Sprintf("%s_%s", string(model), string(serial)), nil return fmt.Sprintf("%s_%s", string(model), string(serial)), nil
} }
@ -521,16 +529,26 @@ func SerialNumberWithContext(ctx context.Context, name string) (string, error) {
func LabelWithContext(ctx context.Context, name string) (string, error) { func LabelWithContext(ctx context.Context, name string) (string, error) {
// Try label based on devicemapper name // Try label based on devicemapper name
dmname_filename := common.HostSysWithContext(ctx, fmt.Sprintf("block/%s/dm/name", name)) dmname_filename := common.HostSysWithContext(ctx, fmt.Sprintf("block/%s/dm/name", name))
// Could errors.Join errs with Go >= 1.20
if !common.PathExists(dmname_filename) { if common.PathExists(dmname_filename) {
return "", nil dmname, err := os.ReadFile(dmname_filename)
if err == nil {
return strings.TrimSpace(string(dmname)), nil
}
} }
// Try udev data
var stat unix.Stat_t
if err := unix.Stat(common.HostDevWithContext(ctx, name), &stat); err != nil {
return "", err
}
major := unix.Major(uint64(stat.Rdev))
minor := unix.Minor(uint64(stat.Rdev))
dmname, err := ioutil.ReadFile(dmname_filename) label, err := udevData(ctx, major, minor, "E:ID_FS_LABEL")
if err != nil { if err != nil {
return "", err return "", err
} }
return strings.TrimSpace(string(dmname)), nil return label, nil
} }
func getFsType(stat unix.Statfs_t) string { func getFsType(stat unix.Statfs_t) string {

@ -0,0 +1,152 @@
//go:build netbsd
// +build netbsd
package disk
import (
"context"
"unsafe"
"github.com/shirou/gopsutil/v3/internal/common"
"golang.org/x/sys/unix"
)
const (
// see sys/fstypes.h and `man 5 statvfs`
MNT_RDONLY = 0x00000001 /* read only filesystem */
MNT_SYNCHRONOUS = 0x00000002 /* file system written synchronously */
MNT_NOEXEC = 0x00000004 /* can't exec from filesystem */
MNT_NOSUID = 0x00000008 /* don't honor setuid bits on fs */
MNT_NODEV = 0x00000010 /* don't interpret special files */
MNT_ASYNC = 0x00000040 /* file system written asynchronously */
MNT_NOATIME = 0x04000000 /* Never update access times in fs */
MNT_SOFTDEP = 0x80000000 /* Use soft dependencies */
)
func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {
var ret []PartitionStat
flag := uint64(1) // ST_WAIT/MNT_WAIT, see sys/fstypes.h
// get required buffer size
emptyBufSize := 0
r, _, err := unix.Syscall(
483, // SYS___getvfsstat90 syscall
uintptr(unsafe.Pointer(nil)),
uintptr(unsafe.Pointer(&emptyBufSize)),
uintptr(unsafe.Pointer(&flag)),
)
if err != 0 {
return ret, err
}
mountedFsCount := uint64(r)
// calculate the buffer size
bufSize := sizeOfStatvfs * mountedFsCount
buf := make([]Statvfs, mountedFsCount)
// request agian to get desired mount data
_, _, err = unix.Syscall(
483, // SYS___getvfsstat90 syscall
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&bufSize)),
uintptr(unsafe.Pointer(&flag)),
)
if err != 0 {
return ret, err
}
for _, stat := range buf {
opts := []string{"rw"}
if stat.Flag&MNT_RDONLY != 0 {
opts = []string{"rw"}
}
if stat.Flag&MNT_SYNCHRONOUS != 0 {
opts = append(opts, "sync")
}
if stat.Flag&MNT_NOEXEC != 0 {
opts = append(opts, "noexec")
}
if stat.Flag&MNT_NOSUID != 0 {
opts = append(opts, "nosuid")
}
if stat.Flag&MNT_NODEV != 0 {
opts = append(opts, "nodev")
}
if stat.Flag&MNT_ASYNC != 0 {
opts = append(opts, "async")
}
if stat.Flag&MNT_SOFTDEP != 0 {
opts = append(opts, "softdep")
}
if stat.Flag&MNT_NOATIME != 0 {
opts = append(opts, "noatime")
}
d := PartitionStat{
Device: common.ByteToString([]byte(stat.Mntfromname[:])),
Mountpoint: common.ByteToString([]byte(stat.Mntonname[:])),
Fstype: common.ByteToString([]byte(stat.Fstypename[:])),
Opts: opts,
}
ret = append(ret, d)
}
return ret, nil
}
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
ret := make(map[string]IOCountersStat)
return ret, common.ErrNotImplementedError
}
func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
stat := Statvfs{}
flag := uint64(1) // ST_WAIT/MNT_WAIT, see sys/fstypes.h
_path, e := unix.BytePtrFromString(path)
if e != nil {
return nil, e
}
_, _, err := unix.Syscall(
484, // SYS___statvfs190, see sys/syscall.h
uintptr(unsafe.Pointer(_path)),
uintptr(unsafe.Pointer(&stat)),
uintptr(unsafe.Pointer(&flag)),
)
if err != 0 {
return nil, err
}
// frsize is the real block size on NetBSD. See discuss here: https://bugzilla.samba.org/show_bug.cgi?id=11810
bsize := stat.Frsize
ret := &UsageStat{
Path: path,
Fstype: getFsType(stat),
Total: (uint64(stat.Blocks) * uint64(bsize)),
Free: (uint64(stat.Bavail) * uint64(bsize)),
InodesTotal: (uint64(stat.Files)),
InodesFree: (uint64(stat.Ffree)),
}
ret.InodesUsed = (ret.InodesTotal - ret.InodesFree)
ret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0
ret.Used = (uint64(stat.Blocks) - uint64(stat.Bfree)) * uint64(bsize)
ret.UsedPercent = (float64(ret.Used) / float64(ret.Total)) * 100.0
return ret, nil
}
func getFsType(stat Statvfs) string {
return common.ByteToString(stat.Fstypename[:])
}
func SerialNumberWithContext(ctx context.Context, name string) (string, error) {
return "", common.ErrNotImplementedError
}
func LabelWithContext(ctx context.Context, name string) (string, error) {
return "", common.ErrNotImplementedError
}

@ -0,0 +1,45 @@
//go:build netbsd && amd64
// +build netbsd,amd64
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs types_netbsd.go
package disk
const (
sizeOfStatvfs = 0xce0
)
type (
Statvfs struct {
Flag uint64
Bsize uint64
Frsize uint64
Iosize uint64
Blocks uint64
Bfree uint64
Bavail uint64
Bresvd uint64
Files uint64
Ffree uint64
Favail uint64
Fresvd uint64
Syncreads uint64
Syncwrites uint64
Asyncreads uint64
Asyncwrites uint64
Fsidx _Ctype_struct___0
Fsid uint64
Namemax uint64
Owner uint32
Spare [4]uint64
Fstypename [32]uint8
Mntonname [1024]uint8
Mntfromname [1024]uint8
Mntfromlabel [1024]uint8
}
)
type _Ctype_struct___0 struct {
FsidVal [2]int32
}

@ -0,0 +1,45 @@
//go:build netbsd && arm64
// +build netbsd,arm64
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs types_netbsd.go
package disk
const (
sizeOfStatvfs = 0xce0
)
type (
Statvfs struct {
Flag uint64
Bsize uint64
Frsize uint64
Iosize uint64
Blocks uint64
Bfree uint64
Bavail uint64
Bresvd uint64
Files uint64
Ffree uint64
Favail uint64
Fresvd uint64
Syncreads uint64
Syncwrites uint64
Asyncreads uint64
Asyncwrites uint64
Fsidx _Ctype_struct___0
Fsid uint64
Namemax uint64
Owner uint32
Spare [4]uint64
Fstypename [32]uint8
Mntonname [1024]uint8
Mntfromname [1024]uint8
Mntfromlabel [1024]uint8
}
)
type _Ctype_struct___0 struct {
FsidVal [2]int32
}

@ -0,0 +1,40 @@
//go:build openbsd && riscv64
// +build openbsd,riscv64
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs disk/types_openbsd.go
package disk
const (
devstat_NO_DATA = 0x00
devstat_READ = 0x01
devstat_WRITE = 0x02
devstat_FREE = 0x03
)
const (
sizeOfDiskstats = 0x70
)
type (
Diskstats struct {
Name [16]int8
Busy int32
Rxfer uint64
Wxfer uint64
Seek uint64
Rbytes uint64
Wbytes uint64
Attachtime Timeval
Timestamp Timeval
Time Timeval
}
Timeval struct {
Sec int64
Usec int64
}
)
type Diskstat struct{}
type bintime struct{}

@ -83,6 +83,8 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro
return ret, err return ret, err
} }
var kstatSplit = regexp.MustCompile(`[:\s]+`)
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
var issolaris bool var issolaris bool
if runtime.GOOS == "illumos" { if runtime.GOOS == "illumos" {
@ -107,7 +109,6 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC
writesarr := make(map[string]uint64) writesarr := make(map[string]uint64)
rtimearr := make(map[string]uint64) rtimearr := make(map[string]uint64)
wtimearr := make(map[string]uint64) wtimearr := make(map[string]uint64)
re := regexp.MustCompile(`[:\s]+`)
// in case the name is "/dev/sda1", then convert to "sda1" // in case the name is "/dev/sda1", then convert to "sda1"
for i, name := range names { for i, name := range names {
@ -115,7 +116,7 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC
} }
for _, line := range lines { for _, line := range lines {
fields := re.Split(line, -1) fields := kstatSplit.Split(line, -1)
if len(fields) == 0 { if len(fields) == 0 {
continue continue
} }

@ -0,0 +1,30 @@
//go:build ignore
// +build ignore
// Hand writing: _Ctype_struct___0
/*
Input to cgo -godefs.
*/
package disk
/*
#include <sys/types.h>
#include <sys/statvfs.h>
#include <sys/cdefs.h>
#include <sys/featuretest.h>
#include <sys/stdint.h>
#include <machine/ansi.h>
#include <sys/ansi.h>
*/
import "C"
const (
sizeOfStatvfs = C.sizeof_struct_statvfs
)
type (
Statvfs C.struct_statvfs
)

@ -3,14 +3,14 @@ module github.com/shirou/gopsutil/v3
go 1.15 go 1.15
require ( require (
github.com/google/go-cmp v0.5.9 github.com/google/go-cmp v0.6.0
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c
github.com/shoenig/go-m1cpu v0.1.6 github.com/shoenig/go-m1cpu v0.1.6
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/tklauser/go-sysconf v0.3.12 github.com/tklauser/go-sysconf v0.3.12
github.com/yusufpapurcu/wmi v1.2.3 github.com/yusufpapurcu/wmi v1.2.4
golang.org/x/sys v0.11.0 golang.org/x/sys v0.17.0
) )
retract v3.22.11 retract v3.22.11

@ -4,8 +4,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= 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/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.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -27,13 +28,14 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

@ -62,6 +62,13 @@ func (t TemperatureStat) String() string {
return string(s) return string(s)
} }
var enableBootTimeCache bool
// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.
func EnableBootTimeCache(enable bool) {
enableBootTimeCache = enable
}
func Info() (*InfoStat, error) { func Info() (*InfoStat, error) {
return InfoWithContext(context.Background()) return InfoWithContext(context.Background())
} }

@ -1,5 +1,5 @@
//go:build darwin || freebsd || openbsd //go:build darwin || freebsd || openbsd || netbsd
// +build darwin freebsd openbsd // +build darwin freebsd openbsd netbsd
package host package host
@ -14,16 +14,20 @@ import (
var cachedBootTime uint64 var cachedBootTime uint64
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context) (uint64, error) {
t := atomic.LoadUint64(&cachedBootTime) if enableBootTimeCache {
if t != 0 { t := atomic.LoadUint64(&cachedBootTime)
return t, nil if t != 0 {
return t, nil
}
} }
tv, err := unix.SysctlTimeval("kern.boottime") tv, err := unix.SysctlTimeval("kern.boottime")
if err != nil { if err != nil {
return 0, err return 0, err
} }
atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec)) if enableBootTimeCache {
atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec))
}
return uint64(tv.Sec), nil return uint64(tv.Sec), nil
} }

@ -8,7 +8,7 @@ import (
"context" "context"
"encoding/binary" "encoding/binary"
"errors" "errors"
"io/ioutil" "io"
"os" "os"
"strings" "strings"
"unsafe" "unsafe"
@ -59,11 +59,14 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
} }
defer file.Close() defer file.Close()
buf, err := ioutil.ReadAll(file) buf, err := io.ReadAll(file)
if err != nil { if err != nil {
return ret, err return ret, err
} }
// Skip macOS utmpx header part
buf = buf[604:]
u := Utmpx{} u := Utmpx{}
entrySize := int(unsafe.Sizeof(u)) entrySize := int(unsafe.Sizeof(u))
count := len(buf) / entrySize count := len(buf) / entrySize

@ -1,5 +1,5 @@
//go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows //go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows
// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows // +build !darwin,!linux,!freebsd,!openbsd,!netbsd,!solaris,!windows
package host package host

@ -7,7 +7,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/binary" "encoding/binary"
"io/ioutil" "io"
"math" "math"
"os" "os"
"strings" "strings"
@ -54,7 +54,7 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
} }
defer file.Close() defer file.Close()
buf, err := ioutil.ReadAll(file) buf, err := io.ReadAll(file)
if err != nil { if err != nil {
return ret, err return ret, err
} }
@ -111,7 +111,7 @@ func getUsersFromUtmp(utmpfile string) ([]UserStat, error) {
} }
defer file.Close() defer file.Close()
buf, err := ioutil.ReadAll(file) buf, err := io.ReadAll(file)
if err != nil { if err != nil {
return ret, err return ret, err
} }

@ -8,7 +8,7 @@ import (
"context" "context"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io/ioutil" "io"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
@ -71,7 +71,7 @@ func numProcs(ctx context.Context) (uint64, error) {
} }
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context) (uint64, error) {
return common.BootTimeWithContext(ctx) return common.BootTimeWithContext(ctx, enableBootTimeCache)
} }
func UptimeWithContext(ctx context.Context) (uint64, error) { func UptimeWithContext(ctx context.Context) (uint64, error) {
@ -91,7 +91,7 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
} }
defer file.Close() defer file.Close()
buf, err := ioutil.ReadAll(file) buf, err := io.ReadAll(file)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -212,6 +212,12 @@ func PlatformInformationWithContext(ctx context.Context) (platform string, famil
} else if lsb.ID == `"Cumulus Linux"` { } else if lsb.ID == `"Cumulus Linux"` {
platform = "cumuluslinux" platform = "cumuluslinux"
version = lsb.Release version = lsb.Release
} else if lsb.ID == "uos" {
platform = "uos"
version = lsb.Release
} else if lsb.ID == "Deepin" {
platform = "Deepin"
version = lsb.Release
} else { } else {
if common.PathExistsWithContents("/usr/bin/raspi-config") { if common.PathExistsWithContents("/usr/bin/raspi-config") {
platform = "raspbian" platform = "raspbian"
@ -223,47 +229,47 @@ func PlatformInformationWithContext(ctx context.Context) (platform string, famil
version = contents[0] version = contents[0]
} }
} }
} else if common.PathExists(common.HostEtcWithContext(ctx, "neokylin-release")) { } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "neokylin-release")) {
contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "neokylin-release")) contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "neokylin-release"))
if err == nil { if err == nil {
version = getRedhatishVersion(contents) version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents) platform = getRedhatishPlatform(contents)
} }
} else if common.PathExists(common.HostEtcWithContext(ctx, "redhat-release")) { } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "redhat-release")) {
contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "redhat-release")) contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "redhat-release"))
if err == nil { if err == nil {
version = getRedhatishVersion(contents) version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents) platform = getRedhatishPlatform(contents)
} }
} else if common.PathExists(common.HostEtcWithContext(ctx, "system-release")) { } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "system-release")) {
contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "system-release")) contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "system-release"))
if err == nil { if err == nil {
version = getRedhatishVersion(contents) version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents) platform = getRedhatishPlatform(contents)
} }
} else if common.PathExists(common.HostEtcWithContext(ctx, "gentoo-release")) { } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "gentoo-release")) {
platform = "gentoo" platform = "gentoo"
contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "gentoo-release")) contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "gentoo-release"))
if err == nil { if err == nil {
version = getRedhatishVersion(contents) version = getRedhatishVersion(contents)
} }
} else if common.PathExists(common.HostEtcWithContext(ctx, "SuSE-release")) { } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "SuSE-release")) {
contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "SuSE-release")) contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "SuSE-release"))
if err == nil { if err == nil {
version = getSuseVersion(contents) version = getSuseVersion(contents)
platform = getSusePlatform(contents) platform = getSusePlatform(contents)
} }
// TODO: slackware detecion // TODO: slackware detecion
} else if common.PathExists(common.HostEtcWithContext(ctx, "arch-release")) { } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "arch-release")) {
platform = "arch" platform = "arch"
version = lsb.Release version = lsb.Release
} else if common.PathExists(common.HostEtcWithContext(ctx, "alpine-release")) { } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "alpine-release")) {
platform = "alpine" platform = "alpine"
contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "alpine-release")) contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "alpine-release"))
if err == nil && len(contents) > 0 && contents[0] != "" { if err == nil && len(contents) > 0 && contents[0] != "" {
version = contents[0] version = contents[0]
} }
} else if common.PathExists(common.HostEtcWithContext(ctx, "os-release")) { } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "os-release")) {
p, v, err := common.GetOSReleaseWithContext(ctx) p, v, err := common.GetOSReleaseWithContext(ctx)
if err == nil { if err == nil {
platform = p platform = p
@ -289,7 +295,7 @@ func PlatformInformationWithContext(ctx context.Context) (platform string, famil
platform = strings.Trim(platform, `"`) platform = strings.Trim(platform, `"`)
switch platform { switch platform {
case "debian", "ubuntu", "linuxmint", "raspbian", "Kylin", "cumuluslinux": case "debian", "ubuntu", "linuxmint", "raspbian", "Kylin", "cumuluslinux", "uos", "Deepin":
family = "debian" family = "debian"
case "fedora": case "fedora":
family = "fedora" family = "fedora"
@ -333,13 +339,15 @@ func getSlackwareVersion(contents []string) string {
return c return c
} }
var redhatishReleaseMatch = regexp.MustCompile(`release (\w[\d.]*)`)
func getRedhatishVersion(contents []string) string { func getRedhatishVersion(contents []string) string {
c := strings.ToLower(strings.Join(contents, "")) c := strings.ToLower(strings.Join(contents, ""))
if strings.Contains(c, "rawhide") { if strings.Contains(c, "rawhide") {
return "rawhide" return "rawhide"
} }
if matches := regexp.MustCompile(`release (\w[\d.]*)`).FindStringSubmatch(c); matches != nil { if matches := redhatishReleaseMatch.FindStringSubmatch(c); matches != nil {
return matches[1] return matches[1]
} }
return "" return ""
@ -356,12 +364,17 @@ func getRedhatishPlatform(contents []string) string {
return f[0] return f[0]
} }
var (
suseVersionMatch = regexp.MustCompile(`VERSION = ([\d.]+)`)
susePatchLevelMatch = regexp.MustCompile(`PATCHLEVEL = (\d+)`)
)
func getSuseVersion(contents []string) string { func getSuseVersion(contents []string) string {
version := "" version := ""
for _, line := range contents { for _, line := range contents {
if matches := regexp.MustCompile(`VERSION = ([\d.]+)`).FindStringSubmatch(line); matches != nil { if matches := suseVersionMatch.FindStringSubmatch(line); matches != nil {
version = matches[1] version = matches[1]
} else if matches := regexp.MustCompile(`PATCHLEVEL = ([\d]+)`).FindStringSubmatch(line); matches != nil { } else if matches = susePatchLevelMatch.FindStringSubmatch(line); matches != nil {
version = version + "." + matches[1] version = version + "." + matches[1]
} }
} }
@ -411,13 +424,13 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err
} }
for _, file := range files { for _, file := range files {
// Get the name of the temperature you are reading // Get the name of the temperature you are reading
name, err := ioutil.ReadFile(filepath.Join(file, "type")) name, err := os.ReadFile(filepath.Join(file, "type"))
if err != nil { if err != nil {
warns.Add(err) warns.Add(err)
continue continue
} }
// Get the temperature reading // Get the temperature reading
current, err := ioutil.ReadFile(filepath.Join(file, "temp")) current, err := os.ReadFile(filepath.Join(file, "temp"))
if err != nil { if err != nil {
warns.Add(err) warns.Add(err)
continue continue
@ -461,13 +474,13 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err
// Get the label of the temperature you are reading // Get the label of the temperature you are reading
label := "" label := ""
if raw, _ = ioutil.ReadFile(basepath + "_label"); len(raw) != 0 { if raw, _ = os.ReadFile(basepath + "_label"); len(raw) != 0 {
// Format the label from "Core 0" to "core_0" // Format the label from "Core 0" to "core_0"
label = strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(raw))), " "), "_") label = strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(raw))), " "), "_")
} }
// Get the name of the temperature you are reading // Get the name of the temperature you are reading
if raw, err = ioutil.ReadFile(filepath.Join(directory, "name")); err != nil { if raw, err = os.ReadFile(filepath.Join(directory, "name")); err != nil {
warns.Add(err) warns.Add(err)
continue continue
} }
@ -479,7 +492,7 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err
} }
// Get the temperature reading // Get the temperature reading
if raw, err = ioutil.ReadFile(file); err != nil { if raw, err = os.ReadFile(file); err != nil {
warns.Add(err) warns.Add(err)
continue continue
} }
@ -513,7 +526,7 @@ func optionalValueReadFromFile(filename string) float64 {
return 0 return 0
} }
if raw, err = ioutil.ReadFile(filename); err != nil { if raw, err = os.ReadFile(filename); err != nil {
return 0 return 0
} }

@ -0,0 +1,55 @@
//go:build netbsd
// +build netbsd
package host
import (
"context"
"strings"
"github.com/shirou/gopsutil/v3/internal/common"
"golang.org/x/sys/unix"
)
func HostIDWithContext(ctx context.Context) (string, error) {
return "", common.ErrNotImplementedError
}
func numProcs(ctx context.Context) (uint64, error) {
return 0, common.ErrNotImplementedError
}
func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
platform := ""
family := ""
version := ""
p, err := unix.Sysctl("kern.ostype")
if err == nil {
platform = strings.ToLower(p)
}
v, err := unix.Sysctl("kern.osrelease")
if err == nil {
version = strings.ToLower(v)
}
return platform, family, version, nil
}
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
return "", "", common.ErrNotImplementedError
}
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
var ret []UserStat
return ret, common.ErrNotImplementedError
}
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
return []TemperatureStat{}, common.ErrNotImplementedError
}
func KernelVersionWithContext(ctx context.Context) (string, error) {
_, _, version, err := PlatformInformationWithContext(ctx)
return version, err
}

@ -7,7 +7,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/binary" "encoding/binary"
"io/ioutil" "io"
"os" "os"
"strings" "strings"
"unsafe" "unsafe"
@ -65,7 +65,7 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
} }
defer file.Close() defer file.Close()
buf, err := ioutil.ReadAll(file) buf, err := io.ReadAll(file)
if err != nil { if err != nil {
return ret, err return ret, err
} }

@ -0,0 +1,36 @@
//go:build openbsd && riscv64
// +build openbsd,riscv64
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs host/types_openbsd.go
package host
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmp = 0x130
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type (
Utmp struct {
Line [8]int8
Name [32]int8
Host [256]int8
Time int64
}
Timeval struct {
Sec int64
Usec int64
}
)

@ -1,5 +1,5 @@
//go:build linux || freebsd || openbsd || darwin || solaris //go:build linux || freebsd || openbsd || netbsd || darwin || solaris
// +build linux freebsd openbsd darwin solaris // +build linux freebsd openbsd netbsd darwin solaris
package host package host

@ -7,7 +7,6 @@ import (
"encoding/csv" "encoding/csv"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"regexp" "regexp"
"strconv" "strconv"
@ -60,7 +59,7 @@ func HostIDWithContext(ctx context.Context) (string, error) {
// Count number of processes based on the number of entries in /proc // Count number of processes based on the number of entries in /proc
func numProcs(ctx context.Context) (uint64, error) { func numProcs(ctx context.Context) (uint64, error) {
dirs, err := ioutil.ReadDir("/proc") dirs, err := os.ReadDir("/proc")
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -138,7 +137,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) {
// Find distribution name from /etc/release // Find distribution name from /etc/release
func parseReleaseFile() (string, error) { func parseReleaseFile() (string, error) {
b, err := ioutil.ReadFile("/etc/release") b, err := os.ReadFile("/etc/release")
if err != nil { if err != nil {
return "", err return "", err
} }

@ -89,6 +89,7 @@ func TestUsers(t *testing.T) {
if u == empty { if u == empty {
t.Errorf("Could not Users %v", v) t.Errorf("Could not Users %v", v)
} }
t.Log(u)
} }
} }
@ -194,3 +195,17 @@ func TestPlatformInformation(t *testing.T) {
t.Logf("PlatformInformation(): %v, %v, %v", platform, family, version) t.Logf("PlatformInformation(): %v, %v, %v", platform, family, version)
} }
func BenchmarkBootTimeWithCache(b *testing.B) {
EnableBootTimeCache(true)
for i := 0; i < b.N; i++ {
BootTime()
}
}
func BenchmarkBootTimeWithoutCache(b *testing.B) {
EnableBootTimeCache(false)
for i := 0; i < b.N; i++ {
BootTime()
}
}

@ -127,16 +127,20 @@ func uptimeMillis() (uint64, error) {
var cachedBootTime uint64 var cachedBootTime uint64
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context) (uint64, error) {
t := atomic.LoadUint64(&cachedBootTime) if enableBootTimeCache {
if t != 0 { t := atomic.LoadUint64(&cachedBootTime)
return t, nil if t != 0 {
return t, nil
}
} }
up, err := uptimeMillis() up, err := uptimeMillis()
if err != nil { if err != nil {
return 0, err return 0, err
} }
t = uint64((time.Duration(timeSinceMillis(up)) * time.Millisecond).Seconds()) t := uint64((time.Duration(timeSinceMillis(up)) * time.Millisecond).Seconds())
atomic.StoreUint64(&cachedBootTime, t) if enableBootTimeCache {
atomic.StoreUint64(&cachedBootTime, t)
}
return t, nil return t, nil
} }

@ -14,7 +14,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
@ -87,7 +86,7 @@ func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
fpath += "_" + i.Suffix fpath += "_" + i.Suffix
} }
if PathExists(fpath) { if PathExists(fpath) {
return ioutil.ReadFile(fpath) return os.ReadFile(fpath)
} }
return []byte{}, fmt.Errorf("could not find testdata: %s", fpath) return []byte{}, fmt.Errorf("could not find testdata: %s", fpath)
} }
@ -100,7 +99,7 @@ var ErrNotImplementedError = errors.New("not implemented yet")
// ReadFile reads contents from a file // ReadFile reads contents from a file
func ReadFile(filename string) (string, error) { func ReadFile(filename string) (string, error) {
content, err := ioutil.ReadFile(filename) content, err := os.ReadFile(filename)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -344,7 +343,7 @@ func PathExistsWithContents(filename string) bool {
if err != nil { if err != nil {
return false return false
} }
return info.Size() > 4 // at least 4 bytes return info.Size() > 4 && !info.IsDir() // at least 4 bytes
} }
// GetEnvWithContext retrieves the environment variable key. If it does not exist it returns the default. // GetEnvWithContext retrieves the environment variable key. If it does not exist it returns the default.

@ -12,10 +12,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"syscall" "syscall"
"time" "time"
) )
// cachedBootTime must be accessed via atomic.Load/StoreUint64
var cachedBootTime uint64
func DoSysctrl(mib string) ([]string, error) { func DoSysctrl(mib string) ([]string, error) {
cmd := exec.Command("sysctl", "-n", mib) cmd := exec.Command("sysctl", "-n", mib)
cmd.Env = getSysctrlEnv(os.Environ()) cmd.Env = getSysctrlEnv(os.Environ())
@ -56,7 +60,14 @@ func NumProcsWithContext(ctx context.Context) (uint64, error) {
return cnt, nil return cnt, nil
} }
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context, enableCache bool) (uint64, error) {
if enableCache {
t := atomic.LoadUint64(&cachedBootTime)
if t != 0 {
return t, nil
}
}
system, role, err := VirtualizationWithContext(ctx) system, role, err := VirtualizationWithContext(ctx)
if err != nil { if err != nil {
return 0, err return 0, err
@ -72,7 +83,13 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) {
} }
if useStatFile { if useStatFile {
return readBootTimeStat(ctx) t, err := readBootTimeStat(ctx)
if err != nil {
return 0, err
}
if enableCache {
atomic.StoreUint64(&cachedBootTime, t)
}
} }
filename := HostProcWithContext(ctx, "uptime") filename := HostProcWithContext(ctx, "uptime")
@ -90,6 +107,11 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) {
} }
currentTime := float64(time.Now().UnixNano()) / float64(time.Second) currentTime := float64(time.Now().UnixNano()) / float64(time.Second)
t := currentTime - b t := currentTime - b
if enableCache {
atomic.StoreUint64(&cachedBootTime, uint64(t))
}
return uint64(t), nil return uint64(t), nil
} }
@ -307,7 +329,7 @@ func GetOSReleaseWithContext(ctx context.Context) (platform string, version stri
switch field[0] { switch field[0] {
case "ID": // use ID for lowercase case "ID": // use ID for lowercase
platform = trimQuotes(field[1]) platform = trimQuotes(field[1])
case "VERSION": case "VERSION_ID":
version = trimQuotes(field[1]) version = trimQuotes(field[1])
} }
} }

@ -0,0 +1,66 @@
//go:build netbsd
// +build netbsd
package common
import (
"os"
"os/exec"
"strings"
"unsafe"
"golang.org/x/sys/unix"
)
func DoSysctrl(mib string) ([]string, error) {
cmd := exec.Command("sysctl", "-n", mib)
cmd.Env = getSysctrlEnv(os.Environ())
out, err := cmd.Output()
if err != nil {
return []string{}, err
}
v := strings.Replace(string(out), "{ ", "", 1)
v = strings.Replace(string(v), " }", "", 1)
values := strings.Fields(string(v))
return values, nil
}
func CallSyscall(mib []int32) ([]byte, uint64, error) {
mibptr := unsafe.Pointer(&mib[0])
miblen := uint64(len(mib))
// get required buffer size
length := uint64(0)
_, _, err := unix.Syscall6(
unix.SYS___SYSCTL,
uintptr(mibptr),
uintptr(miblen),
0,
uintptr(unsafe.Pointer(&length)),
0,
0)
if err != 0 {
var b []byte
return b, length, err
}
if length == 0 {
var b []byte
return b, length, err
}
// get proc info itself
buf := make([]byte, length)
_, _, err = unix.Syscall6(
unix.SYS___SYSCTL,
uintptr(mibptr),
uintptr(miblen),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&length)),
0,
0)
if err != 0 {
return buf, length, err
}
return buf, length, nil
}

@ -5,7 +5,7 @@ package load
import ( import (
"context" "context"
"io/ioutil" "os"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
@ -76,7 +76,7 @@ func Misc() (*MiscStat, error) {
func MiscWithContext(ctx context.Context) (*MiscStat, error) { func MiscWithContext(ctx context.Context) (*MiscStat, error) {
filename := common.HostProcWithContext(ctx, "stat") filename := common.HostProcWithContext(ctx, "stat")
out, err := ioutil.ReadFile(filename) out, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -126,7 +126,7 @@ func getProcsTotal(ctx context.Context) (int64, error) {
func readLoadAvgFromFile(ctx context.Context) ([]string, error) { func readLoadAvgFromFile(ctx context.Context) ([]string, error) {
loadavgFilename := common.HostProcWithContext(ctx, "loadavg") loadavgFilename := common.HostProcWithContext(ctx, "loadavg")
line, err := ioutil.ReadFile(loadavgFilename) line, err := os.ReadFile(loadavgFilename)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -5,7 +5,6 @@ package load
import ( import (
"context" "context"
"log"
"math" "math"
"sync" "sync"
"time" "time"
@ -47,6 +46,7 @@ func loadAvgGoroutine(ctx context.Context) {
} }
loadAvgMutex.Lock() loadAvgMutex.Lock()
loadErr = err
loadAvg1M = loadAvg1M*loadAvgFactor1M + currentLoad*(1-loadAvgFactor1M) loadAvg1M = loadAvg1M*loadAvgFactor1M + currentLoad*(1-loadAvgFactor1M)
loadAvg5M = loadAvg5M*loadAvgFactor5M + currentLoad*(1-loadAvgFactor5M) loadAvg5M = loadAvg5M*loadAvgFactor5M + currentLoad*(1-loadAvgFactor5M)
loadAvg15M = loadAvg15M*loadAvgFactor15M + currentLoad*(1-loadAvgFactor15M) loadAvg15M = loadAvg15M*loadAvgFactor15M + currentLoad*(1-loadAvgFactor15M)

@ -50,6 +50,7 @@ type VirtualMemoryStat struct {
// https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-meminfo.html // https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-meminfo.html
// https://www.kernel.org/doc/Documentation/filesystems/proc.txt // 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/overcommit-accounting
// https://www.kernel.org/doc/Documentation/vm/transhuge.txt
Buffers uint64 `json:"buffers"` Buffers uint64 `json:"buffers"`
Cached uint64 `json:"cached"` Cached uint64 `json:"cached"`
WriteBack uint64 `json:"writeBack"` WriteBack uint64 `json:"writeBack"`
@ -78,6 +79,7 @@ type VirtualMemoryStat struct {
HugePagesRsvd uint64 `json:"hugePagesRsvd"` HugePagesRsvd uint64 `json:"hugePagesRsvd"`
HugePagesSurp uint64 `json:"hugePagesSurp"` HugePagesSurp uint64 `json:"hugePagesSurp"`
HugePageSize uint64 `json:"hugePageSize"` HugePageSize uint64 `json:"hugePageSize"`
AnonHugePages uint64 `json:"anonHugePages"`
} }
type SwapMemoryStat struct { type SwapMemoryStat struct {

@ -5,15 +5,12 @@ package mem
import ( import (
"context" "context"
"regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/internal/common"
) )
var whiteSpaces = regexp.MustCompile(`\s+`)
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
vmem, swap, err := callSVMon(ctx) vmem, swap, err := callSVMon(ctx)
if err != nil { if err != nil {
@ -49,7 +46,7 @@ func callSVMon(ctx context.Context) (*VirtualMemoryStat, *SwapMemoryStat, error)
swap := &SwapMemoryStat{} swap := &SwapMemoryStat{}
for _, line := range strings.Split(string(out), "\n") { for _, line := range strings.Split(string(out), "\n") {
if strings.HasPrefix(line, "memory") { if strings.HasPrefix(line, "memory") {
p := whiteSpaces.Split(line, 7) p := strings.Fields(line)
if len(p) > 2 { if len(p) > 2 {
if t, err := strconv.ParseUint(p[1], 10, 64); err == nil { if t, err := strconv.ParseUint(p[1], 10, 64); err == nil {
vmem.Total = t * pagesize vmem.Total = t * pagesize
@ -65,7 +62,7 @@ func callSVMon(ctx context.Context) (*VirtualMemoryStat, *SwapMemoryStat, error)
} }
} }
} else if strings.HasPrefix(line, "pg space") { } else if strings.HasPrefix(line, "pg space") {
p := whiteSpaces.Split(line, 4) p := strings.Fields(line)
if len(p) > 3 { if len(p) > 3 {
if t, err := strconv.ParseUint(p[2], 10, 64); err == nil { if t, err := strconv.ParseUint(p[2], 10, 64); err == nil {
swap.Total = t * pagesize swap.Total = t * pagesize

@ -1,5 +1,5 @@
//go:build freebsd || openbsd //go:build freebsd || openbsd || netbsd
// +build freebsd openbsd // +build freebsd openbsd netbsd
package mem package mem

@ -1,5 +1,5 @@
//go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !plan9 && !aix //go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !plan9 && !aix && !netbsd
// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows,!plan9,!aix // +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows,!plan9,!aix,!netbsd
package mem package mem

@ -311,6 +311,12 @@ func fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *Virtu
return ret, retEx, err return ret, retEx, err
} }
ret.HugePageSize = t * 1024 ret.HugePageSize = t * 1024
case "AnonHugePages":
t, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return ret, retEx, err
}
ret.AnonHugePages = t * 1024
} }
} }

@ -108,6 +108,16 @@ var virtualMemoryTests = []struct {
HugePageSize: 0, HugePageSize: 0,
}, },
}, },
{
"anonhugepages", &VirtualMemoryStat{
Total: 260799420 * 1024,
Available: 127880216 * 1024,
Free: 119443248 * 1024,
AnonHugePages: 50409472 * 1024,
Used: 144748720128,
UsedPercent: 54.20110673559013,
},
},
} }
func TestVirtualMemoryLinux(t *testing.T) { func TestVirtualMemoryLinux(t *testing.T) {

@ -0,0 +1,87 @@
//go:build netbsd
// +build netbsd
package mem
import (
"context"
"errors"
"fmt"
"golang.org/x/sys/unix"
)
func GetPageSize() (uint64, error) {
return GetPageSizeWithContext(context.Background())
}
func GetPageSizeWithContext(ctx context.Context) (uint64, error) {
uvmexp, err := unix.SysctlUvmexp("vm.uvmexp2")
if err != nil {
return 0, err
}
return uint64(uvmexp.Pagesize), nil
}
func VirtualMemory() (*VirtualMemoryStat, error) {
return VirtualMemoryWithContext(context.Background())
}
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
uvmexp, err := unix.SysctlUvmexp("vm.uvmexp2")
if err != nil {
return nil, err
}
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
// Get buffers from vm.bufmem sysctl
ret.Buffers, err = unix.SysctlUint64("vm.bufmem")
if err != nil {
return nil, err
}
return ret, nil
}
// Return swapctl summary info
func SwapMemory() (*SwapMemoryStat, error) {
return SwapMemoryWithContext(context.Background())
}
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
out, err := invoke.CommandWithContext(ctx, "swapctl", "-sk")
if err != nil {
return &SwapMemoryStat{}, nil
}
line := string(out)
var total, used, free uint64
_, err = fmt.Sscanf(line,
"total: %d 1K-blocks allocated, %d used, %d available",
&total, &used, &free)
if err != nil {
return nil, errors.New("failed to parse swapctl output")
}
percent := float64(used) / float64(total) * 100
return &SwapMemoryStat{
Total: total * 1024,
Used: used * 1024,
Free: free * 1024,
UsedPercent: percent,
}, nil
}

@ -0,0 +1,38 @@
//go:build openbsd && riscv64
// +build openbsd,riscv64
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs mem/types_openbsd.go
package mem
const (
CTLVfs = 10
VfsGeneric = 0
VfsBcacheStat = 3
)
const (
sizeOfBcachestats = 0x90
)
type Bcachestats struct {
Numbufs int64
Numbufpages int64
Numdirtypages int64
Numcleanpages int64
Pendingwrites int64
Pendingreads int64
Numwrites int64
Numreads int64
Cachehits int64
Busymapped int64
Dmapages int64
Highpages int64
Delwribufs int64
Kvaslots int64
Avail int64
Highflips int64
Highflops int64
Dmaflips int64
}

@ -89,7 +89,7 @@ func TestVirtualMemoryStat_String(t *testing.T) {
Free: 40, Free: 40,
} }
t.Log(v) t.Log(v)
e := `{"total":10,"available":20,"used":30,"usedPercent":30.1,"free":40,"active":0,"inactive":0,"wired":0,"laundry":0,"buffers":0,"cached":0,"writeBack":0,"dirty":0,"writeBackTmp":0,"shared":0,"slab":0,"sreclaimable":0,"sunreclaim":0,"pageTables":0,"swapCached":0,"commitLimit":0,"committedAS":0,"highTotal":0,"highFree":0,"lowTotal":0,"lowFree":0,"swapTotal":0,"swapFree":0,"mapped":0,"vmallocTotal":0,"vmallocUsed":0,"vmallocChunk":0,"hugePagesTotal":0,"hugePagesFree":0,"hugePagesRsvd":0,"hugePagesSurp":0,"hugePageSize":0}` e := `{"total":10,"available":20,"used":30,"usedPercent":30.1,"free":40,"active":0,"inactive":0,"wired":0,"laundry":0,"buffers":0,"cached":0,"writeBack":0,"dirty":0,"writeBackTmp":0,"shared":0,"slab":0,"sreclaimable":0,"sunreclaim":0,"pageTables":0,"swapCached":0,"commitLimit":0,"committedAS":0,"highTotal":0,"highFree":0,"lowTotal":0,"lowFree":0,"swapTotal":0,"swapFree":0,"mapped":0,"vmallocTotal":0,"vmallocUsed":0,"vmallocChunk":0,"hugePagesTotal":0,"hugePagesFree":0,"hugePagesRsvd":0,"hugePagesSurp":0,"hugePageSize":0,"anonHugePages":0}`
if e != fmt.Sprintf("%v", v) { if e != fmt.Sprintf("%v", v) {
t.Errorf("VirtualMemoryStat string is invalid: %v", v) t.Errorf("VirtualMemoryStat string is invalid: %v", v)
} }

@ -0,0 +1,4 @@
MemTotal: 260799420 kB
MemFree: 119443248 kB
MemAvailable: 127880216 kB
AnonHugePages: 50409472 kB

@ -10,7 +10,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net" "net"
"os" "os"
"strconv" "strconv"
@ -643,7 +642,7 @@ func (p *process) getUids(ctx context.Context) ([]int32, error) {
func (p *process) fillFromStatus(ctx context.Context) error { func (p *process) fillFromStatus(ctx context.Context) error {
pid := p.Pid pid := p.Pid
statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status") statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status")
contents, err := ioutil.ReadFile(statPath) contents, err := os.ReadFile(statPath)
if err != nil { if err != nil {
return err return err
} }
@ -784,7 +783,7 @@ func processInetWithContext(ctx context.Context, file string, kind netConnection
// This minimizes duplicates in the returned connections // This minimizes duplicates in the returned connections
// For more info: // For more info:
// https://github.com/shirou/gopsutil/pull/361 // https://github.com/shirou/gopsutil/pull/361
contents, err := ioutil.ReadFile(file) contents, err := os.ReadFile(file)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -845,7 +844,7 @@ func processUnix(file string, kind netConnectionKindType, inodes map[string][]in
// This minimizes duplicates in the returned connections // This minimizes duplicates in the returned connections
// For more info: // For more info:
// https://github.com/shirou/gopsutil/pull/361 // https://github.com/shirou/gopsutil/pull/361
contents, err := ioutil.ReadFile(file) contents, err := os.ReadFile(file)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -3,7 +3,6 @@ package net
import ( import (
"context" "context"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"strings" "strings"
@ -17,7 +16,7 @@ import (
func TestIOCountersByFileParsing(t *testing.T) { func TestIOCountersByFileParsing(t *testing.T) {
// Prpare a temporary file, which will be read during the test // Prpare a temporary file, which will be read during the test
tmpfile, err := ioutil.TempFile("", "proc_dev_net") tmpfile, err := os.CreateTemp("", "proc_dev_net")
defer os.Remove(tmpfile.Name()) // clean up defer os.Remove(tmpfile.Name()) // clean up
assert.Nil(t, err, "Temporary file creation failed: ", err) assert.Nil(t, err, "Temporary file creation failed: ", err)
@ -195,7 +194,7 @@ func TestReverse(t *testing.T) {
} }
func TestConntrackStatFileParsing(t *testing.T) { func TestConntrackStatFileParsing(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "proc_net_stat_conntrack") tmpfile, err := os.CreateTemp("", "proc_net_stat_conntrack")
defer os.Remove(tmpfile.Name()) defer os.Remove(tmpfile.Name())
assert.Nil(t, err, "Temporary file creation failed: ", err) assert.Nil(t, err, "Temporary file creation failed: ", err)

@ -23,6 +23,8 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) {
return IOCountersWithContext(context.Background(), pernic) return IOCountersWithContext(context.Background(), pernic)
} }
var kstatSplit = regexp.MustCompile(`[:\s]+`)
func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
// collect all the net class's links with below statistics // collect all the net class's links with below statistics
filterstr := "/^(?!vnic)/::phys:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/" filterstr := "/^(?!vnic)/::phys:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/"
@ -47,9 +49,8 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat,
odrops64arr := make(map[string]uint64) odrops64arr := make(map[string]uint64)
oerrorsarr := make(map[string]uint64) oerrorsarr := make(map[string]uint64)
re := regexp.MustCompile(`[:\s]+`)
for _, line := range lines { for _, line := range lines {
fields := re.Split(line, -1) fields := kstatSplit.Split(line, -1)
interfaceName := fields[0] interfaceName := fields[0]
instance := fields[1] instance := fields[1]
switch fields[3] { switch fields[3] {

@ -171,6 +171,13 @@ func (p NumCtxSwitchesStat) String() string {
return string(s) return string(s)
} }
var enableBootTimeCache bool
// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.
func EnableBootTimeCache(enable bool) {
enableBootTimeCache = enable
}
// Pids returns a slice of process ID list which are running now. // Pids returns a slice of process ID list which are running now.
func Pids() ([]int32, error) { func Pids() ([]int32, error) {
return PidsWithContext(context.Background()) return PidsWithContext(context.Background())

@ -286,11 +286,11 @@ func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
} }
func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
} }
func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, max)
} }
func ProcessesWithContext(ctx context.Context) ([]*Process, error) { func ProcessesWithContext(ctx context.Context) ([]*Process, error) {

@ -9,7 +9,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"math" "math"
"os" "os"
"path/filepath" "path/filepath"
@ -136,7 +135,7 @@ func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
pid := p.Pid pid := p.Pid
statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat") statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat")
contents, err := ioutil.ReadFile(statPath) contents, err := os.ReadFile(statPath)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -391,7 +390,7 @@ func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]M
smapsPath = smapsRollupPath smapsPath = smapsRollupPath
} }
} }
contents, err := ioutil.ReadFile(smapsPath) contents, err := os.ReadFile(smapsPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -484,7 +483,7 @@ func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]M
func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
environPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "environ") environPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "environ")
environContent, err := ioutil.ReadFile(environPath) environContent, err := os.ReadFile(environPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -668,7 +667,7 @@ func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) {
func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) { func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {
pid := p.Pid pid := p.Pid
cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath) cmdline, err := os.ReadFile(cmdPath)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -682,7 +681,7 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error
func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) { func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {
pid := p.Pid pid := p.Pid
cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath) cmdline, err := os.ReadFile(cmdPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -705,7 +704,7 @@ func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string
func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) { func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) {
pid := p.Pid pid := p.Pid
ioPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "io") ioPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "io")
ioline, err := ioutil.ReadFile(ioPath) ioline, err := os.ReadFile(ioPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -741,7 +740,7 @@ func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, e
func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) { func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) {
pid := p.Pid pid := p.Pid
memPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "statm") memPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "statm")
contents, err := ioutil.ReadFile(memPath) contents, err := os.ReadFile(memPath)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -802,7 +801,7 @@ func (p *Process) fillNameWithContext(ctx context.Context) error {
func (p *Process) fillFromCommWithContext(ctx context.Context) error { func (p *Process) fillFromCommWithContext(ctx context.Context) error {
pid := p.Pid pid := p.Pid
statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "comm") statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "comm")
contents, err := ioutil.ReadFile(statPath) contents, err := os.ReadFile(statPath)
if err != nil { if err != nil {
return err return err
} }
@ -819,7 +818,7 @@ func (p *Process) fillFromStatus() error {
func (p *Process) fillFromStatusWithContext(ctx context.Context) error { func (p *Process) fillFromStatusWithContext(ctx context.Context) error {
pid := p.Pid pid := p.Pid
statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status") statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status")
contents, err := ioutil.ReadFile(statPath) contents, err := os.ReadFile(statPath)
if err != nil { if err != nil {
return err return err
} }
@ -1026,7 +1025,7 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui
statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat") statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat")
} }
contents, err := ioutil.ReadFile(statPath) contents, err := os.ReadFile(statPath)
if err != nil { if err != nil {
return 0, 0, nil, 0, 0, 0, nil, err return 0, 0, nil, 0, 0, 0, nil, err
} }
@ -1072,7 +1071,7 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui
Iowait: iotime / float64(clockTicks), Iowait: iotime / float64(clockTicks),
} }
bootTime, _ := common.BootTimeWithContext(ctx) bootTime, _ := common.BootTimeWithContext(ctx, enableBootTimeCache)
t, err := strconv.ParseUint(fields[22], 10, 64) t, err := strconv.ParseUint(fields[22], 10, 64)
if err != nil { if err != nil {
return 0, 0, nil, 0, 0, 0, nil, err return 0, 0, nil, 0, 0, 0, nil, err

@ -6,7 +6,6 @@ package process
import ( import (
"context" "context"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@ -58,7 +57,7 @@ func Test_Process_splitProcStat(t *testing.T) {
} }
func Test_Process_splitProcStat_fromFile(t *testing.T) { func Test_Process_splitProcStat_fromFile(t *testing.T) {
pids, err := ioutil.ReadDir("testdata/linux/") pids, err := os.ReadDir("testdata/linux/")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -72,7 +71,7 @@ func Test_Process_splitProcStat_fromFile(t *testing.T) {
if _, err := os.Stat(statFile); err != nil { if _, err := os.Stat(statFile); err != nil {
continue continue
} }
contents, err := ioutil.ReadFile(statFile) contents, err := os.ReadFile(statFile)
assert.NoError(t, err) assert.NoError(t, err)
pidStr := strconv.Itoa(int(pid)) pidStr := strconv.Itoa(int(pid))
@ -94,7 +93,7 @@ func Test_Process_splitProcStat_fromFile(t *testing.T) {
} }
func Test_fillFromCommWithContext(t *testing.T) { func Test_fillFromCommWithContext(t *testing.T) {
pids, err := ioutil.ReadDir("testdata/linux/") pids, err := os.ReadDir("testdata/linux/")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -115,7 +114,7 @@ func Test_fillFromCommWithContext(t *testing.T) {
} }
func Test_fillFromStatusWithContext(t *testing.T) { func Test_fillFromStatusWithContext(t *testing.T) {
pids, err := ioutil.ReadDir("testdata/linux/") pids, err := os.ReadDir("testdata/linux/")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -154,7 +153,7 @@ func Benchmark_fillFromStatusWithContext(b *testing.B) {
} }
func Test_fillFromTIDStatWithContext_lx_brandz(t *testing.T) { func Test_fillFromTIDStatWithContext_lx_brandz(t *testing.T) {
pids, err := ioutil.ReadDir("testdata/lx_brandz/") pids, err := os.ReadDir("testdata/lx_brandz/")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

@ -0,0 +1,204 @@
//go:build openbsd && riscv64
// +build openbsd,riscv64
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs process/types_openbsd.go
package process
const (
CTLKern = 1
KernProc = 66
KernProcAll = 0
KernProcPID = 1
KernProcProc = 8
KernProcPathname = 12
KernProcArgs = 55
KernProcArgv = 1
KernProcEnv = 3
)
const (
ArgMax = 256 * 1024
)
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
)
const (
sizeOfKinfoVmentry = 0x50
sizeOfKinfoProc = 0x288
)
const (
SIDL = 1
SRUN = 2
SSLEEP = 3
SSTOP = 4
SZOMB = 5
SDEAD = 6
SONPROC = 7
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type Timespec struct {
Sec int64
Nsec int64
}
type Timeval struct {
Sec int64
Usec int64
}
type Rusage struct {
Utime Timeval
Stime Timeval
Maxrss int64
Ixrss int64
Idrss int64
Isrss int64
Minflt int64
Majflt int64
Nswap int64
Inblock int64
Oublock int64
Msgsnd int64
Msgrcv int64
Nsignals int64
Nvcsw int64
Nivcsw int64
}
type Rlimit struct {
Cur uint64
Max uint64
}
type KinfoProc struct {
Forw uint64
Back uint64
Paddr uint64
Addr uint64
Fd uint64
Stats uint64
Limit uint64
Vmspace uint64
Sigacts uint64
Sess uint64
Tsess uint64
Ru uint64
Eflag int32
Exitsig int32
Flag int32
Pid int32
Ppid int32
Sid int32
X_pgid int32
Tpgid int32
Uid uint32
Ruid uint32
Gid uint32
Rgid uint32
Groups [16]uint32
Ngroups int16
Jobc int16
Tdev uint32
Estcpu uint32
Rtime_sec uint32
Rtime_usec uint32
Cpticks int32
Pctcpu uint32
Swtime uint32
Slptime uint32
Schedflags int32
Uticks uint64
Sticks uint64
Iticks uint64
Tracep uint64
Traceflag int32
Holdcnt int32
Siglist int32
Sigmask uint32
Sigignore uint32
Sigcatch uint32
Stat int8
Priority uint8
Usrpri uint8
Nice uint8
Xstat uint16
Spare uint16
Comm [24]int8
Wmesg [8]uint8
Wchan uint64
Login [32]uint8
Vm_rssize int32
Vm_tsize int32
Vm_dsize int32
Vm_ssize int32
Uvalid int64
Ustart_sec uint64
Ustart_usec uint32
Uutime_sec uint32
Uutime_usec uint32
Ustime_sec uint32
Ustime_usec uint32
Uru_maxrss uint64
Uru_ixrss uint64
Uru_idrss uint64
Uru_isrss uint64
Uru_minflt uint64
Uru_majflt uint64
Uru_nswap uint64
Uru_inblock uint64
Uru_oublock uint64
Uru_msgsnd uint64
Uru_msgrcv uint64
Uru_nsignals uint64
Uru_nvcsw uint64
Uru_nivcsw uint64
Uctime_sec uint32
Uctime_usec uint32
Psflags uint32
Acflag uint32
Svuid uint32
Svgid uint32
Emul [8]uint8
Rlim_rss_cur uint64
Cpuid uint64
Vm_map_size uint64
Tid int32
Rtableid uint32
Pledge uint64
Name [24]uint8
}
type Priority struct{}
type KinfoVmentry struct {
Start uint64
End uint64
Guard uint64
Fspace uint64
Fspace_augment uint64
Offset uint64
Wired_count int32
Etype int32
Protection int32
Max_protection int32
Advice int32
Inheritance int32
Flags uint8
Pad_cgo_0 [7]byte
}

@ -3,7 +3,6 @@ package process
import ( import (
"bytes" "bytes"
"context" "context"
"io/ioutil"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@ -232,7 +231,7 @@ func (p *Process) fillFromPathAOutWithContext(ctx context.Context) (string, erro
func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, error) { func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, error) {
pid := p.Pid pid := p.Pid
execNamePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "execname") execNamePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "execname")
exe, err := ioutil.ReadFile(execNamePath) exe, err := os.ReadFile(execNamePath)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -242,7 +241,7 @@ func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, erro
func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) { func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {
pid := p.Pid pid := p.Pid
cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath) cmdline, err := os.ReadFile(cmdPath)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -259,7 +258,7 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error
func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) { func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {
pid := p.Pid pid := p.Pid
cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath) cmdline, err := os.ReadFile(cmdPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -4,7 +4,7 @@ import (
"bufio" "bufio"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io"
"net" "net"
"os" "os"
"os/exec" "os/exec"
@ -227,6 +227,11 @@ func Test_Process_NumCtx(t *testing.T) {
func Test_Process_Nice(t *testing.T) { func Test_Process_Nice(t *testing.T) {
p := testGetProcess() p := testGetProcess()
// https://github.com/shirou/gopsutil/issues/1532
if os.Getenv("CI") == "true" && runtime.GOOS == "darwin" {
t.Skip("Skip CI")
}
n, err := p.Nice() n, err := p.Nice()
skipIfNotImplementedErr(t, err) skipIfNotImplementedErr(t, err)
if err != nil { if err != nil {
@ -302,7 +307,7 @@ func Test_Process_Name(t *testing.T) {
} }
func Test_Process_Long_Name_With_Spaces(t *testing.T) { func Test_Process_Long_Name_With_Spaces(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "") tmpdir, err := os.MkdirTemp("", "")
if err != nil { if err != nil {
t.Fatalf("unable to create temp dir %v", err) t.Fatalf("unable to create temp dir %v", err)
} }
@ -348,7 +353,7 @@ func Test_Process_Long_Name_With_Spaces(t *testing.T) {
} }
func Test_Process_Long_Name(t *testing.T) { func Test_Process_Long_Name(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "") tmpdir, err := os.MkdirTemp("", "")
if err != nil { if err != nil {
t.Fatalf("unable to create temp dir %v", err) t.Fatalf("unable to create temp dir %v", err)
} }
@ -405,7 +410,7 @@ func Test_Process_Name_Against_Python(t *testing.T) {
t.Skipf("psutil not found for %s: %s", py3Path, out) t.Skipf("psutil not found for %s: %s", py3Path, out)
} }
tmpdir, err := ioutil.TempDir("", "") tmpdir, err := os.MkdirTemp("", "")
if err != nil { if err != nil {
t.Fatalf("unable to create temp dir %v", err) t.Fatalf("unable to create temp dir %v", err)
} }
@ -571,7 +576,7 @@ func Test_Connections(t *testing.T) {
defer conn.Close() defer conn.Close()
serverEstablished <- struct{}{} serverEstablished <- struct{}{}
_, err = ioutil.ReadAll(conn) _, err = io.ReadAll(conn)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -774,7 +779,7 @@ func Test_IsRunning(t *testing.T) {
} }
func Test_Process_Environ(t *testing.T) { func Test_Process_Environ(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "") tmpdir, err := os.MkdirTemp("", "")
if err != nil { if err != nil {
t.Fatalf("unable to create temp dir %v", err) t.Fatalf("unable to create temp dir %v", err)
} }

@ -253,7 +253,7 @@ func pidsWithContext(ctx context.Context) ([]int32, error) {
if err := windows.EnumProcesses(ps, &read); err != nil { if err := windows.EnumProcesses(ps, &read); err != nil {
return nil, err return nil, err
} }
if uint32(len(ps)) == read { // ps buffer was too small to host every results, retry with a bigger one if uint32(len(ps)) == read/dwordSize { // ps buffer was too small to host every results, retry with a bigger one
psSize += 1024 psSize += 1024
continue continue
} }

Loading…
Cancel
Save