pax_global_header00006660000000000000000000000064145540774720014531gustar00rootroot0000000000000052 comment=65b5fa32b9430e1969b688f837bf7467f2a03fac gopsutil-3.24.1/000077500000000000000000000000001455407747200134665ustar00rootroot00000000000000gopsutil-3.24.1/.github/000077500000000000000000000000001455407747200150265ustar00rootroot00000000000000gopsutil-3.24.1/.github/FUNDING.yml000066400000000000000000000000761455407747200166460ustar00rootroot00000000000000# These are supported funding model platforms github: shirou gopsutil-3.24.1/.github/ISSUE_TEMPLATE/000077500000000000000000000000001455407747200172115ustar00rootroot00000000000000gopsutil-3.24.1/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000015151455407747200217050ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve gopsutil --- **Describe the bug** [A clear and concise description of what the bug is.] **To Reproduce** ```go // paste example code reproducing the bug you are reporting ``` **Expected behavior** [A clear and concise description of what you expected to happen.] **Environment (please complete the following information):** - [ ] Windows: [paste the result of `ver`] - [ ] Linux: [paste contents of `/etc/os-release` and the result of `uname -a`] - [ ] Mac OS: [paste the result of `sw_vers` and `uname -a` - [ ] FreeBSD: [paste the result of `freebsd-version -k -r -u` and `uname -a`] - [ ] OpenBSD: [paste the result of `uname -a`] **Additional context** [Cross-compiling? Paste the command you are using to cross-compile and the result of the corresponding `go env`] gopsutil-3.24.1/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000010641455407747200227370ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for gopsutil --- **Is your feature request related to a problem? Please describe.** [A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]] **Describe the solution you'd like** [A clear and concise description of what you want to happen.] **Describe alternatives you've considered** [A clear and concise description of any alternative solutions or features you've considered.] **Additional context** [Add any other context or screenshots about the feature request here.] gopsutil-3.24.1/.github/SECURITY.md000066400000000000000000000013001455407747200166110ustar00rootroot00000000000000# Security Policy ## Supported Versions Security updates are applied only to the latest release. ## Reporting a Vulnerability If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. Please disclose it at [Security Advisories](https://github.com/shirou/gopsutil/security/advisories/new). This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerability reports will be investigated and fixed or disclosed as soon as possible. gopsutil-3.24.1/.github/dependabot.yml000066400000000000000000000002611455407747200176550ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: gomod directory: / schedule: interval: daily - package-ecosystem: github-actions directory: / schedule: interval: daily gopsutil-3.24.1/.github/labeler.yml000066400000000000000000000020021455407747200171510ustar00rootroot00000000000000package:cpu: - cpu/* package:disk: - disk/* package:docker: - docker/* package:host: - host/* package:load: - load/* package:mem: - mem/* package:net: - net/* package:process: - process/* package:winservices: - winservices/* os:linux: - ./**/*_linux.go - ./**/*_linux_mips64.go - ./**/*_linux_386.go - ./**/*_linux_test.go - ./**/*_linux_s390x.go - ./**/*_linux_amd64.go - ./**/*_posix.go os:freebsd: - ./**/*_freebsd.go - ./**/*_freebsd_386.go - ./**/*_freebsd_test.go - ./**/*_freebsd_amd64.go - ./**/*_bsd.go - ./**/*_posix.go os:darwin: - ./**/*_darwin.go - ./**/*_darwin_386.go - ./**/*_darwin_test.go - ./**/*_darwin_amd64.go - ./**/*_posix.go os:openbsd: - ./**/*_openbsd.go - ./**/*_openbsd_386.go - ./**/*_openbsd_test.go - ./**/*_openbsd_amd64.go - ./**/*_bsd.go - ./**/*_posix.go os:windows: - ./**/*_windows.go - ./**/*_windows_386.go - ./**/*_windows_test.go - ./**/*_windows_amd64.go os:solaris: - ./**/*_solaris.go - ./**/*_posix.go gopsutil-3.24.1/.github/release.yml000066400000000000000000000013401455407747200171670ustar00rootroot00000000000000changelog: exclude: labels: - ignore-for-release - dependencies authors: - dependabot[bot] categories: - title: "cpu" labels: - "package:cpu" - title: "disk" labels: - "package:disk" - title: "docker" labels: - "package:docker" - title: "host" labels: - "package:host" - title: "load" labels: - "package:load" - title: "mem" labels: - "package:mem" - title: "net" labels: - "package:net" - title: "process" labels: - "package:process" - title: "winservices" labels: - "package:winservices" - title: Other Changes labels: - "*"gopsutil-3.24.1/.github/workflows/000077500000000000000000000000001455407747200170635ustar00rootroot00000000000000gopsutil-3.24.1/.github/workflows/build_test.yml000066400000000000000000000025701455407747200217500ustar00rootroot00000000000000on: [push, pull_request] name: Build Test permissions: contents: read jobs: go-versions: runs-on: ubuntu-latest outputs: versions: ${{ steps.versions.outputs.value }} steps: - id: versions run: | versions=$(curl -s 'https://go.dev/dl/?mode=json' | jq -c 'map(.version[2:])') echo "::set-output name=value::${versions}" build_test_v3: needs: go-versions strategy: fail-fast: false matrix: go-version: ${{fromJson(needs.go-versions.outputs.versions)}} runs-on: ubuntu-22.04 steps: - name: Install Go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - 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@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.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 gopsutil-3.24.1/.github/workflows/labeler.yml000066400000000000000000000006711455407747200212200ustar00rootroot00000000000000name: "Pull Request Labeler" on: - pull_request_target permissions: contents: read jobs: triage: permissions: contents: read # for actions/labeler to determine modified files 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 }}" gopsutil-3.24.1/.github/workflows/lint.yml000066400000000000000000000014271455407747200205600ustar00rootroot00000000000000name: Golangci-lint on: push: pull_request: permissions: contents: read jobs: golangci: 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: ubuntu-latest steps: - name: Setup go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: 1.17 cache: false - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup golangci-lint uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: args: --verbose version: latest gopsutil-3.24.1/.github/workflows/release.yml000066400000000000000000000004731455407747200212320ustar00rootroot00000000000000on: schedule: - cron: '0 1 1 * *' # UTC 01:00 on the first day of the Month name: Release permissions: contents: write jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Release run: make release gopsutil-3.24.1/.github/workflows/sbom_generator.yml000066400000000000000000000011261455407747200226140ustar00rootroot00000000000000name: SBOM Generator on: push: branches: [ "master" ] workflow_dispatch: permissions: read-all jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - uses: advanced-security/sbom-generator-action@375dee8e6144d9fd0ec1f5667b4f6fb4faacefed # v0.0.1 id: sbom env: GITHUB_TOKEN: ${{ github.token }} - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 with: path: ${{steps.sbom.outputs.fileName }} name: "SBOM" gopsutil-3.24.1/.github/workflows/shellcheck.yml000066400000000000000000000005321455407747200217130ustar00rootroot00000000000000on: [push, pull_request] name: Shellcheck permissions: contents: read jobs: shellcheck: name: Shellcheck runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run ShellCheck uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 gopsutil-3.24.1/.github/workflows/test.yml000066400000000000000000000027451455407747200205750ustar00rootroot00000000000000on: [push, pull_request] name: Test permissions: contents: read jobs: go-versions: runs-on: ubuntu-latest outputs: versions: ${{ steps.versions.outputs.value }} steps: - id: versions run: | versions=$(curl -s 'https://go.dev/dl/?mode=json' | jq -c 'map(.version[2:])') echo "::set-output name=value::${versions}" test_v3_module: needs: go-versions strategy: fail-fast: false matrix: go-version: ${{fromJson(needs.go-versions.outputs.versions)}} os: [ubuntu-22.04, ubuntu-20.04, windows-2022, windows-2019, macos-11, macos-12] runs-on: ${{ matrix.os }} steps: - name: Install Go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - 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@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.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 ./... gopsutil-3.24.1/.gitignore000066400000000000000000000000361455407747200154550ustar00rootroot00000000000000*~ #* _obj *.tmp .idea vendor gopsutil-3.24.1/.golangci.yml000066400000000000000000000020021455407747200160440ustar00rootroot00000000000000issues: max-same-issues: 0 exclude-rules: - linters: - gosec text: "G204" - linters: - revive text: "var-naming" - linters: - revive text: "exported" - linters: - revive text: "empty-block" - linters: - revive text: "unused-parameter" linters: enable: - asciicheck - contextcheck - durationcheck - errorlint - gci - gofmt - gofumpt - goimports - gomodguard - gosec - gosimple - importas - megacheck - misspell - nakedret - nolintlint - predeclared - revive - typecheck - unparam disable: - deadcode - errcheck - govet - ineffassign - staticcheck - structcheck - unused - varcheck linters-settings: gci: sections: - standard - default - prefix(github.com/shirou) gomodguard: blocked: modules: - io/ioutil: recommandations: - io - os gopsutil-3.24.1/LICENSE000066400000000000000000000061131455407747200144740ustar00rootroot00000000000000gopsutil is distributed under BSD license reproduced below. Copyright (c) 2014, WAKAYAMA Shirou All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the gopsutil authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------- internal/common/binary.go in the gopsutil is copied and modified from golang/encoding/binary.go. Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.gopsutil-3.24.1/Makefile000066400000000000000000000065061455407747200151350ustar00rootroot00000000000000.PHONY: help check .DEFAULT_GOAL := help SUBPKGS=cpu disk docker host internal load mem net process help: ## Show help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' check: ## Check errcheck -ignore="Close|Run|Write" ./... golint ./... | egrep -v 'underscores|HttpOnly|should have comment|comment on exported|CamelCase|VM|UID' && exit 1 || exit 0 BUILD_FAIL_PATTERN=grep -v "exec format error" | grep "build failed" && exit 1 || exit 0 build_test: ## test only buildable # Supported operating systems GOOS=linux GOARCH=amd64 go test ./... | $(BUILD_FAIL_PATTERN) GOOS=linux GOARCH=386 go test ./... | $(BUILD_FAIL_PATTERN) GOOS=linux GOARCH=arm go test ./... | $(BUILD_FAIL_PATTERN) GOOS=linux GOARCH=arm64 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=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=386 go test ./... | $(BUILD_FAIL_PATTERN) GOOS=freebsd GOARCH=arm go test ./... | $(BUILD_FAIL_PATTERN) GOOS=freebsd GOARCH=arm64 go test ./... | $(BUILD_FAIL_PATTERN) CGO_ENABLED=0 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN) GOOS=windows go test ./... | $(BUILD_FAIL_PATTERN) # Operating systems supported for building only (not implemented error if used) GOOS=solaris go test ./... | $(BUILD_FAIL_PATTERN) GOOS=dragonfly go test ./... | $(BUILD_FAIL_PATTERN) GOOS=netbsd go test ./... | $(BUILD_FAIL_PATTERN) # cross build to OpenBSD not worked since process has "C" # GOOS=openbsd go test ./... | $(BUILD_FAIL_PATTERN) GOOS=plan9 go test ./... | $(BUILD_FAIL_PATTERN) ifeq ($(shell uname -s), Darwin) CGO_ENABLED=1 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN) endif @echo 'Successfully built on all known operating systems' vet: GOOS=darwin GOARCH=amd64 go vet ./... GOOS=darwin GOARCH=arm64 go vet ./... GOOS=dragonfly GOARCH=amd64 go vet ./... GOOS=freebsd GOARCH=amd64 go vet ./... GOOS=freebsd GOARCH=386 go vet ./... GOOS=freebsd GOARCH=arm go vet ./... GOOS=linux GOARCH=386 go vet ./... GOOS=linux GOARCH=amd64 go vet ./... GOOS=linux GOARCH=arm64 go vet ./... GOOS=linux GOARCH=arm go vet ./... GOOS=linux GOARCH=loong64 go vet ./... GOOS=linux GOARCH=mips64 go vet ./... GOOS=linux GOARCH=mips64le go vet ./... GOOS=linux GOARCH=mips go vet ./... GOOS=linux GOARCH=mipsle go vet ./... GOOS=linux GOARCH=ppc64le go vet ./... GOOS=linux GOARCH=ppc64 go vet ./... GOOS=linux GOARCH=riscv64 go vet ./... GOOS=linux GOARCH=s390x go vet ./... GOOS=netbsd GOARCH=amd64 go vet ./... GOOS=openbsd GOARCH=386 go vet ./... GOOS=openbsd GOARCH=amd64 go vet ./... GOOS=solaris GOARCH=amd64 go vet ./... GOOS=windows GOARCH=amd64 go vet ./... GOOS=windows GOARCH=386 go vet ./... GOOS=plan9 GOARCH=amd64 go vet ./... GOOS=plan9 GOARCH=386 go vet ./... macos_test: CGO_ENABLED=0 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN) CGO_ENABLED=1 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN) init_tools: go get github.com/golang/dep/cmd/dep TAG=$(shell date +'v3.%y.%-m' --date='last Month') release: git tag $(TAG) git push origin $(TAG) gopsutil-3.24.1/README.md000066400000000000000000000335521455407747200147550ustar00rootroot00000000000000# gopsutil: psutil for golang [![Test](https://github.com/shirou/gopsutil/actions/workflows/test.yml/badge.svg)](https://github.com/shirou/gopsutil/actions/workflows/test.yml) [![Coverage Status](https://coveralls.io/repos/github/shirou/gopsutil/badge.svg?branch=master)](https://coveralls.io/github/shirou/gopsutil?branch=master) [![Go Reference](https://pkg.go.dev/badge/github.com/shirou/gopsutil/v3.svg)](https://pkg.go.dev/github.com/shirou/gopsutil/v3) [![Go Documentation](https://godocs.io/github.com/shirou/gopsutil/v3?status.svg)](https://godocs.io/github.com/shirou/gopsutil/v3) [![Calendar Versioning](https://img.shields.io/badge/calver-vMAJOR.YY.MM-22bfda.svg)](https://calver.org/) This is a port of psutil (https://github.com/giampaolo/psutil). The challenge is porting all psutil functions on some architectures. ## v3 migration From v3.20.10, gopsutil becomes v3 which breaks backwards compatibility. See [v3Changes.md](_tools/v3migration/v3Changes.md) for more detailed changes. ## Tag semantics gopsutil tag policy is almost same as Semantic Versioning, but automatically increases like [Ubuntu versioning](https://calver.org/). For example, v2.17.04 means - v2: major version - 17: release year, 2017 - 04: release month gopsutil aims to keep backwards compatibility until major version change. Tagged at every end of month, but if there are only a few commits, it can be skipped. ## Available Architectures - FreeBSD i386/amd64/arm - Linux i386/amd64/arm(raspberry pi) - Windows i386/amd64/arm/arm64 - Darwin amd64/arm64 - OpenBSD amd64 (Thank you @mpfz0r!) - Solaris amd64 (developed and tested on SmartOS/Illumos, Thank you @jen20!) These have partial support: - CPU on DragonFly BSD (#893, Thank you @gballet!) - host on Linux RISC-V (#896, Thank you @tklauser!) All works are implemented without cgo by porting C structs to golang structs. ## Usage ```go package main import ( "fmt" "github.com/shirou/gopsutil/v3/mem" // "github.com/shirou/gopsutil/mem" // to use v2 ) func main() { v, _ := mem.VirtualMemory() // almost every return value is a struct fmt.Printf("Total: %v, Free:%v, UsedPercent:%f%%\n", v.Total, v.Free, v.UsedPercent) // convert to JSON. String() is also implemented fmt.Println(v) } ``` The output is below. Total: 3179569152, Free:284233728, UsedPercent:84.508194% {"total":3179569152,"available":492572672,"used":2895335424,"usedPercent":84.50819439828305, (snip...)} You can set an alternative location to `/proc` by setting the `HOST_PROC` environment variable. You can set an alternative location to `/sys` by setting the `HOST_SYS` environment variable. You can set an alternative location to `/etc` by setting the `HOST_ETC` environment variable. You can set an alternative location to `/var` by setting the `HOST_VAR` environment variable. You can set an alternative location to `/run` by setting the `HOST_RUN` environment variable. You can set an alternative location to `/dev` by setting the `HOST_DEV` environment variable. You can set an alternative location to `/` by setting the `HOST_ROOT` environment variable. You can set an alternative location to `/proc/N/mountinfo` by setting the `HOST_PROC_MOUNTINFO` environment variable. ### Adding settings using `context` (from v3.23.6) As of v3.23.6, it is now possible to pass a path location using `context`: import `"github.com/shirou/gopsutil/v3/common"` and pass a context with `common.EnvMap` set to `common.EnvKey`, and the location will be used within each function. ``` ctx := context.WithValue(context.Background(), common.EnvKey, common.EnvMap{common.HostProcEnvKey: "/myproc"}, ) v, err := mem.VirtualMemoryWithContext(ctx) ``` 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 See https://pkg.go.dev/github.com/shirou/gopsutil/v3 or https://godocs.io/github.com/shirou/gopsutil/v3 ## Requirements - go1.16 or above is required. ## More Info Several methods have been added which are not present in psutil, but will provide useful information. - host/HostInfo() (linux) - Hostname - Uptime - Procs - OS (ex: "linux") - Platform (ex: "ubuntu", "arch") - PlatformFamily (ex: "debian") - PlatformVersion (ex: "Ubuntu 13.10") - VirtualizationSystem (ex: "LXC") - VirtualizationRole (ex: "guest"/"host") - IOCounters - Label (linux only) The registered [device mapper name](https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm) - cpu/CPUInfo() (linux, freebsd) - CPU (ex: 0, 1, ...) - VendorID (ex: "GenuineIntel") - Family - Model - Stepping - PhysicalID - CoreID - Cores (ex: 2) - ModelName (ex: "Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz") - Mhz - CacheSize - Flags (ex: "fpu vme de pse tsc msr pae mce cx8 ...") - Microcode - load/Avg() (linux, freebsd, solaris) - Load1 - Load5 - Load15 - docker/GetDockerIDList() (linux only) - container id list ([]string) - docker/CgroupCPU() (linux only) - user - system - docker/CgroupMem() (linux only) - various status - net_protocols (linux only) - system wide stats on network protocols (i.e IP, TCP, UDP, etc.) - sourced from /proc/net/snmp - iptables nf_conntrack (linux only) - system wide stats on netfilter conntrack module - sourced from /proc/sys/net/netfilter/nf_conntrack_count Some code is ported from Ohai. Many thanks. ## Current Status - x: works - b: almost works, but something is broken |name |Linux |FreeBSD |OpenBSD |macOS |Windows |Solaris |Plan 9 | |----------------------|-------|---------|---------|--------|---------|---------|---------| |cpu\_times |x |x |x |x |x | |b | |cpu\_count |x |x |x |x |x | |x | |cpu\_percent |x |x |x |x |x | | | |cpu\_times\_percent |x |x |x |x |x | | | |virtual\_memory |x |x |x |x |x | b |x | |swap\_memory |x |x |x |x | | |x | |disk\_partitions |x |x |x |x |x | | | |disk\_io\_counters |x |x |x | | | | | |disk\_usage |x |x |x |x |x | | | |net\_io\_counters |x |x |x |b |x | | | |boot\_time |x |x |x |x |x | | | |users |x |x |x |x |x | | | |pids |x |x |x |x |x | | | |pid\_exists |x |x |x |x |x | | | |net\_connections |x |x |x |x | | | | |net\_protocols |x | | | | | | | |net\_if\_addrs | | | | | | | | |net\_if\_stats | | | | | | | | |netfilter\_conntrack |x | | | | | | | ### Process class |name |Linux |FreeBSD |OpenBSD |macOS |Windows | |--------------------|-------|---------|---------|-------|---------| |pid |x |x |x |x |x | |ppid |x |x |x |x |x | |name |x |x |x |x |x | |cmdline |x |x | |x |x | |create\_time |x | | |x |x | |status |x |x |x |x | | |cwd |x | | |x | | |exe |x |x |x | |x | |uids |x |x |x |x | | |gids |x |x |x |x | | |terminal |x |x |x | | | |io\_counters |x |x |x | |x | |nice |x |x |x |x |x | |num\_fds |x | | | | | |num\_ctx\_switches |x | | | | | |num\_threads |x |x |x |x |x | |cpu\_times |x | | | |x | |memory\_info |x |x |x |x |x | |memory\_info\_ex |x | | | | | |memory\_maps |x | | | | | |open\_files |x | | | | | |send\_signal |x |x |x |x | | |suspend |x |x |x |x | | |resume |x |x |x |x | | |terminate |x |x |x |x |x | |kill |x |x |x |x | | |username |x |x |x |x |x | |ionice | | | | | | |rlimit |x | | | | | |num\_handlers | | | | | | |threads |x | | | | | |cpu\_percent |x | |x |x |x | |cpu\_affinity | | | | | | |memory\_percent |x | | | |x | |parent |x | |x |x |x | |children |x |x |x |x |x | |connections |x | |x |x | | |is\_running | | | | | | |page\_faults |x | | | | | ### Original Metrics |item |Linux |FreeBSD |OpenBSD |macOS |Windows |Solaris | |-----------------|-------|---------|---------|--------|--------|---------| |**HostInfo** | | | | | | | |hostname |x |x |x |x |x |x | |uptime |x |x |x |x | |x | |process |x |x |x | | |x | |os |x |x |x |x |x |x | |platform |x |x |x |x | |x | |platformfamily |x |x |x |x | |x | |virtualization |x | | | | | | |**CPU** | | | | | | | |VendorID |x |x |x |x |x |x | |Family |x |x |x |x |x |x | |Model |x |x |x |x |x |x | |Stepping |x |x |x |x |x |x | |PhysicalID |x | | | | |x | |CoreID |x | | | | |x | |Cores |x | | | |x |x | |ModelName |x |x |x |x |x |x | |Microcode |x | | | | |x | |**LoadAvg** | | | | | | | |Load1 |x |x |x |x | | | |Load5 |x |x |x |x | | | |Load15 |x |x |x |x | | | |**GetDockerID** | | | | | | | |container id |x |no |no |no |no | | |**CgroupsCPU** | | | | | | | |user |x |no |no |no |no | | |system |x |no |no |no |no | | |**CgroupsMem** | | | | | | | |various |x |no |no |no |no | | - future work - process_iter - wait_procs - Process class - as_dict - wait ## License New BSD License (same as psutil) ## Related Works I have been influenced by the following great works: - psutil: https://github.com/giampaolo/psutil - dstat: https://github.com/dagwieers/dstat - gosigar: https://github.com/cloudfoundry/gosigar/ - goprocinfo: https://github.com/c9s/goprocinfo - go-ps: https://github.com/mitchellh/go-ps - ohai: https://github.com/opscode/ohai/ - bosun: https://github.com/bosun-monitor/bosun/tree/master/cmd/scollector/collectors - mackerel: https://github.com/mackerelio/mackerel-agent/tree/master/metrics ## How to Contribute 1. Fork it 2. Create your feature branch (git checkout -b my-new-feature) 3. Commit your changes (git commit -am 'Add some feature') 4. Push to the branch (git push origin my-new-feature) 5. Create new Pull Request English is not my native language, so PRs correcting grammar or spelling are welcome and appreciated. gopsutil-3.24.1/_tools/000077500000000000000000000000001455407747200147655ustar00rootroot00000000000000gopsutil-3.24.1/_tools/v3migration/000077500000000000000000000000001455407747200172275ustar00rootroot00000000000000gopsutil-3.24.1/_tools/v3migration/v3Changes.md000066400000000000000000000030271455407747200213740ustar00rootroot00000000000000# v2 to v3 changes - v3 is in the `v3` directory - [process] RLimit is now uint64 ([#364](https://github.com/shirou/gopsutil/issues/364)) - [process] Remove process.NetIOCounters ([#429](https://github.com/shirou/gopsutil/issues/429)) - [docker] fix typo of memoryLimitInBbytes ([#464](https://github.com/shirou/gopsutil/issues/464)) - [mem] VirtualMemoryStat JSON fields capitalization ([#545](https://github.com/shirou/gopsutil/issues/545)) - various JSON field name and some of Variable name have been changed. see v3migration.sh - [all] various kind of platform dependent values/constants such as process.GetWin32Proc is now private. see v3migration.sh - [process] process.Status() now returns []string. and status string is "Running", not just "R". defined in process.go. ([#596](https://github.com/shirou/gopsutil/issues/596)) - [docker] `CgroupCPU()` now returns `*CgroupCPUStat` with Usage ([#590](https://github.com/shirou/gopsutil/issues/590) and [#581](https://github.com/shirou/gopsutil/issues/581)) - [disk] `disk.Opts` is now string[], not string. (related to [#955](https://github.com/shirou/gopsutil/issues/955)) - [host] Fixed temperature sensors detection in Linux ([#905](https://github.com/shirou/gopsutil/issues/905)) - [disk] `GetDiskSerialNumber()` is now `SerialNumber()` and spread to all platforms - [disk] `GetLabel ()` is now `Label()` and spread to all platform - [net] Change net.InterfaceStat.Addrs to InterfaceAddrList ([#226](https://github.com/shirou/gopsutil/issues/226)) - [cpu] Removed windows-specific `ProcInfo()` gopsutil-3.24.1/_tools/v3migration/v3migration.go000066400000000000000000000044171455407747200220260ustar00rootroot00000000000000package main import ( "flag" "fmt" "go/ast" "go/format" "go/parser" "go/token" "log" "os" "golang.org/x/tools/go/ast/astutil" ) // https://github.com/shirou/gopsutil/issues/429 func issue429() error { f := func(filename string) error { fset := token.NewFileSet() expr, err := parser.ParseFile(fset, filename, nil, parser.ParseComments) if err != nil { return err } n := astutil.Apply(expr, func(cr *astutil.Cursor) bool { if cr.Name() == "Decls" { switch n := cr.Node().(type) { case *ast.FuncDecl: if n.Name.Name == "NetIOCounters" || n.Name.Name == ("NetIOCountersWithContext") { cr.Delete() } } } return true }, nil) return replace(filename, fset, n) } root := "process/" fnames := []string{"process.go", "process_darwin.go", "process_fallback.go", "process_freebsd.go", "process_linux.go", "process_openbsd.go", "process_bsd.go", "process_posix.go", "process_windows.go", "process_test.go"} for _, fname := range fnames { if err := f(root + fname); err != nil { log.Fatalln("run 429:", err) } } return nil } func issueRemoveUnusedValue() error { f := func(filename string) error { fset := token.NewFileSet() expr, err := parser.ParseFile(fset, filename, nil, parser.ParseComments) if err != nil { return err } n := astutil.Apply(expr, func(cr *astutil.Cursor) bool { if cr.Name() == "Decls" { switch n := cr.Node().(type) { case *ast.GenDecl: if n.Tok != token.TYPE { break } ts := n.Specs[0].(*ast.TypeSpec) if ts.Name.Name == "SystemProcessInformation" { cr.Delete() } } } return true }, nil) return replace(filename, fset, n) } if err := f("process/process_windows.go"); err != nil { log.Fatalln("run 429:", err) } return nil } func replace(filename string, fset *token.FileSet, n ast.Node) error { if err := os.Remove(filename); err != nil { return err } fp, err := os.Create(filename) if err != nil { return err } defer fp.Close() if err := format.Node(fp, fset, n); err != nil { return err } fp.WriteString("\n") return nil } func main() { flag.Parse() for _, n := range flag.Args() { fmt.Println("issue:" + n) switch n { case "429": issue429() case "issueRemoveUnusedValue": issueRemoveUnusedValue() } } } gopsutil-3.24.1/_tools/v3migration/v3migration.sh000066400000000000000000000142111455407747200220240ustar00rootroot00000000000000#!/usr/bin/env bash set -eu # this scripts is used when migrating v2 to v3. # usage: cd ${GOPATH}/src/github.com/shirou/gopsutil && bash tools/v3migration/v3migration.sh DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)" ROOT=$(cd "${DIR}"/../.. && pwd) ## 1. refresh cd "${ROOT}" /bin/rm -rf v3 ## 2. copy directories # docker is removed, #464 will be fixed mkdir -p v3 cp -rp cpu disk docker host internal load mem net process winservices v3 cp Makefile v3 # build migartion tool go build -o v3/v3migration "${DIR}"/v3migration.go V3DIR=$(cd "${ROOT}"/v3 && pwd) cd "${V3DIR}" ## 3. mod go mod init ### change import path find . -name "*.go" -print0 | xargs -0 -I@ sed -i 's|"github.com/shirou/gopsutil/|"github.com/shirou/gopsutil/v3/|g' @ ############ Issues # #429 process.NetIOCounters is pointless on Linux ./v3migration "$(pwd)" 429 sed -i '/NetIOCounters/d' process/process.go sed -i "/github.com\/shirou\/gopsutil\/v3\/net/d" process/process_bsd.go # #464 CgroupMem : fix typo and wrong file names sed -i 's|memoryLimitInBbytes|memoryLimitInBytes|g' docker/docker.go sed -i 's|memoryLimitInBbytes|memory.limit_in_bytes|g' docker/docker_linux.go sed -i 's|memoryFailcnt|memory.failcnt|g' docker/docker_linux.go # fix #346 sed -i 's/Soft int32/Soft uint64/' process/process.go sed -i 's/Hard int32/Hard uint64/' process/process.go sed -i 's| //TODO too small. needs to be uint64||' process/process.go sed -i 's|limitToInt(val string) (int32, error)|limitToUint(val string) (uint64, error)|' process/process_*.go sed -i 's|limitToInt|limitToUint|' process/process_*.go sed -i 's|return int32(res), nil|return uint64(res), nil|' process/process_*.go sed -i 's|math.MaxInt32|math.MaxUint64|' process/process_*.go # fix #545 # variable names sed -i 's|WritebackTmp|WriteBackTmp|g' mem/*.go sed -i 's|Writeback|WriteBack|g' mem/*.go sed -i 's|SReclaimable|Sreclaimable|g' mem/*.go sed -i 's|SUnreclaim|Sunreclaim|g' mem/*.go sed -i 's|VMallocTotal|VmallocTotal|g' mem/*.go sed -i 's|VMallocUsed|VmallocUsed|g' mem/*.go sed -i 's|VMallocChunk|VmallocChunk|g' mem/*.go # json field name sed -i 's|hostid|hostId|g' host/host.go sed -i 's|hostid|hostId|g' host/host_test.go sed -i 's|sensorTemperature|temperature|g' host/host.go sed -i 's|sensorTemperature|temperature|g' host/host_test.go sed -i 's|writeback|writeBack|g' mem/*.go sed -i 's|writeBacktmp|writeBackTmp|g' mem/*.go sed -i 's|pagetables|pageTables|g' mem/*.go sed -i 's|swapcached|swapCached|g' mem/*.go sed -i 's|commitlimit|commitLimit|g' mem/*.go sed -i 's|committedas|committedAS|g' mem/*.go sed -i 's|hightotal|highTotal|g' mem/*.go sed -i 's|highfree|highFree|g' mem/*.go sed -i 's|lowtotal|lowTotal|g' mem/*.go sed -i 's|lowfree|lowFree|g' mem/*.go sed -i 's|swaptotal|swapTotal|g' mem/*.go sed -i 's|swapfree|swapFree|g' mem/*.go sed -i 's|vmalloctotal|vmallocTotal|g' mem/*.go sed -i 's|vmallocused|vmallocUsed|g' mem/*.go sed -i 's|vmallocchunk|vmallocChunk|g' mem/*.go sed -i 's|hugepagestotal|hugePagesTotal|g' mem/*.go sed -i 's|hugepagesfree|hugePagesFree|g' mem/*.go sed -i 's|hugepagesize|hugePageSize|g' mem/*.go sed -i 's|pgin|pgIn|g' mem/*.go sed -i 's|pgout|pgOut|g' mem/*.go sed -i 's|pgfault|pgFault|g' mem/*.go sed -i 's|pgmajfault|pgMajFault|g' mem/*.go sed -i 's|hardwareaddr|hardwareAddr|g' net/*.go sed -i 's|conntrackCount|connTrackCount|g' net/*.go sed -i 's|conntrackMax|connTrackMax|g' net/*.go sed -i 's|delete_list|deleteList|g' net/*.go sed -i 's|insert_failed|insertFailed|g' net/*.go sed -i 's|early_drop|earlyDrop|g' net/*.go sed -i 's|expect_create|expectCreate|g' net/*.go sed -i 's|expect_delete|expectDelete|g' net/*.go sed -i 's|search_restart|searchRestart|g' net/*.go sed -i 's|icmp_error|icmpError|g' net/*.go sed -i 's|expect_new|expectNew|g' net/*.go # fix no more public API/types/constants defined only for some platforms sed -i 's|CTLKern|ctlKern|g' cpu/*.go sed -i 's|CPNice|cpNice|g' cpu/*.go sed -i 's|CPSys|cpSys|g' cpu/*.go sed -i 's|CPIntr|cpIntr|g' cpu/*.go sed -i 's|CPIdle|cpIdle|g' cpu/*.go sed -i 's|CPUStates|cpUStates|g' cpu/*.go sed -i 's|CTLKern|ctlKern|g' cpu/cpu_openbsd.go sed -i 's|CTLHw|ctlHw|g' cpu/cpu_openbsd.go sed -i 's|SMT|sMT|g' cpu/cpu_openbsd.go sed -i 's|KernCptime|kernCptime|g' cpu/cpu_openbsd.go sed -i 's|KernCptime2|kernCptime2|g' cpu/cpu_openbsd.go sed -i 's|Win32_Processor|win32Processor|g' cpu/cpu_windows.go sed -i 's|DEVSTAT_NO_DATA|devstat_NO_DATA|g' disk/*.go sed -i 's|DEVSTAT_READ|devstat_READ|g' disk/*.go sed -i 's|DEVSTAT_WRITE|devstat_WRITE|g' disk/*.go sed -i 's|DEVSTAT_FREE|devstat_FREE|g' disk/*.go sed -i 's|Devstat|devstat|g' disk/*.go sed -i 's|Bintime|bintime|g' disk/*.go sed -i 's|SectorSize|sectorSize|g' disk/disk_linux.go sed -i 's|FileFileCompression|fileFileCompression|g' disk/disk_windows.go sed -i 's|FileReadOnlyVolume|fileReadOnlyVolume|g' disk/disk_windows.go sed -i 's|USER_PROCESS|user_PROCESS|g' host/host_*.go sed -i 's|LSB|lsbStruct|g' host/host_linux* sed -i 's| BcacheStats | bcacheStats |g' mem/*.go sed -i 's|TCPStatuses|tcpStatuses|g' net/*.go sed -i 's|CT_ENTRIES|ctENTRIES|g' net/net_linux.go sed -i 's|CT_SEARCHED|ctSEARCHED|g' net/net_linux.go sed -i 's|CT_FOUND|ctFOUND|g' net/net_linux.go sed -i 's|CT_NEW|ctNEW|g' net/net_linux.go sed -i 's|CT_INVALID|ctINVALID|g' net/net_linux.go sed -i 's|CT_IGNORE|ctIGNORE|g' net/net_linux.go sed -i 's|CT_DELETE|ctDELETE|g' net/net_linux.go sed -i 's|CT_DELETE_LIST|ctDELETE_LIST|g' net/net_linux.go sed -i 's|CT_INSERT|ctINSERT|g' net/net_linux.go sed -i 's|CT_INSERT_FAILED|ctINSERT_FAILED|g' net/net_linux.go sed -i 's|CT_DROP|ctDROP|g' net/net_linux.go sed -i 's|CT_EARLY_DROP|ctEARLY_DROP|g' net/net_linux.go sed -i 's|CT_ICMP_ERROR|ctICMP_ERROR|g' net/net_linux.go sed -i 's|CT_EXPECT_NEW|ctEXPECT_NEW|g' net/net_linux.go sed -i 's|CT_EXPECT_CREATE|ctEXPECT_CREATE|g' net/net_linux.go sed -i 's|CT_EXPECT_DELETE|ctEXPECT_DELETE|g' net/net_linux.go sed -i 's|CT_SEARCH_RESTART|ctSEARCH_RESTART|g' net/net_linux.go sed -i 's|PageSize|pageSize|g' process/process_*.go sed -i 's|PrioProcess|prioProcess|g' process/process_*.go sed -i 's|ClockTicks|clockTicks|g' process/process_*.go ./v3migration "$(pwd)" issueRemoveUnusedValue ############ SHOULD BE FIXED BY HAND gopsutil-3.24.1/common/000077500000000000000000000000001455407747200147565ustar00rootroot00000000000000gopsutil-3.24.1/common/env.go000066400000000000000000000013031455407747200160720ustar00rootroot00000000000000package common type EnvKeyType string // EnvKey is a context key that can be used to set programmatically the environment // gopsutil relies on to perform calls against the OS. // Example of use: // // ctx := context.WithValue(context.Background(), common.EnvKey, EnvMap{common.HostProcEnvKey: "/myproc"}) // avg, err := load.AvgWithContext(ctx) var EnvKey = EnvKeyType("env") const ( HostProcEnvKey EnvKeyType = "HOST_PROC" HostSysEnvKey EnvKeyType = "HOST_SYS" HostEtcEnvKey EnvKeyType = "HOST_ETC" HostVarEnvKey EnvKeyType = "HOST_VAR" HostRunEnvKey EnvKeyType = "HOST_RUN" HostDevEnvKey EnvKeyType = "HOST_DEV" HostRootEnvKey EnvKeyType = "HOST_ROOT" ) type EnvMap map[EnvKeyType]string gopsutil-3.24.1/coverall.sh000066400000000000000000000011071455407747200156300ustar00rootroot00000000000000#!/bin/sh # see http://www.songmu.jp/riji/entry/2015-01-15-goveralls-multi-package.html set -e # cleanup cleanup() { if [ "$tmpprof" != "" ] && [ -f "$tmpprof" ]; then rm -f "$tmpprof" fi exit } trap cleanup INT QUIT TERM EXIT # メインの処理 prof=${1:-".profile.cov"} echo "mode: count" > "$prof" gopath1=$(echo "$GOPATH" | cut -d: -f1) for pkg in $(go list ./...); do tmpprof="$gopath1/src/$pkg/profile.tmp" go test -covermode=count -coverprofile="$tmpprof" "$pkg" if [ -f "$tmpprof" ]; then tail -n +2 "$tmpprof" >> "$prof" rm "$tmpprof" fi done gopsutil-3.24.1/cpu/000077500000000000000000000000001455407747200142555ustar00rootroot00000000000000gopsutil-3.24.1/cpu/cpu.go000066400000000000000000000124311455407747200153740ustar00rootroot00000000000000package cpu import ( "context" "encoding/json" "fmt" "math" "runtime" "strconv" "strings" "sync" "time" "github.com/shirou/gopsutil/v3/internal/common" ) // TimesStat contains the amounts of time the CPU has spent performing different // kinds of work. Time units are in seconds. It is based on linux /proc/stat file. type TimesStat struct { CPU string `json:"cpu"` User float64 `json:"user"` System float64 `json:"system"` Idle float64 `json:"idle"` Nice float64 `json:"nice"` Iowait float64 `json:"iowait"` Irq float64 `json:"irq"` Softirq float64 `json:"softirq"` Steal float64 `json:"steal"` Guest float64 `json:"guest"` GuestNice float64 `json:"guestNice"` } type InfoStat struct { CPU int32 `json:"cpu"` VendorID string `json:"vendorId"` Family string `json:"family"` Model string `json:"model"` Stepping int32 `json:"stepping"` PhysicalID string `json:"physicalId"` CoreID string `json:"coreId"` Cores int32 `json:"cores"` ModelName string `json:"modelName"` Mhz float64 `json:"mhz"` CacheSize int32 `json:"cacheSize"` Flags []string `json:"flags"` Microcode string `json:"microcode"` } type lastPercent struct { sync.Mutex lastCPUTimes []TimesStat lastPerCPUTimes []TimesStat } var ( lastCPUPercent lastPercent invoke common.Invoker = common.Invoke{} ) func init() { lastCPUPercent.Lock() lastCPUPercent.lastCPUTimes, _ = Times(false) lastCPUPercent.lastPerCPUTimes, _ = Times(true) lastCPUPercent.Unlock() } // Counts returns the number of physical or logical cores in the system func Counts(logical bool) (int, error) { return CountsWithContext(context.Background(), logical) } func (c TimesStat) String() string { v := []string{ `"cpu":"` + c.CPU + `"`, `"user":` + strconv.FormatFloat(c.User, 'f', 1, 64), `"system":` + strconv.FormatFloat(c.System, 'f', 1, 64), `"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64), `"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64), `"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64), `"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64), `"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64), `"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64), `"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64), `"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64), } return `{` + strings.Join(v, ",") + `}` } // Deprecated: Total returns the total number of seconds in a CPUTimesStat // Please do not use this internal function. func (c TimesStat) Total() float64 { total := c.User + c.System + c.Idle + c.Nice + c.Iowait + c.Irq + c.Softirq + c.Steal + c.Guest + c.GuestNice return total } func (c InfoStat) String() string { s, _ := json.Marshal(c) return string(s) } func getAllBusy(t TimesStat) (float64, float64) { tot := t.Total() if runtime.GOOS == "linux" { tot -= t.Guest // Linux 2.6.24+ tot -= t.GuestNice // Linux 3.2.0+ } busy := tot - t.Idle - t.Iowait return tot, busy } func calculateBusy(t1, t2 TimesStat) float64 { t1All, t1Busy := getAllBusy(t1) t2All, t2Busy := getAllBusy(t2) if t2Busy <= t1Busy { return 0 } if t2All <= t1All { return 100 } return math.Min(100, math.Max(0, (t2Busy-t1Busy)/(t2All-t1All)*100)) } func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) { // Make sure the CPU measurements have the same length. if len(t1) != len(t2) { return nil, fmt.Errorf( "received two CPU counts: %d != %d", len(t1), len(t2), ) } ret := make([]float64, len(t1)) for i, t := range t2 { ret[i] = calculateBusy(t1[i], t) } return ret, nil } // Percent calculates the percentage of cpu used either per CPU or combined. // If an interval of 0 is given it will compare the current cpu times against the last call. // Returns one value per cpu, or a single value if percpu is set to false. func Percent(interval time.Duration, percpu bool) ([]float64, error) { return PercentWithContext(context.Background(), interval, percpu) } func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) { if interval <= 0 { return percentUsedFromLastCallWithContext(ctx, percpu) } // Get CPU usage at the start of the interval. cpuTimes1, err := TimesWithContext(ctx, percpu) if err != nil { return nil, err } if err := common.Sleep(ctx, interval); err != nil { return nil, err } // And at the end of the interval. cpuTimes2, err := TimesWithContext(ctx, percpu) if err != nil { return nil, err } return calculateAllBusy(cpuTimes1, cpuTimes2) } func percentUsedFromLastCall(percpu bool) ([]float64, error) { return percentUsedFromLastCallWithContext(context.Background(), percpu) } func percentUsedFromLastCallWithContext(ctx context.Context, percpu bool) ([]float64, error) { cpuTimes, err := TimesWithContext(ctx, percpu) if err != nil { return nil, err } lastCPUPercent.Lock() defer lastCPUPercent.Unlock() var lastTimes []TimesStat if percpu { lastTimes = lastCPUPercent.lastPerCPUTimes lastCPUPercent.lastPerCPUTimes = cpuTimes } else { lastTimes = lastCPUPercent.lastCPUTimes lastCPUPercent.lastCPUTimes = cpuTimes } if lastTimes == nil { return nil, fmt.Errorf("error getting times for cpu percent. lastTimes was nil") } return calculateAllBusy(lastTimes, cpuTimes) } gopsutil-3.24.1/cpu/cpu_aix.go000066400000000000000000000003751455407747200162410ustar00rootroot00000000000000//go:build aix // +build aix package cpu import ( "context" ) func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } gopsutil-3.24.1/cpu/cpu_aix_cgo.go000066400000000000000000000024161455407747200170670ustar00rootroot00000000000000//go:build aix && cgo // +build aix,cgo package cpu import ( "context" "github.com/power-devops/perfstat" ) func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { var ret []TimesStat if percpu { cpus, err := perfstat.CpuStat() if err != nil { return nil, err } for _, c := range cpus { ct := &TimesStat{ CPU: c.Name, Idle: float64(c.Idle), User: float64(c.User), System: float64(c.Sys), Iowait: float64(c.Wait), } ret = append(ret, *ct) } } else { c, err := perfstat.CpuUtilTotalStat() if err != nil { return nil, err } ct := &TimesStat{ CPU: "cpu-total", Idle: float64(c.IdlePct), User: float64(c.UserPct), System: float64(c.KernPct), Iowait: float64(c.WaitPct), } ret = append(ret, *ct) } return ret, nil } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { c, err := perfstat.CpuTotalStat() if err != nil { return nil, err } info := InfoStat{ CPU: 0, Mhz: float64(c.ProcessorHz / 1000000), Cores: int32(c.NCpusCfg), } result := []InfoStat{info} return result, nil } func CountsWithContext(ctx context.Context, logical bool) (int, error) { c, err := perfstat.CpuTotalStat() if err != nil { return 0, err } return c.NCpusCfg, nil } gopsutil-3.24.1/cpu/cpu_aix_nocgo.go000066400000000000000000000037661455407747200174350ustar00rootroot00000000000000//go:build aix && !cgo // +build aix,!cgo package cpu import ( "context" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" ) func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { if percpu { return []TimesStat{}, common.ErrNotImplementedError } else { out, err := invoke.CommandWithContext(ctx, "sar", "-u", "10", "1") if err != nil { return nil, err } lines := strings.Split(string(out), "\n") if len(lines) < 5 { return []TimesStat{}, common.ErrNotImplementedError } ret := TimesStat{CPU: "cpu-total"} h := strings.Fields(lines[len(lines)-3]) // headers v := strings.Fields(lines[len(lines)-2]) // values for i, header := range h { if t, err := strconv.ParseFloat(v[i], 64); err == nil { switch header { case `%usr`: ret.User = t case `%sys`: ret.System = t case `%wio`: ret.Iowait = t case `%idle`: ret.Idle = t } } } return []TimesStat{ret}, nil } } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { out, err := invoke.CommandWithContext(ctx, "prtconf") if err != nil { return nil, err } ret := InfoStat{} for _, line := range strings.Split(string(out), "\n") { if strings.HasPrefix(line, "Number Of Processors:") { p := strings.Fields(line) if len(p) > 3 { if t, err := strconv.ParseUint(p[3], 10, 64); err == nil { ret.Cores = int32(t) } } } else if strings.HasPrefix(line, "Processor Clock Speed:") { p := strings.Fields(line) if len(p) > 4 { if t, err := strconv.ParseFloat(p[3], 64); err == nil { switch strings.ToUpper(p[4]) { case "MHZ": ret.Mhz = t case "GHZ": ret.Mhz = t * 1000.0 case "KHZ": ret.Mhz = t / 1000.0 default: ret.Mhz = t } } } break } } return []InfoStat{ret}, nil } func CountsWithContext(ctx context.Context, logical bool) (int, error) { info, err := InfoWithContext(ctx) if err == nil { return int(info[0].Cores), nil } return 0, err } gopsutil-3.24.1/cpu/cpu_darwin.go000066400000000000000000000053361455407747200167460ustar00rootroot00000000000000//go:build darwin // +build darwin package cpu import ( "context" "strconv" "strings" "github.com/shoenig/go-m1cpu" "github.com/tklauser/go-sysconf" "golang.org/x/sys/unix" ) // sys/resource.h const ( CPUser = 0 cpNice = 1 cpSys = 2 cpIntr = 3 cpIdle = 4 cpUStates = 5 ) // default value. from time.h var ClocksPerSec = float64(128) 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) ([]TimesStat, error) { if percpu { return perCPUTimes() } return allCPUTimes() } // Returns only one CPUInfoStat on FreeBSD func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { var ret []InfoStat c := InfoStat{} c.ModelName, _ = unix.Sysctl("machdep.cpu.brand_string") family, _ := unix.SysctlUint32("machdep.cpu.family") c.Family = strconv.FormatUint(uint64(family), 10) model, _ := unix.SysctlUint32("machdep.cpu.model") c.Model = strconv.FormatUint(uint64(model), 10) stepping, _ := unix.SysctlUint32("machdep.cpu.stepping") c.Stepping = int32(stepping) features, err := unix.Sysctl("machdep.cpu.features") if err == nil { for _, v := range strings.Fields(features) { c.Flags = append(c.Flags, strings.ToLower(v)) } } leaf7Features, err := unix.Sysctl("machdep.cpu.leaf7_features") if err == nil { for _, v := range strings.Fields(leaf7Features) { c.Flags = append(c.Flags, strings.ToLower(v)) } } extfeatures, err := unix.Sysctl("machdep.cpu.extfeatures") if err == nil { for _, v := range strings.Fields(extfeatures) { c.Flags = append(c.Flags, strings.ToLower(v)) } } cores, _ := unix.SysctlUint32("machdep.cpu.core_count") c.Cores = int32(cores) cacheSize, _ := unix.SysctlUint32("machdep.cpu.cache.size") c.CacheSize = int32(cacheSize) c.VendorID, _ = unix.Sysctl("machdep.cpu.vendor") if m1cpu.IsAppleSilicon() { c.Mhz = float64(m1cpu.PCoreHz() / 1_000_000) } else { // Use the rated frequency of the CPU. This is a static value and does not // account for low power or Turbo Boost modes. cpuFrequency, err := unix.SysctlUint64("hw.cpufrequency") if err == nil { c.Mhz = float64(cpuFrequency) / 1000000.0 } } return append(ret, c), nil } func CountsWithContext(ctx context.Context, logical bool) (int, error) { var cpuArgument string if logical { cpuArgument = "hw.logicalcpu" } else { cpuArgument = "hw.physicalcpu" } count, err := unix.SysctlUint32(cpuArgument) if err != nil { return 0, err } return int(count), nil } gopsutil-3.24.1/cpu/cpu_darwin_cgo.go000066400000000000000000000053601455407747200175730ustar00rootroot00000000000000//go:build darwin && cgo // +build darwin,cgo package cpu /* #include #include #include #include #include #include #include #if TARGET_OS_MAC #include #endif #include #include */ import "C" import ( "bytes" "encoding/binary" "fmt" "unsafe" ) // these CPU times for darwin is borrowed from influxdb/telegraf. func perCPUTimes() ([]TimesStat, error) { var ( count C.mach_msg_type_number_t cpuload *C.processor_cpu_load_info_data_t ncpu C.natural_t ) status := C.host_processor_info(C.host_t(C.mach_host_self()), C.PROCESSOR_CPU_LOAD_INFO, &ncpu, (*C.processor_info_array_t)(unsafe.Pointer(&cpuload)), &count) if status != C.KERN_SUCCESS { return nil, fmt.Errorf("host_processor_info error=%d", status) } // jump through some cgo casting hoops and ensure we properly free // the memory that cpuload points to target := C.vm_map_t(C.mach_task_self_) address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload))) defer C.vm_deallocate(target, address, C.vm_size_t(ncpu)) // the body of struct processor_cpu_load_info // aka processor_cpu_load_info_data_t var cpu_ticks [C.CPU_STATE_MAX]uint32 // copy the cpuload array to a []byte buffer // where we can binary.Read the data size := int(ncpu) * binary.Size(cpu_ticks) buf := (*[1 << 30]byte)(unsafe.Pointer(cpuload))[:size:size] bbuf := bytes.NewBuffer(buf) var ret []TimesStat for i := 0; i < int(ncpu); i++ { err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks) if err != nil { return nil, err } c := TimesStat{ CPU: fmt.Sprintf("cpu%d", i), User: float64(cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec, System: float64(cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec, Nice: float64(cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec, Idle: float64(cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec, } ret = append(ret, c) } return ret, nil } func allCPUTimes() ([]TimesStat, error) { var count C.mach_msg_type_number_t var cpuload C.host_cpu_load_info_data_t count = C.HOST_CPU_LOAD_INFO_COUNT status := C.host_statistics(C.host_t(C.mach_host_self()), C.HOST_CPU_LOAD_INFO, C.host_info_t(unsafe.Pointer(&cpuload)), &count) if status != C.KERN_SUCCESS { return nil, fmt.Errorf("host_statistics error=%d", status) } c := TimesStat{ CPU: "cpu-total", User: float64(cpuload.cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec, System: float64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec, Nice: float64(cpuload.cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec, Idle: float64(cpuload.cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec, } return []TimesStat{c}, nil } gopsutil-3.24.1/cpu/cpu_darwin_nocgo.go000066400000000000000000000004711455407747200201260ustar00rootroot00000000000000//go:build darwin && !cgo // +build darwin,!cgo package cpu import "github.com/shirou/gopsutil/v3/internal/common" func perCPUTimes() ([]TimesStat, error) { return []TimesStat{}, common.ErrNotImplementedError } func allCPUTimes() ([]TimesStat, error) { return []TimesStat{}, common.ErrNotImplementedError } gopsutil-3.24.1/cpu/cpu_darwin_test.go000066400000000000000000000011231455407747200177730ustar00rootroot00000000000000//go:build darwin // +build darwin package cpu import ( "testing" "github.com/shoenig/go-m1cpu" ) func Test_CpuInfo_AppleSilicon(t *testing.T) { if !m1cpu.IsAppleSilicon() { t.Skip("wrong cpu type") } v, err := Info() if err != nil { t.Errorf("cpu info should be implemented on darwin systems") } for _, vv := range v { if vv.ModelName == "" { t.Errorf("could not get CPU info: %v", vv) } if vv.Mhz <= 0 { t.Errorf("could not get frequency of: %s", vv.ModelName) } if vv.Mhz > 6000 { t.Errorf("cpu frequency is absurdly high value: %f MHz", vv.Mhz) } } } gopsutil-3.24.1/cpu/cpu_dragonfly.go000066400000000000000000000076771455407747200174610ustar00rootroot00000000000000package cpu import ( "context" "fmt" "reflect" "regexp" "runtime" "strconv" "strings" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "github.com/tklauser/go-sysconf" "golang.org/x/sys/unix" ) var ( ClocksPerSec = float64(128) cpuMatch = regexp.MustCompile(`^CPU:`) originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`) featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`) featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`) cpuEnd = regexp.MustCompile(`^Trying to mount root`) cpuTimesSize int emptyTimes cpuTimes ) func init() { clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK) // ignore errors if err == nil { ClocksPerSec = float64(clkTck) } } func timeStat(name string, t *cpuTimes) *TimesStat { return &TimesStat{ User: float64(t.User) / ClocksPerSec, Nice: float64(t.Nice) / ClocksPerSec, System: float64(t.Sys) / ClocksPerSec, Idle: float64(t.Idle) / ClocksPerSec, Irq: float64(t.Intr) / ClocksPerSec, CPU: name, } } func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { if percpu { buf, err := unix.SysctlRaw("kern.cp_times") if err != nil { return nil, err } // We can't do this in init due to the conflict with cpu.init() if cpuTimesSize == 0 { cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size()) } ncpus := len(buf) / cpuTimesSize ret := make([]TimesStat, 0, ncpus) for i := 0; i < ncpus; i++ { times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize])) if *times == emptyTimes { // CPU not present continue } ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times)) } return ret, nil } buf, err := unix.SysctlRaw("kern.cp_time") if err != nil { return nil, err } times := (*cpuTimes)(unsafe.Pointer(&buf[0])) return []TimesStat{*timeStat("cpu-total", times)}, nil } // Returns only one InfoStat on DragonflyBSD. The information regarding core // count, however is accurate and it is assumed that all InfoStat attributes // are the same across CPUs. func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { const dmesgBoot = "/var/run/dmesg.boot" c, err := parseDmesgBoot(dmesgBoot) if err != nil { return nil, err } var u32 uint32 if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil { return nil, err } c.Mhz = float64(u32) var num int var buf string if buf, err = unix.Sysctl("hw.cpu_topology.tree"); err != nil { return nil, err } num = strings.Count(buf, "CHIP") c.Cores = int32(strings.Count(string(buf), "CORE") / num) if c.ModelName, err = unix.Sysctl("hw.model"); err != nil { return nil, err } ret := make([]InfoStat, num) for i := 0; i < num; i++ { ret[i] = c } return ret, nil } func parseDmesgBoot(fileName string) (InfoStat, error) { c := InfoStat{} lines, _ := common.ReadLines(fileName) for _, line := range lines { if matches := cpuEnd.FindStringSubmatch(line); matches != nil { break } else if matches := originMatch.FindStringSubmatch(line); matches != nil { 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: %v", line, err) } c.Stepping = int32(t) } else if matches := featuresMatch.FindStringSubmatch(line); matches != nil { for _, v := range strings.Split(matches[1], ",") { c.Flags = append(c.Flags, strings.ToLower(v)) } } else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil { for _, v := range strings.Split(matches[1], ",") { c.Flags = append(c.Flags, strings.ToLower(v)) } } } return c, nil } func CountsWithContext(ctx context.Context, logical bool) (int, error) { return runtime.NumCPU(), nil } gopsutil-3.24.1/cpu/cpu_dragonfly_amd64.go000066400000000000000000000001471455407747200204350ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint64 Nice uint64 Sys uint64 Intr uint64 Idle uint64 } gopsutil-3.24.1/cpu/cpu_fallback.go000066400000000000000000000015311455407747200172120ustar00rootroot00000000000000//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows && !dragonfly && !plan9 && !aix // +build !darwin,!linux,!freebsd,!openbsd,!netbsd,!solaris,!windows,!dragonfly,!plan9,!aix package cpu import ( "context" "runtime" "github.com/shirou/gopsutil/v3/internal/common" ) func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { return []TimesStat{}, common.ErrNotImplementedError } func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { return []InfoStat{}, common.ErrNotImplementedError } func CountsWithContext(ctx context.Context, logical bool) (int, error) { return runtime.NumCPU(), nil } gopsutil-3.24.1/cpu/cpu_freebsd.go000066400000000000000000000107571455407747200170770ustar00rootroot00000000000000package cpu import ( "context" "fmt" "reflect" "regexp" "runtime" "strconv" "strings" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "github.com/tklauser/go-sysconf" "golang.org/x/sys/unix" ) var ( ClocksPerSec = float64(128) cpuMatch = regexp.MustCompile(`^CPU:`) originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Family\s*=\s*(.+)\s+Model\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`) featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`) featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`) cpuEnd = regexp.MustCompile(`^Trying to mount root`) cpuCores = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`) cpuTimesSize int emptyTimes cpuTimes ) func init() { clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK) // ignore errors if err == nil { ClocksPerSec = float64(clkTck) } } func timeStat(name string, t *cpuTimes) *TimesStat { return &TimesStat{ User: float64(t.User) / ClocksPerSec, Nice: float64(t.Nice) / ClocksPerSec, System: float64(t.Sys) / ClocksPerSec, Idle: float64(t.Idle) / ClocksPerSec, Irq: float64(t.Intr) / ClocksPerSec, CPU: name, } } func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { if percpu { buf, err := unix.SysctlRaw("kern.cp_times") if err != nil { return nil, err } // We can't do this in init due to the conflict with cpu.init() if cpuTimesSize == 0 { cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size()) } ncpus := len(buf) / cpuTimesSize ret := make([]TimesStat, 0, ncpus) for i := 0; i < ncpus; i++ { times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize])) if *times == emptyTimes { // CPU not present continue } ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times)) } return ret, nil } buf, err := unix.SysctlRaw("kern.cp_time") if err != nil { return nil, err } times := (*cpuTimes)(unsafe.Pointer(&buf[0])) return []TimesStat{*timeStat("cpu-total", times)}, nil } // Returns only one InfoStat on FreeBSD. The information regarding core // count, however is accurate and it is assumed that all InfoStat attributes // are the same across CPUs. func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { const dmesgBoot = "/var/run/dmesg.boot" c, num, err := parseDmesgBoot(dmesgBoot) if err != nil { return nil, err } var u32 uint32 if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil { return nil, err } c.Mhz = float64(u32) if u32, err = unix.SysctlUint32("hw.ncpu"); err != nil { return nil, err } c.Cores = int32(u32) if c.ModelName, err = unix.Sysctl("hw.model"); err != nil { return nil, err } ret := make([]InfoStat, num) for i := 0; i < num; i++ { ret[i] = c } return ret, nil } func parseDmesgBoot(fileName string) (InfoStat, int, error) { c := InfoStat{} lines, _ := common.ReadLines(fileName) cpuNum := 1 // default cpu num is 1 for _, line := range lines { if matches := cpuEnd.FindStringSubmatch(line); matches != nil { break } else if matches := originMatch.FindStringSubmatch(line); matches != nil { c.VendorID = matches[1] c.Family = matches[3] c.Model = matches[4] t, err := strconv.ParseInt(matches[5], 10, 32) if err != nil { return c, 0, fmt.Errorf("unable to parse FreeBSD CPU stepping information from %q: %v", line, err) } c.Stepping = int32(t) } else if matches := featuresMatch.FindStringSubmatch(line); matches != nil { for _, v := range strings.Split(matches[1], ",") { c.Flags = append(c.Flags, strings.ToLower(v)) } } else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil { for _, v := range strings.Split(matches[1], ",") { c.Flags = append(c.Flags, strings.ToLower(v)) } } else if matches := cpuCores.FindStringSubmatch(line); matches != nil { t, err := strconv.ParseInt(matches[1], 10, 32) if err != nil { return c, 0, fmt.Errorf("unable to parse FreeBSD CPU Nums from %q: %v", line, err) } cpuNum = int(t) t2, err := strconv.ParseInt(matches[2], 10, 32) if err != nil { return c, 0, fmt.Errorf("unable to parse FreeBSD CPU cores from %q: %v", line, err) } c.Cores = int32(t2) } } return c, cpuNum, nil } func CountsWithContext(ctx context.Context, logical bool) (int, error) { return runtime.NumCPU(), nil } gopsutil-3.24.1/cpu/cpu_freebsd_386.go000066400000000000000000000001471455407747200174670ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint32 Nice uint32 Sys uint32 Intr uint32 Idle uint32 } gopsutil-3.24.1/cpu/cpu_freebsd_amd64.go000066400000000000000000000001471455407747200200620ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint64 Nice uint64 Sys uint64 Intr uint64 Idle uint64 } gopsutil-3.24.1/cpu/cpu_freebsd_arm.go000066400000000000000000000001471455407747200177260ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint32 Nice uint32 Sys uint32 Intr uint32 Idle uint32 } gopsutil-3.24.1/cpu/cpu_freebsd_arm64.go000066400000000000000000000001471455407747200201000ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint64 Nice uint64 Sys uint64 Intr uint64 Idle uint64 } gopsutil-3.24.1/cpu/cpu_freebsd_test.go000066400000000000000000000015501455407747200201250ustar00rootroot00000000000000package cpu import ( "path/filepath" "runtime" "testing" "github.com/shirou/gopsutil/v3/internal/common" ) func TestParseDmesgBoot(t *testing.T) { if runtime.GOOS != "freebsd" { t.SkipNow() } cpuTests := []struct { file string cpuNum int cores int32 }{ {"1cpu_2core.txt", 1, 2}, {"1cpu_4core.txt", 1, 4}, {"2cpu_4core.txt", 2, 4}, } for _, tt := range cpuTests { v, num, err := parseDmesgBoot(filepath.Join("testdata", "freebsd", tt.file)) if err != nil { t.Errorf("parseDmesgBoot failed(%s), %v", tt.file, err) } if num != tt.cpuNum { t.Errorf("parseDmesgBoot wrong length(%s), %v", tt.file, err) } if v.Cores != tt.cores { t.Errorf("parseDmesgBoot wrong core(%s), %v", tt.file, err) } if !common.StringsContains(v.Flags, "fpu") { t.Errorf("parseDmesgBoot fail to parse features(%s), %v", tt.file, err) } } } gopsutil-3.24.1/cpu/cpu_linux.go000066400000000000000000000273731455407747200166260ustar00rootroot00000000000000//go:build linux // +build linux package cpu import ( "context" "errors" "fmt" "path/filepath" "strconv" "strings" "github.com/tklauser/go-sysconf" "github.com/shirou/gopsutil/v3/internal/common" ) var ClocksPerSec = float64(100) var armModelToModelName = map[uint64]string{ 0x810: "ARM810", 0x920: "ARM920", 0x922: "ARM922", 0x926: "ARM926", 0x940: "ARM940", 0x946: "ARM946", 0x966: "ARM966", 0xa20: "ARM1020", 0xa22: "ARM1022", 0xa26: "ARM1026", 0xb02: "ARM11 MPCore", 0xb36: "ARM1136", 0xb56: "ARM1156", 0xb76: "ARM1176", 0xc05: "Cortex-A5", 0xc07: "Cortex-A7", 0xc08: "Cortex-A8", 0xc09: "Cortex-A9", 0xc0d: "Cortex-A17", 0xc0f: "Cortex-A15", 0xc0e: "Cortex-A17", 0xc14: "Cortex-R4", 0xc15: "Cortex-R5", 0xc17: "Cortex-R7", 0xc18: "Cortex-R8", 0xc20: "Cortex-M0", 0xc21: "Cortex-M1", 0xc23: "Cortex-M3", 0xc24: "Cortex-M4", 0xc27: "Cortex-M7", 0xc60: "Cortex-M0+", 0xd01: "Cortex-A32", 0xd02: "Cortex-A34", 0xd03: "Cortex-A53", 0xd04: "Cortex-A35", 0xd05: "Cortex-A55", 0xd06: "Cortex-A65", 0xd07: "Cortex-A57", 0xd08: "Cortex-A72", 0xd09: "Cortex-A73", 0xd0a: "Cortex-A75", 0xd0b: "Cortex-A76", 0xd0c: "Neoverse-N1", 0xd0d: "Cortex-A77", 0xd0e: "Cortex-A76AE", 0xd13: "Cortex-R52", 0xd20: "Cortex-M23", 0xd21: "Cortex-M33", 0xd40: "Neoverse-V1", 0xd41: "Cortex-A78", 0xd42: "Cortex-A78AE", 0xd43: "Cortex-A65AE", 0xd44: "Cortex-X1", 0xd46: "Cortex-A510", 0xd47: "Cortex-A710", 0xd48: "Cortex-X2", 0xd49: "Neoverse-N2", 0xd4a: "Neoverse-E1", 0xd4b: "Cortex-A78C", 0xd4c: "Cortex-X1C", 0xd4d: "Cortex-A715", 0xd4e: "Cortex-X3", } 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) ([]TimesStat, error) { filename := common.HostProcWithContext(ctx, "stat") lines := []string{} if percpu { statlines, err := common.ReadLines(filename) if err != nil || len(statlines) < 2 { return []TimesStat{}, nil } for _, line := range statlines[1:] { if !strings.HasPrefix(line, "cpu") { break } lines = append(lines, line) } } else { lines, _ = common.ReadLinesOffsetN(filename, 0, 1) } ret := make([]TimesStat, 0, len(lines)) for _, line := range lines { ct, err := parseStatLine(line) if err != nil { continue } ret = append(ret, *ct) } return ret, nil } func sysCPUPath(ctx context.Context, cpu int32, relPath string) string { return common.HostSysWithContext(ctx, fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath) } func finishCPUInfo(ctx context.Context, c *InfoStat) { var lines []string var err error var value float64 if len(c.CoreID) == 0 { lines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, "topology/core_id")) if err == nil { c.CoreID = lines[0] } } // override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless // of the value from /proc/cpuinfo because we want to report the maximum // clock-speed of the CPU for c.Mhz, matching the behaviour of Windows lines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, "cpufreq/cpuinfo_max_freq")) // if we encounter errors below such as there are no cpuinfo_max_freq file, // we just ignore. so let Mhz is 0. if err != nil || len(lines) == 0 { return } value, err = strconv.ParseFloat(lines[0], 64) if err != nil { return } c.Mhz = value / 1000.0 // value is in kHz if c.Mhz > 9999 { c.Mhz = c.Mhz / 1000.0 // value in Hz } } // CPUInfo on linux will return 1 item per physical thread. // // CPUs have three levels of counting: sockets, cores, threads. // Cores with HyperThreading count as having 2 threads per core. // Sockets often come with many physical CPU cores. // For example a single socket board with two cores each with HT will // return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1. func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { filename := common.HostProcWithContext(ctx, "cpuinfo") lines, _ := common.ReadLines(filename) var ret []InfoStat var processorName string c := InfoStat{CPU: -1, Cores: 1} for _, line := range lines { fields := strings.Split(line, ":") if len(fields) < 2 { continue } key := strings.TrimSpace(fields[0]) value := strings.TrimSpace(fields[1]) switch key { case "Processor": processorName = value case "processor", "cpu number": if c.CPU >= 0 { finishCPUInfo(ctx, &c) ret = append(ret, c) } c = InfoStat{Cores: 1, ModelName: processorName} t, err := strconv.ParseInt(value, 10, 64) if err != nil { return ret, err } c.CPU = int32(t) case "vendorId", "vendor_id": c.VendorID = value if strings.Contains(value, "S390") { processorName = "S390" } case "CPU implementer": if v, err := strconv.ParseUint(value, 0, 8); err == nil { switch v { case 0x41: c.VendorID = "ARM" case 0x42: c.VendorID = "Broadcom" case 0x43: c.VendorID = "Cavium" case 0x44: c.VendorID = "DEC" case 0x46: c.VendorID = "Fujitsu" case 0x48: c.VendorID = "HiSilicon" case 0x49: c.VendorID = "Infineon" case 0x4d: c.VendorID = "Motorola/Freescale" case 0x4e: c.VendorID = "NVIDIA" case 0x50: c.VendorID = "APM" case 0x51: c.VendorID = "Qualcomm" case 0x56: c.VendorID = "Marvell" case 0x61: c.VendorID = "Apple" case 0x69: c.VendorID = "Intel" case 0xc0: c.VendorID = "Ampere" } } case "cpu family": c.Family = value case "model", "CPU part": c.Model = value // if CPU is arm based, model name is found via model number. refer to: arch/arm64/kernel/cpuinfo.c if c.VendorID == "ARM" { if v, err := strconv.ParseUint(c.Model, 0, 16); err == nil { modelName, exist := armModelToModelName[v] if exist { c.ModelName = modelName } else { c.ModelName = "Undefined" } } } case "Model Name", "model name", "cpu": c.ModelName = value if strings.Contains(value, "POWER") { c.Model = strings.Split(value, " ")[0] c.Family = "POWER" c.VendorID = "IBM" } case "stepping", "revision", "CPU revision": val := value if key == "revision" { val = strings.Split(value, ".")[0] } t, err := strconv.ParseInt(val, 10, 64) if err != nil { return ret, err } c.Stepping = int32(t) case "cpu MHz", "clock", "cpu MHz dynamic": // treat this as the fallback value, thus we ignore error if t, err := strconv.ParseFloat(strings.Replace(value, "MHz", "", 1), 64); err == nil { c.Mhz = t } case "cache size": t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64) if err != nil { return ret, err } c.CacheSize = int32(t) case "physical id": c.PhysicalID = value case "core id": c.CoreID = value case "flags", "Features": c.Flags = strings.FieldsFunc(value, func(r rune) bool { return r == ',' || r == ' ' }) case "microcode": c.Microcode = value } } if c.CPU >= 0 { finishCPUInfo(ctx, &c) ret = append(ret, c) } return ret, nil } func parseStatLine(line string) (*TimesStat, error) { fields := strings.Fields(line) if len(fields) < 8 { return nil, errors.New("stat does not contain cpu info") } if !strings.HasPrefix(fields[0], "cpu") { return nil, errors.New("not contain cpu") } cpu := fields[0] if cpu == "cpu" { cpu = "cpu-total" } user, err := strconv.ParseFloat(fields[1], 64) if err != nil { return nil, err } nice, err := strconv.ParseFloat(fields[2], 64) if err != nil { return nil, err } system, err := strconv.ParseFloat(fields[3], 64) if err != nil { return nil, err } idle, err := strconv.ParseFloat(fields[4], 64) if err != nil { return nil, err } iowait, err := strconv.ParseFloat(fields[5], 64) if err != nil { return nil, err } irq, err := strconv.ParseFloat(fields[6], 64) if err != nil { return nil, err } softirq, err := strconv.ParseFloat(fields[7], 64) if err != nil { return nil, err } ct := &TimesStat{ CPU: cpu, User: user / ClocksPerSec, Nice: nice / ClocksPerSec, System: system / ClocksPerSec, Idle: idle / ClocksPerSec, Iowait: iowait / ClocksPerSec, Irq: irq / ClocksPerSec, Softirq: softirq / ClocksPerSec, } if len(fields) > 8 { // Linux >= 2.6.11 steal, err := strconv.ParseFloat(fields[8], 64) if err != nil { return nil, err } ct.Steal = steal / ClocksPerSec } if len(fields) > 9 { // Linux >= 2.6.24 guest, err := strconv.ParseFloat(fields[9], 64) if err != nil { return nil, err } ct.Guest = guest / ClocksPerSec } if len(fields) > 10 { // Linux >= 3.2.0 guestNice, err := strconv.ParseFloat(fields[10], 64) if err != nil { return nil, err } ct.GuestNice = guestNice / ClocksPerSec } return ct, nil } func CountsWithContext(ctx context.Context, logical bool) (int, error) { if logical { ret := 0 // https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_pslinux.py#L599 procCpuinfo := common.HostProcWithContext(ctx, "cpuinfo") lines, err := common.ReadLines(procCpuinfo) if err == nil { for _, line := range lines { line = strings.ToLower(line) if strings.HasPrefix(line, "processor") { _, err = strconv.Atoi(strings.TrimSpace(line[strings.IndexByte(line, ':')+1:])) if err == nil { ret++ } } } } if ret == 0 { procStat := common.HostProcWithContext(ctx, "stat") lines, err = common.ReadLines(procStat) if err != nil { return 0, err } for _, line := range lines { if len(line) >= 4 && strings.HasPrefix(line, "cpu") && '0' <= line[3] && line[3] <= '9' { // `^cpu\d` regexp matching ret++ } } } return ret, nil } // physical cores // https://github.com/giampaolo/psutil/blob/8415355c8badc9c94418b19bdf26e622f06f0cce/psutil/_pslinux.py#L615-L628 threadSiblingsLists := make(map[string]bool) // These 2 files are the same but */core_cpus_list is newer while */thread_siblings_list is deprecated and may disappear in the future. // https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst // https://github.com/giampaolo/psutil/pull/1727#issuecomment-707624964 // https://lkml.org/lkml/2019/2/26/41 for _, glob := range []string{"devices/system/cpu/cpu[0-9]*/topology/core_cpus_list", "devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list"} { if files, err := filepath.Glob(common.HostSysWithContext(ctx, glob)); err == nil { for _, file := range files { lines, err := common.ReadLines(file) if err != nil || len(lines) != 1 { continue } threadSiblingsLists[lines[0]] = true } ret := len(threadSiblingsLists) if ret != 0 { return ret, nil } } } // https://github.com/giampaolo/psutil/blob/122174a10b75c9beebe15f6c07dcf3afbe3b120d/psutil/_pslinux.py#L631-L652 filename := common.HostProcWithContext(ctx, "cpuinfo") lines, err := common.ReadLines(filename) if err != nil { return 0, err } mapping := make(map[int]int) currentInfo := make(map[string]int) for _, line := range lines { line = strings.ToLower(strings.TrimSpace(line)) if line == "" { // new section id, okID := currentInfo["physical id"] cores, okCores := currentInfo["cpu cores"] if okID && okCores { mapping[id] = cores } currentInfo = make(map[string]int) continue } fields := strings.Split(line, ":") if len(fields) < 2 { continue } fields[0] = strings.TrimSpace(fields[0]) if fields[0] == "physical id" || fields[0] == "cpu cores" { val, err := strconv.Atoi(strings.TrimSpace(fields[1])) if err != nil { continue } currentInfo[fields[0]] = val } } ret := 0 for _, v := range mapping { ret += v } return ret, nil } gopsutil-3.24.1/cpu/cpu_linux_test.go000066400000000000000000000053031455407747200176520ustar00rootroot00000000000000package cpu import ( "errors" "os/exec" "strconv" "strings" "testing" ) func TestTimesEmpty(t *testing.T) { t.Setenv("HOST_PROC", "testdata/linux/times_empty") _, err := Times(true) if err != nil { t.Error("Times(true) failed") } _, err = Times(false) if err != nil { t.Error("Times(false) failed") } } func TestCPUparseStatLine_424(t *testing.T) { t.Setenv("HOST_PROC", "testdata/linux/424/proc") { l, err := Times(true) if err != nil || len(l) == 0 { t.Error("Times(true) failed") } t.Logf("Times(true): %#v", l) } { l, err := Times(false) if err != nil || len(l) == 0 { t.Error("Times(false) failed") } t.Logf("Times(false): %#v", l) } } func TestCPUCountsAgainstLscpu(t *testing.T) { cmd := exec.Command("lscpu") cmd.Env = []string{"LC_ALL=C"} out, err := cmd.Output() if err != nil { if errors.Is(err, exec.ErrNotFound) { t.Skip("no lscpu to compare with") } t.Errorf("error executing lscpu: %v", err) } var threadsPerCore, coresPerSocket, sockets, books, drawers int books = 1 drawers = 1 lines := strings.Split(string(out), "\n") for _, line := range lines { fields := strings.Split(line, ":") if len(fields) < 2 { continue } switch fields[0] { case "Thread(s) per core": threadsPerCore, _ = strconv.Atoi(strings.TrimSpace(fields[1])) case "Core(s) per socket": coresPerSocket, _ = strconv.Atoi(strings.TrimSpace(fields[1])) case "Socket(s)", "Socket(s) per book": sockets, _ = strconv.Atoi(strings.TrimSpace(fields[1])) case "Book(s) per drawer": books, _ = strconv.Atoi(strings.TrimSpace(fields[1])) case "Drawer(s)": drawers, _ = strconv.Atoi(strings.TrimSpace(fields[1])) } } if threadsPerCore == 0 || coresPerSocket == 0 || sockets == 0 { t.Errorf("missing info from lscpu: threadsPerCore=%d coresPerSocket=%d sockets=%d", threadsPerCore, coresPerSocket, sockets) } expectedPhysical := coresPerSocket * sockets * books * drawers expectedLogical := expectedPhysical * threadsPerCore physical, err := Counts(false) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } logical, err := Counts(true) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if expectedPhysical != physical { t.Errorf("expected %v, got %v", expectedPhysical, physical) } if expectedLogical != logical { t.Errorf("expected %v, got %v", expectedLogical, logical) } } func TestCPUCountsLogicalAndroid_1037(t *testing.T) { // https://github.com/shirou/gopsutil/issues/1037 t.Setenv("HOST_PROC", "testdata/linux/1037/proc") count, err := Counts(true) if err != nil { t.Errorf("error %v", err) } expected := 8 if count != expected { t.Errorf("expected %v, got %v", expected, count) } } gopsutil-3.24.1/cpu/cpu_netbsd.go000066400000000000000000000046411455407747200167370ustar00rootroot00000000000000//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 } gopsutil-3.24.1/cpu/cpu_netbsd_amd64.go000066400000000000000000000001471455407747200177270ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint64 Nice uint64 Sys uint64 Intr uint64 Idle uint64 } gopsutil-3.24.1/cpu/cpu_netbsd_arm64.go000066400000000000000000000001471455407747200177450ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint64 Nice uint64 Sys uint64 Intr uint64 Idle uint64 } gopsutil-3.24.1/cpu/cpu_openbsd.go000066400000000000000000000054611455407747200171130ustar00rootroot00000000000000//go:build openbsd // +build openbsd 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/sched.h cpuOnline = 0x0001 // CPUSTATS_ONLINE // sys/sysctl.h ctlKern = 1 // "high kernel": proc, limits ctlHw = 6 // CTL_HW smt = 24 // HW_SMT kernCpTime = 40 // KERN_CPTIME kernCPUStats = 85 // KERN_CPUSTATS ) var ClocksPerSec = float64(128) type cpuStats struct { // cs_time[CPUSTATES] User uint64 Nice uint64 Sys uint64 Spin uint64 Intr uint64 Idle uint64 // cs_flags Flags uint64 } 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) / ClocksPerSec, Nice: float64(times.Nice) / ClocksPerSec, System: float64(times.Sys) / ClocksPerSec, Idle: float64(times.Idle) / ClocksPerSec, Irq: float64(times.Intr) / ClocksPerSec, } 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, kernCPUStats, int32(i)} buf, _, err := common.CallSyscall(mib) if err != nil { return ret, err } stats := (*cpuStats)(unsafe.Pointer(&buf[0])) if (stats.Flags & cpuOnline) == 0 { continue } ret = append(ret, TimesStat{ CPU: fmt.Sprintf("cpu%d", i), User: float64(stats.User) / ClocksPerSec, Nice: float64(stats.Nice) / ClocksPerSec, System: float64(stats.Sys) / ClocksPerSec, Idle: float64(stats.Idle) / ClocksPerSec, Irq: float64(stats.Intr) / ClocksPerSec, }) } return ret, nil } // Returns only one (minimal) CPUInfoStat on OpenBSD 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.SysctlUint32("hw.cpuspeed") if err != nil { return nil, err } c.Mhz = float64(mhz) ncpu, err := unix.SysctlUint32("hw.ncpuonline") if err != nil { return nil, err } c.Cores = int32(ncpu) if c.ModelName, err = unix.Sysctl("hw.model"); err != nil { return nil, err } return append(ret, c), nil } func CountsWithContext(ctx context.Context, logical bool) (int, error) { return runtime.NumCPU(), nil } gopsutil-3.24.1/cpu/cpu_openbsd_386.go000066400000000000000000000001641455407747200175060ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint32 Nice uint32 Sys uint32 Spin uint32 Intr uint32 Idle uint32 } gopsutil-3.24.1/cpu/cpu_openbsd_amd64.go000066400000000000000000000001641455407747200201010ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint64 Nice uint64 Sys uint64 Spin uint64 Intr uint64 Idle uint64 } gopsutil-3.24.1/cpu/cpu_openbsd_arm.go000066400000000000000000000001641455407747200177450ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint32 Nice uint32 Sys uint32 Spin uint32 Intr uint32 Idle uint32 } gopsutil-3.24.1/cpu/cpu_openbsd_arm64.go000066400000000000000000000001641455407747200201170ustar00rootroot00000000000000package cpu type cpuTimes struct { User uint64 Nice uint64 Sys uint64 Spin uint64 Intr uint64 Idle uint64 } gopsutil-3.24.1/cpu/cpu_plan9.go000066400000000000000000000020711455407747200164760ustar00rootroot00000000000000//go:build plan9 // +build plan9 package cpu import ( "context" "os" "runtime" stats "github.com/lufia/plan9stats" "github.com/shirou/gopsutil/v3/internal/common" ) func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { // BUG: percpu flag is not supported yet. root := os.Getenv("HOST_ROOT") c, err := stats.ReadCPUType(ctx, stats.WithRootDir(root)) if err != nil { return nil, err } s, err := stats.ReadCPUStats(ctx, stats.WithRootDir(root)) if err != nil { return nil, err } return []TimesStat{ { CPU: c.Name, User: s.User.Seconds(), System: s.Sys.Seconds(), Idle: s.Idle.Seconds(), }, }, nil } func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { return []InfoStat{}, common.ErrNotImplementedError } func CountsWithContext(ctx context.Context, logical bool) (int, error) { return runtime.NumCPU(), nil } gopsutil-3.24.1/cpu/cpu_plan9_test.go000066400000000000000000000016101455407747200175330ustar00rootroot00000000000000//go:build plan9 // +build plan9 package cpu import ( "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" ) var timesTests = []struct { mockedRootFS string stats []TimesStat }{ { "2cores", []TimesStat{ { CPU: "Core i7/Xeon", User: 2780.0 / 1000.0, System: 30020.0 / 1000.0, Idle: (1412961713341830*2)/1000000000.0 - 2.78 - 30.02, }, }, }, } func TestTimesPlan9(t *testing.T) { for _, tt := range timesTests { t.Run(tt.mockedRootFS, func(t *testing.T) { t.Setenv("HOST_ROOT", filepath.Join("testdata/plan9", tt.mockedRootFS)) stats, err := Times(false) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } eps := cmpopts.EquateApprox(0, 0.00000001) if !cmp.Equal(stats, tt.stats, eps) { t.Errorf("got: %+v\nwant: %+v", stats, tt.stats) } }) } } gopsutil-3.24.1/cpu/cpu_solaris.go000066400000000000000000000170241455407747200171330ustar00rootroot00000000000000package cpu import ( "context" "errors" "fmt" "regexp" "runtime" "sort" "strconv" "strings" "github.com/tklauser/go-sysconf" ) var ClocksPerSec = float64(128) func init() { clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK) // ignore errors if err == nil { ClocksPerSec = float64(clkTck) } } // sum all values in a float64 map with float64 keys func msum(x map[float64]float64) float64 { total := 0.0 for _, y := range x { total += y } return total } func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } 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: %s", err) } cpu := make(map[float64]float64) idle := make(map[float64]float64) user := make(map[float64]float64) kern := make(map[float64]float64) iowt := make(map[float64]float64) // swap := make(map[float64]float64) for _, line := range strings.Split(string(kstatSysOut), "\n") { fields := kstatSplit.Split(line, -1) if fields[0] != "cpu_stat" { continue } cpuNumber, err := strconv.ParseFloat(fields[1], 64) if err != nil { 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: %s", err) } case "user": user[cpuNumber], err = strconv.ParseFloat(fields[4], 64) if err != nil { 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: %s", err) } case "iowait": iowt[cpuNumber], err = strconv.ParseFloat(fields[4], 64) if err != nil { return nil, fmt.Errorf("cannot parse iowait: %s", err) } //not sure how this translates, don't report, add to kernel, something else? /*case "swap": swap[cpuNumber], err = strconv.ParseFloat(fields[4], 64) if err != nil { return nil, fmt.Errorf("cannot parse swap: %s", err) } */ } } ret := make([]TimesStat, 0, len(cpu)) if percpu { for _, c := range cpu { ct := &TimesStat{ CPU: fmt.Sprintf("cpu%d", int(cpu[c])), Idle: idle[c] / ClocksPerSec, User: user[c] / ClocksPerSec, System: kern[c] / ClocksPerSec, Iowait: iowt[c] / ClocksPerSec, } ret = append(ret, *ct) } } else { ct := &TimesStat{ CPU: "cpu-total", Idle: msum(idle) / ClocksPerSec, User: msum(user) / ClocksPerSec, System: msum(kern) / ClocksPerSec, Iowait: msum(iowt) / ClocksPerSec, } ret = append(ret, *ct) } return ret, nil } func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } 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: %s", err) } procs, err := parseProcessorInfo(string(psrInfoOut)) if err != nil { 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: %s", err) } flags, err := parseISAInfo(string(isaInfoOut)) if err != nil { return nil, fmt.Errorf("error parsing isainfo output: %s", err) } result := make([]InfoStat, 0, len(flags)) for _, proc := range procs { procWithFlags := proc procWithFlags.Flags = flags result = append(result, procWithFlags) } return result, nil } var flagsMatch = regexp.MustCompile(`[\w\.]+`) func parseISAInfo(cmdOutput string) ([]string, error) { words := flagsMatch.FindAllString(cmdOutput, -1) // Sanity check the output if len(words) < 4 || words[1] != "bit" || words[3] != "applications" { return nil, errors.New("attempted to parse invalid isainfo output") } flags := make([]string, len(words)-4) for i, val := range words[4:] { flags[i] = val } sort.Strings(flags) return flags, nil } var psrInfoMatch = regexp.MustCompile(`The physical processor has (?:([\d]+) virtual processors? \(([\d-]+)\)|([\d]+) cores and ([\d]+) virtual processors[^\n]+)\n(?:\s+ The core has.+\n)*\s+.+ \((\w+) ([\S]+) family (.+) model (.+) step (.+) clock (.+) MHz\)\n[\s]*(.*)`) const ( psrNumCoresOffset = 1 psrNumCoresHTOffset = 3 psrNumHTOffset = 4 psrVendorIDOffset = 5 psrFamilyOffset = 7 psrModelOffset = 8 psrStepOffset = 9 psrClockOffset = 10 psrModelNameOffset = 11 ) func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) { matches := psrInfoMatch.FindAllStringSubmatch(cmdOutput, -1) var infoStatCount int32 result := make([]InfoStat, 0, len(matches)) for physicalIndex, physicalCPU := range matches { var step int32 var clock float64 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: %s", physicalCPU[9], err) } step = int32(stepParsed) } 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: %s", physicalCPU[10], err) } clock = float64(clockParsed) } var err error var numCores int64 var numHT int64 switch { 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: %s", physicalCPU[1], err) } for i := 0; i < int(numCores); i++ { result = append(result, InfoStat{ CPU: infoStatCount, PhysicalID: strconv.Itoa(physicalIndex), CoreID: strconv.Itoa(i), Cores: 1, VendorID: physicalCPU[psrVendorIDOffset], ModelName: physicalCPU[psrModelNameOffset], Family: physicalCPU[psrFamilyOffset], Model: physicalCPU[psrModelOffset], Stepping: step, Mhz: clock, }) infoStatCount++ } 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: %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: %s", physicalCPU[4], err) } for i := 0; i < int(numCores); i++ { result = append(result, InfoStat{ CPU: infoStatCount, PhysicalID: strconv.Itoa(physicalIndex), CoreID: strconv.Itoa(i), Cores: int32(numHT) / int32(numCores), VendorID: physicalCPU[psrVendorIDOffset], ModelName: physicalCPU[psrModelNameOffset], Family: physicalCPU[psrFamilyOffset], Model: physicalCPU[psrModelOffset], Stepping: step, Mhz: clock, }) infoStatCount++ } default: return nil, errors.New("values for cores with and without hyperthreading are both set") } } return result, nil } func CountsWithContext(ctx context.Context, logical bool) (int, error) { return runtime.NumCPU(), nil } gopsutil-3.24.1/cpu/cpu_solaris_test.go000066400000000000000000000247301455407747200201740ustar00rootroot00000000000000package cpu import ( "os" "path/filepath" "reflect" "sort" "testing" ) func TestParseISAInfo(t *testing.T) { cases := []struct { filename string expected []string }{ { "1cpu_1core_isainfo.txt", []string{ "rdseed", "adx", "avx2", "fma", "bmi2", "bmi1", "rdrand", "f16c", "vmx", "avx", "xsave", "pclmulqdq", "aes", "movbe", "sse4.2", "sse4.1", "ssse3", "popcnt", "tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8", "tsc", "fpu", }, }, { "2cpu_1core_isainfo.txt", []string{ "rdseed", "adx", "avx2", "fma", "bmi2", "bmi1", "rdrand", "f16c", "vmx", "avx", "xsave", "pclmulqdq", "aes", "movbe", "sse4.2", "sse4.1", "ssse3", "popcnt", "tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8", "tsc", "fpu", }, }, { "2cpu_8core_isainfo.txt", []string{ "vmx", "avx", "xsave", "pclmulqdq", "aes", "sse4.2", "sse4.1", "ssse3", "popcnt", "tscp", "cx16", "sse3", "sse2", "sse", "fxsr", "mmx", "cmov", "amd_sysc", "cx8", "tsc", "fpu", }, }, { "2cpu_12core_isainfo.txt", []string{ "amd_svm", "amd_lzcnt", "popcnt", "amd_sse4a", "tscp", "ahf", "cx16", "sse3", "sse2", "sse", "fxsr", "amd_3dnowx", "amd_3dnow", "amd_mmx", "mmx", "cmov", "amd_sysc", "cx8", "tsc", "fpu", }, }, } for _, tc := range cases { content, err := os.ReadFile(filepath.Join("testdata", "solaris", tc.filename)) if err != nil { t.Errorf("cannot read test case: %s", err) } sort.Strings(tc.expected) flags, err := parseISAInfo(string(content)) if err != nil { t.Fatalf("parseISAInfo: %s", err) } if !reflect.DeepEqual(tc.expected, flags) { t.Fatalf("Bad flags\nExpected: %v\n Actual: %v", tc.expected, flags) } } } func TestParseProcessorInfo(t *testing.T) { cases := []struct { filename string expected []InfoStat }{ { "1cpu_1core_psrinfo.txt", []InfoStat{ {CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "0", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312}, }, }, { "2cpu_1core_psrinfo.txt", []InfoStat{ {CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "0", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312}, {CPU: 1, VendorID: "GenuineIntel", Family: "6", Model: "78", Stepping: 3, PhysicalID: "1", CoreID: "0", Cores: 1, ModelName: "Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz", Mhz: 3312}, }, }, { "2cpu_8core_psrinfo.txt", []InfoStat{ {CPU: 0, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "0", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 1, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "1", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 2, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "2", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 3, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "3", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 4, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "4", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 5, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "5", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 6, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "6", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 7, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "0", CoreID: "7", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 8, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "0", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 9, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "1", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 10, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "2", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 11, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "3", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 12, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "4", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 13, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "5", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 14, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "6", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, {CPU: 15, VendorID: "GenuineIntel", Family: "6", Model: "45", Stepping: 7, PhysicalID: "1", CoreID: "7", Cores: 2, ModelName: "Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz", Mhz: 2600}, }, }, { "2cpu_12core_psrinfo.txt", []InfoStat{ {CPU: 0, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "0", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 1, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "1", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 2, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "2", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 3, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "3", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 4, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "4", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 5, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "5", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 6, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "6", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 7, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "7", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 8, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "8", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 9, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "9", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 10, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "10", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 11, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "0", CoreID: "11", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 12, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "0", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 13, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "1", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 14, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "2", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 15, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "3", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 16, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "4", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 17, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "5", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 18, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "6", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 19, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "7", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 20, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "8", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 21, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "9", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 22, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "10", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, {CPU: 23, VendorID: "AuthenticAMD", Family: "16", Model: "9", Stepping: 1, PhysicalID: "1", CoreID: "11", Cores: 1, ModelName: "AMD Opteron(tm) Processor 6176\t[ Socket: G34 ]", Mhz: 2300}, }, }, } for _, tc := range cases { content, err := os.ReadFile(filepath.Join("testdata", "solaris", tc.filename)) if err != nil { t.Errorf("cannot read test case: %s", err) } cpus, err := parseProcessorInfo(string(content)) if err != nil { t.Errorf("cannot parse processor info: %s", err) } if !reflect.DeepEqual(tc.expected, cpus) { t.Fatalf("Bad Processor Info\nExpected: %v\n Actual: %v", tc.expected, cpus) } } } gopsutil-3.24.1/cpu/cpu_test.go000066400000000000000000000116451455407747200164410ustar00rootroot00000000000000package cpu import ( "errors" "fmt" "os" "runtime" "testing" "time" "github.com/stretchr/testify/assert" "github.com/shirou/gopsutil/v3/internal/common" ) func skipIfNotImplementedErr(t *testing.T, err error) { if errors.Is(err, common.ErrNotImplementedError) { t.Skip("not implemented") } } func TestCpu_times(t *testing.T) { v, err := Times(false) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if len(v) == 0 { t.Error("could not get CPUs ", err) } empty := TimesStat{} for _, vv := range v { if vv == empty { t.Errorf("could not get CPU User: %v", vv) } } // test sum of per cpu stats is within margin of error for cpu total stats cpuTotal, err := Times(false) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if len(cpuTotal) == 0 { t.Error("could not get CPUs", err) } perCPU, err := Times(true) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if len(perCPU) == 0 { t.Error("could not get CPUs", err) } var perCPUUserTimeSum float64 var perCPUSystemTimeSum float64 var perCPUIdleTimeSum float64 for _, pc := range perCPU { perCPUUserTimeSum += pc.User perCPUSystemTimeSum += pc.System perCPUIdleTimeSum += pc.Idle } margin := 2.0 t.Log(cpuTotal[0]) if cpuTotal[0].User == 0 && cpuTotal[0].System == 0 && cpuTotal[0].Idle == 0 { t.Error("could not get cpu values") } if cpuTotal[0].User != 0 { assert.InEpsilon(t, cpuTotal[0].User, perCPUUserTimeSum, margin) } if cpuTotal[0].System != 0 { assert.InEpsilon(t, cpuTotal[0].System, perCPUSystemTimeSum, margin) } if cpuTotal[0].Idle != 0 { assert.InEpsilon(t, cpuTotal[0].Idle, perCPUIdleTimeSum, margin) } } func TestCpu_counts(t *testing.T) { v, err := Counts(true) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if v == 0 { t.Errorf("could not get logical CPU counts: %v", v) } t.Logf("logical cores: %d", v) v, err = Counts(false) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if v == 0 { t.Errorf("could not get physical CPU counts: %v", v) } t.Logf("physical cores: %d", v) } func TestCPUTimeStat_String(t *testing.T) { v := TimesStat{ CPU: "cpu0", User: 100.1, System: 200.1, Idle: 300.1, } e := `{"cpu":"cpu0","user":100.1,"system":200.1,"idle":300.1,"nice":0.0,"iowait":0.0,"irq":0.0,"softirq":0.0,"steal":0.0,"guest":0.0,"guestNice":0.0}` if e != fmt.Sprintf("%v", v) { t.Errorf("CPUTimesStat string is invalid: %v", v) } } func TestCpuInfo(t *testing.T) { v, err := Info() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if len(v) == 0 { t.Errorf("could not get CPU Info") } for _, vv := range v { if vv.ModelName == "" { t.Errorf("could not get CPU Info: %v", vv) } } } func testCPUPercent(t *testing.T, percpu bool) { numcpu := runtime.NumCPU() testCount := 3 if runtime.GOOS != "windows" { testCount = 100 v, err := Percent(time.Millisecond, percpu) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } // Skip CI which CPU num is different if os.Getenv("CI") != "true" { if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) { t.Fatalf("wrong number of entries from CPUPercent: %v", v) } } } for i := 0; i < testCount; i++ { duration := time.Duration(10) * time.Microsecond v, err := Percent(duration, percpu) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } for _, percent := range v { // Check for slightly greater then 100% to account for any rounding issues. if percent < 0.0 || percent > 100.0001*float64(numcpu) { t.Fatalf("CPUPercent value is invalid: %f", percent) } } } } func testCPUPercentLastUsed(t *testing.T, percpu bool) { numcpu := runtime.NumCPU() testCount := 10 if runtime.GOOS != "windows" { testCount = 2 v, err := Percent(time.Millisecond, percpu) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } // Skip CI which CPU num is different if os.Getenv("CI") != "true" { if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) { t.Fatalf("wrong number of entries from CPUPercent: %v", v) } } } for i := 0; i < testCount; i++ { v, err := Percent(0, percpu) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } time.Sleep(1 * time.Millisecond) for _, percent := range v { // Check for slightly greater then 100% to account for any rounding issues. if percent < 0.0 || percent > 100.0001*float64(numcpu) { t.Fatalf("CPUPercent value is invalid: %f", percent) } } } } func TestCPUPercent(t *testing.T) { testCPUPercent(t, false) } func TestCPUPercentPerCpu(t *testing.T) { testCPUPercent(t, true) } func TestCPUPercentIntervalZero(t *testing.T) { testCPUPercentLastUsed(t, false) } func TestCPUPercentIntervalZeroPerCPU(t *testing.T) { testCPUPercentLastUsed(t, true) } gopsutil-3.24.1/cpu/cpu_windows.go000066400000000000000000000172421455407747200171530ustar00rootroot00000000000000//go:build windows // +build windows package cpu import ( "context" "fmt" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows" ) var ( procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo") ) type win32_Processor struct { Family uint16 Manufacturer string Name string NumberOfLogicalProcessors uint32 NumberOfCores uint32 ProcessorID *string Stepping *string MaxClockSpeed uint32 } // SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION // defined in windows api doc with the following // https://docs.microsoft.com/en-us/windows/desktop/api/winternl/nf-winternl-ntquerysysteminformation#system_processor_performance_information // additional fields documented here // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/processor_performance.htm type win32_SystemProcessorPerformanceInformation struct { IdleTime int64 // idle time in 100ns (this is not a filetime). KernelTime int64 // kernel time in 100ns. kernel time includes idle time. (this is not a filetime). UserTime int64 // usertime in 100ns (this is not a filetime). DpcTime int64 // dpc time in 100ns (this is not a filetime). InterruptTime int64 // interrupt time in 100ns InterruptCount uint32 } const ( ClocksPerSec = 10000000.0 // systemProcessorPerformanceInformationClass information class to query with NTQuerySystemInformation // https://processhacker.sourceforge.io/doc/ntexapi_8h.html#ad5d815b48e8f4da1ef2eb7a2f18a54e0 win32_SystemProcessorPerformanceInformationClass = 8 // size of systemProcessorPerformanceInfoSize in memory win32_SystemProcessorPerformanceInfoSize = uint32(unsafe.Sizeof(win32_SystemProcessorPerformanceInformation{})) ) // Times returns times stat per cpu and combined for all CPUs func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { if percpu { return perCPUTimes() } var ret []TimesStat var lpIdleTime common.FILETIME var lpKernelTime common.FILETIME var lpUserTime common.FILETIME r, _, _ := common.ProcGetSystemTimes.Call( uintptr(unsafe.Pointer(&lpIdleTime)), uintptr(unsafe.Pointer(&lpKernelTime)), uintptr(unsafe.Pointer(&lpUserTime))) if r == 0 { return ret, windows.GetLastError() } LOT := float64(0.0000001) HIT := (LOT * 4294967296.0) idle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime))) user := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime))) kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime))) system := (kernel - idle) ret = append(ret, TimesStat{ CPU: "cpu-total", Idle: float64(idle), User: float64(user), System: float64(system), }) return ret, nil } func Info() ([]InfoStat, error) { return InfoWithContext(context.Background()) } func InfoWithContext(ctx context.Context) ([]InfoStat, error) { var ret []InfoStat var dst []win32_Processor q := wmi.CreateQuery(&dst, "") if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil { return ret, err } var procID string for i, l := range dst { procID = "" if l.ProcessorID != nil { procID = *l.ProcessorID } cpu := InfoStat{ CPU: int32(i), Family: fmt.Sprintf("%d", l.Family), VendorID: l.Manufacturer, ModelName: l.Name, Cores: int32(l.NumberOfLogicalProcessors), PhysicalID: procID, Mhz: float64(l.MaxClockSpeed), Flags: []string{}, } ret = append(ret, cpu) } return ret, nil } // perCPUTimes returns times stat per cpu, per core and overall for all CPUs func perCPUTimes() ([]TimesStat, error) { var ret []TimesStat stats, err := perfInfo() if err != nil { return nil, err } for core, v := range stats { c := TimesStat{ CPU: fmt.Sprintf("cpu%d", core), User: float64(v.UserTime) / ClocksPerSec, System: float64(v.KernelTime-v.IdleTime) / ClocksPerSec, Idle: float64(v.IdleTime) / ClocksPerSec, Irq: float64(v.InterruptTime) / ClocksPerSec, } ret = append(ret, c) } return ret, nil } // makes call to Windows API function to retrieve performance information for each core func perfInfo() ([]win32_SystemProcessorPerformanceInformation, error) { // Make maxResults large for safety. // We can't invoke the api call with a results array that's too small. // If we have more than 2056 cores on a single host, then it's probably the future. maxBuffer := 2056 // buffer for results from the windows proc resultBuffer := make([]win32_SystemProcessorPerformanceInformation, maxBuffer) // size of the buffer in memory bufferSize := uintptr(win32_SystemProcessorPerformanceInfoSize) * uintptr(maxBuffer) // size of the returned response var retSize uint32 // Invoke windows api proc. // The returned err from the windows dll proc will always be non-nil even when successful. // See https://godoc.org/golang.org/x/sys/windows#LazyProc.Call for more information retCode, _, err := common.ProcNtQuerySystemInformation.Call( win32_SystemProcessorPerformanceInformationClass, // System Information Class -> SystemProcessorPerformanceInformation uintptr(unsafe.Pointer(&resultBuffer[0])), // pointer to first element in result buffer bufferSize, // size of the buffer in memory uintptr(unsafe.Pointer(&retSize)), // pointer to the size of the returned results the windows proc will set this ) // check return code for errors if retCode != 0 { return nil, fmt.Errorf("call to NtQuerySystemInformation returned %d. err: %s", retCode, err.Error()) } // calculate the number of returned elements based on the returned size numReturnedElements := retSize / win32_SystemProcessorPerformanceInfoSize // trim results to the number of returned elements resultBuffer = resultBuffer[:numReturnedElements] return resultBuffer, nil } // SystemInfo is an equivalent representation of SYSTEM_INFO in the Windows API. // https://msdn.microsoft.com/en-us/library/ms724958%28VS.85%29.aspx?f=255&MSPPError=-2147217396 // https://github.com/elastic/go-windows/blob/bb1581babc04d5cb29a2bfa7a9ac6781c730c8dd/kernel32.go#L43 type systemInfo struct { wProcessorArchitecture uint16 wReserved uint16 dwPageSize uint32 lpMinimumApplicationAddress uintptr lpMaximumApplicationAddress uintptr dwActiveProcessorMask uintptr dwNumberOfProcessors uint32 dwProcessorType uint32 dwAllocationGranularity uint32 wProcessorLevel uint16 wProcessorRevision uint16 } func CountsWithContext(ctx context.Context, logical bool) (int, error) { if logical { // https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L97 ret := windows.GetActiveProcessorCount(windows.ALL_PROCESSOR_GROUPS) if ret != 0 { return int(ret), nil } var systemInfo systemInfo _, _, err := procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo))) if systemInfo.dwNumberOfProcessors == 0 { return 0, err } return int(systemInfo.dwNumberOfProcessors), nil } // physical cores https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L499 // for the time being, try with unreliable and slow WMI call… var dst []win32_Processor q := wmi.CreateQuery(&dst, "") if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil { return 0, err } var count uint32 for _, d := range dst { count += d.NumberOfCores } return int(count), nil } gopsutil-3.24.1/cpu/testdata/000077500000000000000000000000001455407747200160665ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/freebsd/000077500000000000000000000000001455407747200175005ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/freebsd/1cpu_2core.txt000066400000000000000000000041761455407747200222130ustar00rootroot00000000000000Copyright (c) 1992-2016 The FreeBSD Project. Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD is a registered trademark of The FreeBSD Foundation. FreeBSD 11.0-RELEASE-p2 #0: Mon Oct 24 06:55:27 UTC 2016 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64 FreeBSD clang version 3.8.0 (tags/RELEASE_380/final 262564) (based on LLVM 3.8.0) VT(vga): resolution 640x480 CPU: Intel(R) Core(TM) i3 CPU 550 @ 3.20GHz (3192.07-MHz K8-class CPU) Origin="GenuineIntel" Id=0x20655 Family=0x6 Model=0x25 Stepping=5 Features=0xbfebfbff Features2=0x9ae3bd AMD Features=0x28100800 AMD Features2=0x1 VT-x: PAT,HLT,MTF,PAUSE,EPT,UG,VPID TSC: P-state invariant, performance statistics real memory = 8589934592 (8192 MB) avail memory = 8046452736 (7673 MB) Event timer "LAPIC" quality 600 ACPI APIC Table: FreeBSD/SMP: Multiprocessor System Detected: 4 CPUs FreeBSD/SMP: 1 package(s) x 2 core(s) x 2 hardware threads random: unblocking device. ioapic0 irqs 0-23 on motherboard random: entropy device external interface kbd1 at kbdmux0 netmap: loaded module module_register_init: MOD_LOAD (vesa, 0xffffffff8101c970, 0) error 19 vtvga0: on motherboard cryptosoft0: on motherboard aesni0: No AESNI support. acpi0: on motherboard acpi0: Power Button (fixed) cpu0: on acpi0 ACPI BIOS Warning (bug): Incorrect checksum in table [SSDT] - 0x3F, should be 0x1F (20160527/tbprint-229) cpu1: on acpi0 cpu2: on acpi0 cpu3: on acpi0 attimer0: port 0x40-0x43 irq 0 on acpi0 Timecounter "i8254" frequency 1193182 Hz quality 0 Event timer "i8254" frequency 1193182 Hz quality 100 atrtc0: port 0x70-0x71 irq 8 on acpi0 Event timer "RTC" frequency 32768 Hz quality 0gopsutil-3.24.1/cpu/testdata/freebsd/1cpu_4core.txt000066400000000000000000000035471455407747200222160ustar00rootroot00000000000000Copyright (c) 1992-2016 The FreeBSD Project. Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD is a registered trademark of The FreeBSD Foundation. FreeBSD 10.3-RELEASE-p4 #0: Sat May 28 12:23:44 UTC 2016 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64 FreeBSD clang version 3.4.1 (tags/RELEASE_34/dot1-final 208032) 20140512 CPU: Intel(R) Xeon(R) CPU E5-1620 v2 @ 3.70GHz (3700.09-MHz K8-class CPU) Origin="GenuineIntel" Id=0x306e4 Family=0x6 Model=0x3e Stepping=4 Features=0xbfebfbff Features2=0x7fbee3ff AMD Features=0x2c100800 AMD Features2=0x1 Structured Extended Features=0x281 XSAVE Features=0x1 VT-x: PAT,HLT,MTF,PAUSE,EPT,UG,VPID,VID,PostIntr TSC: P-state invariant, performance statistics real memory = 34368126976 (32776 MB) avail memory = 33228333056 (31689 MB) Event timer "LAPIC" quality 600 ACPI APIC Table: < > FreeBSD/SMP: Multiprocessor System Detected: 8 CPUs FreeBSD/SMP: 1 package(s) x 4 core(s) x 2 SMT threads cpu0 (BSP): APIC ID: 0 cpu1 (AP): APIC ID: 1 cpu2 (AP): APIC ID: 2 cpu3 (AP): APIC ID: 3 cpu4 (AP): APIC ID: 4 cpu5 (AP): APIC ID: 5 cpu6 (AP): APIC ID: 6 cpu7 (AP): APIC ID: 7 random: initialized ioapic0 irqs 0-23 on motherboard ioapic1 irqs 24-47 on motherboard kbd1 at kbdmux0 cryptosoft0: on motherboard aesni0: on motherboard acpi0: on motherboardgopsutil-3.24.1/cpu/testdata/freebsd/2cpu_4core.txt000066400000000000000000000035651455407747200222170ustar00rootroot00000000000000Copyright (c) 1992-2011 The FreeBSD Project. Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD is a registered trademark of The FreeBSD Foundation. FreeBSD 8.2-RELEASE #1: Sat Mar 5 23:03:14 CET 2011 root@host1:/usr/obj/usr/src/sys/MYKERNEL amd64 Timecounter "i8254" frequency 1193182 Hz quality 0 CPU: Intel(R) Xeon(R) CPU E5420 @ 2.50GHz (2500.11-MHz K8-class CPU) Origin = "GenuineIntel" Id = 0x10676 Family = 6 Model = 17 Stepping = 6 Features=0xbfebfbff Features2=0xce3bd AMD Features=0x20100800 AMD Features2=0x1 TSC: P-state invariant real memory = 17179869184 (16384 MB) avail memory = 16531587072 (15765 MB) ACPI APIC Table: FreeBSD/SMP: Multiprocessor System Detected: 8 CPUs FreeBSD/SMP: 2 package(s) x 4 core(s) cpu0 (BSP): APIC ID: 0 cpu1 (AP): APIC ID: 1 cpu2 (AP): APIC ID: 2 cpu3 (AP): APIC ID: 3 cpu4 (AP): APIC ID: 4 cpu5 (AP): APIC ID: 5 cpu6 (AP): APIC ID: 6 cpu7 (AP): APIC ID: 7 ioapic0 irqs 0-23 on motherboard ioapic1 irqs 24-47 on motherboard kbd1 at kbdmux0 acpi0: on motherboard acpi0: [ITHREAD] acpi0: Power Button (fixed) unknown: I/O range not supported Timecounter "ACPI-fast" frequency 3579545 Hz quality 1000 acpi_timer0: <24-bit timer at 3.579545MHz> port 0x1008-0x100b on acpi0 cpu0: on acpi0 cpu1: on acpi0 cpu2: on acpi0 cpu3: on acpi0 cpu4: on acpi0 cpu5: on acpi0 cpu6: on acpi0 cpu7: on acpi0 pcib0: port 0xcf8-0xcff on acpi0gopsutil-3.24.1/cpu/testdata/linux/000077500000000000000000000000001455407747200172255ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/linux/1037/000077500000000000000000000000001455407747200176175ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/linux/1037/proc/000077500000000000000000000000001455407747200205625ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/linux/1037/proc/cpuinfo000066400000000000000000000051751455407747200221600ustar00rootroot00000000000000processor : 0 Processor : ARMv7 Processor rev 4 (v7l) model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 42.43 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 1 Processor : ARMv7 Processor rev 4 (v7l) model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 42.43 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 2 Processor : ARMv7 Processor rev 4 (v7l) model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 42.43 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 3 Processor : ARMv7 Processor rev 4 (v7l) model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 42.43 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 4 Processor : ARMv7 Processor rev 2 (v7l) model name : ARMv7 Processor rev 2 (v7l) BogoMIPS : 29.52 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd09 CPU revision : 2 processor : 5 Processor : ARMv7 Processor rev 2 (v7l) model name : ARMv7 Processor rev 2 (v7l) BogoMIPS : 29.52 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd09 CPU revision : 2 processor : 6 Processor : ARMv7 Processor rev 2 (v7l) model name : ARMv7 Processor rev 2 (v7l) BogoMIPS : 29.52 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd09 CPU revision : 2 processor : 7 Processor : ARMv7 Processor rev 2 (v7l) model name : ARMv7 Processor rev 2 (v7l) BogoMIPS : 29.52 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd09 CPU revision : 2 Hardware : MT8183 Revision : 0000 Serial : 29aa1cf5ba0159c3 gopsutil-3.24.1/cpu/testdata/linux/424/000077500000000000000000000000001455407747200175365ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/linux/424/proc/000077500000000000000000000000001455407747200205015ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/linux/424/proc/stat000066400000000000000000000045421455407747200214040ustar00rootroot00000000000000cpu 23644 6695 4764 134931750 22115 0 473 5892 0 0 cpu0 6418 888 1230 33730755 5043 0 4 1046 0 0 cpu1 6858 4870 1632 33716510 12327 0 235 1765 0 0 cpu2 4859 622 915 33742072 2312 0 25 1546 0 0 cpu3 5507 314 986 33742411 2432 0 208 1534 0 0 intr 32552791 35 9 0 0 2335 0 3 0 2 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3107077 2985327 15704 0 6672 0 3218027 3063711 11558 0 6151 0 2160633 2194945 15838 0 6565 0 1595129 2134446 15337 0 5715 0 157 112837 717318 710764 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ctxt 41317767 btime 1505515383 processes 41562 procs_running 1 procs_blocked 0 softirq 5433315 0 1644387 67542 1428221 0 0 12270 1573783 0 707112gopsutil-3.24.1/cpu/testdata/linux/times_empty/000077500000000000000000000000001455407747200215645ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/linux/times_empty/proc/000077500000000000000000000000001455407747200225275ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/linux/times_empty/proc/stat000066400000000000000000000000001455407747200234130ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/000077500000000000000000000000001455407747200171115ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/000077500000000000000000000000001455407747200203065ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/dev/000077500000000000000000000000001455407747200210645ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/dev/cputype000066400000000000000000000000221455407747200224720ustar00rootroot00000000000000Core i7/Xeon 2403 gopsutil-3.24.1/cpu/testdata/plan9/2cores/dev/sysstat000066400000000000000000000003621455407747200225220ustar00rootroot00000000000000 0 59251106 37524162 1208203 65907 0 0 7 100 0 1 219155408 28582838 5017097 1002072 0 0 0 98 1 gopsutil-3.24.1/cpu/testdata/plan9/2cores/dev/time000066400000000000000000000001161455407747200217430ustar00rootroot00000000000000 1633882064 1633882064926300833 2825920097745864 1999997644 gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/000077500000000000000000000000001455407747200212515ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/1/000077500000000000000000000000001455407747200214115ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/1/status000066400000000000000000000002601455407747200226550ustar00rootroot00000000000000init bootes Await 10 20 1404307210 110 20 0 116 10 10 gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/331/000077500000000000000000000000001455407747200215575ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/331/.gitkeep000066400000000000000000000000001455407747200231760ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/54384/000077500000000000000000000000001455407747200217405ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/54384/status000066400000000000000000000002601455407747200232040ustar00rootroot00000000000000rc lufia Await 0 0 589160 8770 3260 0 248 10 10 gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/54412/000077500000000000000000000000001455407747200217305ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/54412/status000066400000000000000000000002601455407747200231740ustar00rootroot00000000000000git-remote-https lufia Semacquire 390 310 370670 0 0 0 98368 10 10 gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/72/000077500000000000000000000000001455407747200215015ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/plan9/2cores/proc/72/status000066400000000000000000000002601455407747200227450ustar00rootroot00000000000000httpd none Open 2380 29690 1404804330 0 0 0 23616 10 10 gopsutil-3.24.1/cpu/testdata/solaris/000077500000000000000000000000001455407747200175425ustar00rootroot00000000000000gopsutil-3.24.1/cpu/testdata/solaris/1cpu_1core_isainfo.txt000066400000000000000000000003231455407747200237520ustar00rootroot0000000000000064-bit amd64 applications rdseed adx avx2 fma bmi2 bmi1 rdrand f16c vmx avx xsave pclmulqdq aes movbe sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr mmx cmov amd_sysc cx8 tsc fpugopsutil-3.24.1/cpu/testdata/solaris/1cpu_1core_psrinfo.txt000066400000000000000000000002461455407747200240060ustar00rootroot00000000000000The physical processor has 1 virtual processor (0) x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz) Intel(r) Core(tm) i7-6567U CPU @ 3.30GHzgopsutil-3.24.1/cpu/testdata/solaris/2cpu_12core_isainfo.txt000066400000000000000000000002331455407747200240350ustar00rootroot0000000000000064-bit amd64 applications amd_svm amd_lzcnt popcnt amd_sse4a tscp ahf cx16 sse3 sse2 sse fxsr amd_3dnowx amd_3dnow amd_mmx mmx cmov amd_sysc cx8 tsc fpu gopsutil-3.24.1/cpu/testdata/solaris/2cpu_12core_psrinfo.txt000066400000000000000000000005311455407747200240660ustar00rootroot00000000000000The physical processor has 12 virtual processors (0-11) x86 (AuthenticAMD 100F91 family 16 model 9 step 1 clock 2300 MHz) AMD Opteron(tm) Processor 6176 [ Socket: G34 ] The physical processor has 12 virtual processors (12-23) x86 (AuthenticAMD 100F91 family 16 model 9 step 1 clock 2300 MHz) AMD Opteron(tm) Processor 6176 [ Socket: G34 ] gopsutil-3.24.1/cpu/testdata/solaris/2cpu_1core_isainfo.txt000066400000000000000000000003231455407747200237530ustar00rootroot0000000000000064-bit amd64 applications rdseed adx avx2 fma bmi2 bmi1 rdrand f16c vmx avx xsave pclmulqdq aes movbe sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr mmx cmov amd_sysc cx8 tsc fpugopsutil-3.24.1/cpu/testdata/solaris/2cpu_1core_psrinfo.txt000066400000000000000000000005151455407747200240060ustar00rootroot00000000000000The physical processor has 1 virtual processor (0) x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz) Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz The physical processor has 1 virtual processor (1) x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz) Intel(r) Core(tm) i7-6567U CPU @ 3.30GHzgopsutil-3.24.1/cpu/testdata/solaris/2cpu_8core_isainfo.txt000066400000000000000000000002331455407747200237620ustar00rootroot0000000000000064-bit amd64 applications vmx avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr mmx cmov amd_sysc cx8 tsc fpugopsutil-3.24.1/cpu/testdata/solaris/2cpu_8core_psrinfo.txt000066400000000000000000000020601455407747200240120ustar00rootroot00000000000000The physical processor has 8 cores and 16 virtual processors (0-7 16-23) The core has 2 virtual processors (0 16) The core has 2 virtual processors (1 17) The core has 2 virtual processors (2 18) The core has 2 virtual processors (3 19) The core has 2 virtual processors (4 20) The core has 2 virtual processors (5 21) The core has 2 virtual processors (6 22) The core has 2 virtual processors (7 23) x86 (GenuineIntel 206D7 family 6 model 45 step 7 clock 2600 MHz) Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz The physical processor has 8 cores and 16 virtual processors (8-15 24-31) The core has 2 virtual processors (8 24) The core has 2 virtual processors (9 25) The core has 2 virtual processors (10 26) The core has 2 virtual processors (11 27) The core has 2 virtual processors (12 28) The core has 2 virtual processors (13 29) The core has 2 virtual processors (14 30) The core has 2 virtual processors (15 31) x86 (GenuineIntel 206D7 family 6 model 45 step 7 clock 2600 MHz) Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHzgopsutil-3.24.1/disk/000077500000000000000000000000001455407747200144205ustar00rootroot00000000000000gopsutil-3.24.1/disk/disk.go000066400000000000000000000061431455407747200157050ustar00rootroot00000000000000package disk import ( "context" "encoding/json" "github.com/shirou/gopsutil/v3/internal/common" ) var invoke common.Invoker = common.Invoke{} type Warnings = common.Warnings type UsageStat struct { Path string `json:"path"` Fstype string `json:"fstype"` Total uint64 `json:"total"` Free uint64 `json:"free"` Used uint64 `json:"used"` UsedPercent float64 `json:"usedPercent"` InodesTotal uint64 `json:"inodesTotal"` InodesUsed uint64 `json:"inodesUsed"` InodesFree uint64 `json:"inodesFree"` InodesUsedPercent float64 `json:"inodesUsedPercent"` } type PartitionStat struct { Device string `json:"device"` Mountpoint string `json:"mountpoint"` Fstype string `json:"fstype"` Opts []string `json:"opts"` } type IOCountersStat struct { ReadCount uint64 `json:"readCount"` MergedReadCount uint64 `json:"mergedReadCount"` WriteCount uint64 `json:"writeCount"` MergedWriteCount uint64 `json:"mergedWriteCount"` ReadBytes uint64 `json:"readBytes"` WriteBytes uint64 `json:"writeBytes"` ReadTime uint64 `json:"readTime"` WriteTime uint64 `json:"writeTime"` IopsInProgress uint64 `json:"iopsInProgress"` IoTime uint64 `json:"ioTime"` WeightedIO uint64 `json:"weightedIO"` Name string `json:"name"` SerialNumber string `json:"serialNumber"` Label string `json:"label"` } func (d UsageStat) String() string { s, _ := json.Marshal(d) return string(s) } func (d PartitionStat) String() string { s, _ := json.Marshal(d) return string(s) } func (d IOCountersStat) String() string { s, _ := json.Marshal(d) return string(s) } // Usage returns a file system usage. path is a filesystem path such // as "/", not device file path like "/dev/vda1". If you want to use // a return value of disk.Partitions, use "Mountpoint" not "Device". func Usage(path string) (*UsageStat, error) { return UsageWithContext(context.Background(), path) } // Partitions returns disk partitions. If all is false, returns // physical devices only (e.g. hard disks, cd-rom drives, USB keys) // and ignore all others (e.g. memory partitions such as /dev/shm) // // 'all' argument is ignored for BSD, see: https://github.com/giampaolo/psutil/issues/906 func Partitions(all bool) ([]PartitionStat, error) { return PartitionsWithContext(context.Background(), all) } func IOCounters(names ...string) (map[string]IOCountersStat, error) { return IOCountersWithContext(context.Background(), names...) } // SerialNumber returns Serial Number of given device or empty string // on error. Name of device is expected, eg. /dev/sda func SerialNumber(name string) (string, error) { return SerialNumberWithContext(context.Background(), name) } // Label returns label of given device or empty string on error. // Name of device is expected, eg. /dev/sda // Supports label based on devicemapper name // See https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm func Label(name string) (string, error) { return LabelWithContext(context.Background(), name) } gopsutil-3.24.1/disk/disk_aix.go000066400000000000000000000007751455407747200165530ustar00rootroot00000000000000//go:build aix // +build aix package disk import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { return nil, common.ErrNotImplementedError } func SerialNumberWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } func LabelWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } gopsutil-3.24.1/disk/disk_aix_cgo.go000066400000000000000000000035621455407747200174000ustar00rootroot00000000000000//go:build aix && cgo // +build aix,cgo package disk import ( "context" "fmt" "github.com/power-devops/perfstat" ) var FSType map[int]string func init() { FSType = map[int]string{ 0: "jfs2", 1: "namefs", 2: "nfs", 3: "jfs", 5: "cdrom", 6: "proc", 16: "special-fs", 17: "cache-fs", 18: "nfs3", 19: "automount-fs", 20: "pool-fs", 32: "vxfs", 33: "veritas-fs", 34: "udfs", 35: "nfs4", 36: "nfs4-pseudo", 37: "smbfs", 38: "mcr-pseudofs", 39: "ahafs", 40: "sterm-nfs", 41: "asmfs", } } func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { f, err := perfstat.FileSystemStat() if err != nil { return nil, err } ret := make([]PartitionStat, len(f)) for _, fs := range f { fstyp, exists := FSType[fs.FSType] if !exists { fstyp = "unknown" } info := PartitionStat{ Device: fs.Device, Mountpoint: fs.MountPoint, Fstype: fstyp, } ret = append(ret, info) } return ret, err } func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) { f, err := perfstat.FileSystemStat() if err != nil { return nil, err } blocksize := uint64(512) for _, fs := range f { if path == fs.MountPoint { fstyp, exists := FSType[fs.FSType] if !exists { fstyp = "unknown" } info := UsageStat{ Path: path, Fstype: fstyp, Total: uint64(fs.TotalBlocks) * blocksize, Free: uint64(fs.FreeBlocks) * blocksize, Used: uint64(fs.TotalBlocks-fs.FreeBlocks) * blocksize, InodesTotal: uint64(fs.TotalInodes), InodesFree: uint64(fs.FreeInodes), InodesUsed: uint64(fs.TotalInodes - fs.FreeInodes), } info.UsedPercent = (float64(info.Used) / float64(info.Total)) * 100.0 info.InodesUsedPercent = (float64(info.InodesUsed) / float64(info.InodesTotal)) * 100.0 return &info, nil } } return nil, fmt.Errorf("mountpoint %s not found", path) } gopsutil-3.24.1/disk/disk_aix_nocgo.go000066400000000000000000000035631455407747200177360ustar00rootroot00000000000000//go:build aix && !cgo // +build aix,!cgo package disk import ( "context" "regexp" "strings" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/unix" ) var startBlank = regexp.MustCompile(`^\s+`) var ignoreFSType = map[string]bool{"procfs": true} var FSType = map[int]string{ 0: "jfs2", 1: "namefs", 2: "nfs", 3: "jfs", 5: "cdrom", 6: "proc", 16: "special-fs", 17: "cache-fs", 18: "nfs3", 19: "automount-fs", 20: "pool-fs", 32: "vxfs", 33: "veritas-fs", 34: "udfs", 35: "nfs4", 36: "nfs4-pseudo", 37: "smbfs", 38: "mcr-pseudofs", 39: "ahafs", 40: "sterm-nfs", 41: "asmfs", } func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { var ret []PartitionStat out, err := invoke.CommandWithContext(ctx, "mount") if err != nil { return nil, err } // parse head lines for column names colidx := make(map[string]int) lines := strings.Split(string(out), "\n") if len(lines) < 3 { return nil, common.ErrNotImplementedError } idx := 0 start := 0 finished := false for pos, ch := range lines[1] { if ch == ' ' && !finished { name := strings.TrimSpace(lines[0][start:pos]) colidx[name] = idx finished = true } else if ch == '-' && finished { idx++ start = pos finished = false } } name := strings.TrimSpace(lines[0][start:len(lines[1])]) colidx[name] = idx for idx := 2; idx < len(lines); idx++ { line := lines[idx] if startBlank.MatchString(line) { line = "localhost" + line } p := strings.Fields(lines[idx]) if len(p) < 5 || ignoreFSType[p[colidx["vfs"]]] { continue } d := PartitionStat{ Device: p[colidx["mounted"]], Mountpoint: p[colidx["mounted over"]], Fstype: p[colidx["vfs"]], Opts: strings.Split(p[colidx["options"]], ","), } ret = append(ret, d) } return ret, nil } func getFsType(stat unix.Statfs_t) string { return FSType[int(stat.Vfstype)] } gopsutil-3.24.1/disk/disk_darwin.go000066400000000000000000000046101455407747200172460ustar00rootroot00000000000000//go:build darwin // +build darwin package disk import ( "context" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/internal/common" ) // PartitionsWithContext returns disk partition. // 'all' argument is ignored, see: https://github.com/giampaolo/psutil/issues/906 func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { var ret []PartitionStat count, err := unix.Getfsstat(nil, unix.MNT_WAIT) if err != nil { return ret, err } fs := make([]unix.Statfs_t, count) count, err = unix.Getfsstat(fs, unix.MNT_WAIT) if err != nil { return ret, err } // On 10.14, and possibly other OS versions, the actual count may // be less than from the first call. Truncate to the returned count // to prevent accessing uninitialized entries. // https://github.com/shirou/gopsutil/issues/1390 fs = fs[:count] for _, stat := range fs { opts := []string{"rw"} if stat.Flags&unix.MNT_RDONLY != 0 { opts = []string{"ro"} } if stat.Flags&unix.MNT_SYNCHRONOUS != 0 { opts = append(opts, "sync") } if stat.Flags&unix.MNT_NOEXEC != 0 { opts = append(opts, "noexec") } if stat.Flags&unix.MNT_NOSUID != 0 { opts = append(opts, "nosuid") } if stat.Flags&unix.MNT_UNION != 0 { opts = append(opts, "union") } if stat.Flags&unix.MNT_ASYNC != 0 { opts = append(opts, "async") } if stat.Flags&unix.MNT_DONTBROWSE != 0 { opts = append(opts, "nobrowse") } if stat.Flags&unix.MNT_AUTOMOUNTED != 0 { opts = append(opts, "automounted") } if stat.Flags&unix.MNT_JOURNALED != 0 { opts = append(opts, "journaled") } if stat.Flags&unix.MNT_MULTILABEL != 0 { opts = append(opts, "multilabel") } if stat.Flags&unix.MNT_NOATIME != 0 { opts = append(opts, "noatime") } if stat.Flags&unix.MNT_NODEV != 0 { opts = append(opts, "nodev") } d := PartitionStat{ Device: common.ByteToString(stat.Mntfromname[:]), Mountpoint: common.ByteToString(stat.Mntonname[:]), Fstype: common.ByteToString(stat.Fstypename[:]), Opts: opts, } ret = append(ret, d) } return ret, nil } func getFsType(stat unix.Statfs_t) 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 } gopsutil-3.24.1/disk/disk_darwin_cgo.go000066400000000000000000000022541455407747200201000ustar00rootroot00000000000000//go:build darwin && cgo && !ios // +build darwin,cgo,!ios package disk /* #cgo LDFLAGS: -framework CoreFoundation -framework IOKit #include #include #include "iostat_darwin.h" */ import "C" import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { var buf [C.NDRIVE]C.DriveStats n, err := C.gopsutil_v3_readdrivestat(&buf[0], C.int(len(buf))) if err != nil { return nil, err } ret := make(map[string]IOCountersStat, 0) for i := 0; i < int(n); i++ { d := IOCountersStat{ ReadBytes: uint64(buf[i].read), WriteBytes: uint64(buf[i].written), ReadCount: uint64(buf[i].nread), WriteCount: uint64(buf[i].nwrite), ReadTime: uint64(buf[i].readtime / 1000 / 1000), // note: read/write time are in ns, but we want ms. WriteTime: uint64(buf[i].writetime / 1000 / 1000), IoTime: uint64((buf[i].readtime + buf[i].writetime) / 1000 / 1000), Name: C.GoString(&buf[i].name[0]), } if len(names) > 0 && !common.StringsHas(names, d.Name) { continue } ret[d.Name] = d } return ret, nil } gopsutil-3.24.1/disk/disk_darwin_nocgo.go000066400000000000000000000004501455407747200204310ustar00rootroot00000000000000//go:build (darwin && !cgo) || ios // +build darwin,!cgo ios package disk import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/disk/disk_fallback.go000066400000000000000000000016301455407747200175200ustar00rootroot00000000000000//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !windows && !solaris && !aix // +build !darwin,!linux,!freebsd,!openbsd,!netbsd,!windows,!solaris,!aix package disk import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { return nil, common.ErrNotImplementedError } func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { return []PartitionStat{}, common.ErrNotImplementedError } func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) { return nil, common.ErrNotImplementedError } func SerialNumberWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } func LabelWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } gopsutil-3.24.1/disk/disk_freebsd.go000066400000000000000000000112261455407747200173750ustar00rootroot00000000000000//go:build freebsd // +build freebsd package disk import ( "bufio" "bytes" "context" "encoding/binary" "fmt" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/unix" ) // PartitionsWithContext returns disk partition. // 'all' argument is ignored, see: https://github.com/giampaolo/psutil/issues/906 func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { var ret []PartitionStat // get length count, err := unix.Getfsstat(nil, unix.MNT_WAIT) if err != nil { return ret, err } fs := make([]unix.Statfs_t, count) if _, err = unix.Getfsstat(fs, unix.MNT_WAIT); err != nil { return ret, err } for _, stat := range fs { opts := []string{"rw"} if stat.Flags&unix.MNT_RDONLY != 0 { opts = []string{"ro"} } if stat.Flags&unix.MNT_SYNCHRONOUS != 0 { opts = append(opts, "sync") } if stat.Flags&unix.MNT_NOEXEC != 0 { opts = append(opts, "noexec") } if stat.Flags&unix.MNT_NOSUID != 0 { opts = append(opts, "nosuid") } if stat.Flags&unix.MNT_UNION != 0 { opts = append(opts, "union") } if stat.Flags&unix.MNT_ASYNC != 0 { opts = append(opts, "async") } if stat.Flags&unix.MNT_SUIDDIR != 0 { opts = append(opts, "suiddir") } if stat.Flags&unix.MNT_SOFTDEP != 0 { opts = append(opts, "softdep") } if stat.Flags&unix.MNT_NOSYMFOLLOW != 0 { opts = append(opts, "nosymfollow") } if stat.Flags&unix.MNT_GJOURNAL != 0 { opts = append(opts, "gjournal") } if stat.Flags&unix.MNT_MULTILABEL != 0 { opts = append(opts, "multilabel") } if stat.Flags&unix.MNT_ACLS != 0 { opts = append(opts, "acls") } if stat.Flags&unix.MNT_NOATIME != 0 { opts = append(opts, "noatime") } if stat.Flags&unix.MNT_NOCLUSTERR != 0 { opts = append(opts, "noclusterr") } if stat.Flags&unix.MNT_NOCLUSTERW != 0 { opts = append(opts, "noclusterw") } if stat.Flags&unix.MNT_NFS4ACLS != 0 { opts = append(opts, "nfsv4acls") } d := PartitionStat{ Device: common.ByteToString(stat.Mntfromname[:]), Mountpoint: common.ByteToString(stat.Mntonname[:]), Fstype: common.ByteToString(stat.Fstypename[:]), Opts: opts, } ret = append(ret, d) } return ret, nil } func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { // statinfo->devinfo->devstat // /usr/include/devinfo.h ret := make(map[string]IOCountersStat) r, err := unix.Sysctl("kern.devstat.all") if err != nil { return nil, err } buf := []byte(r) length := len(buf) count := int(uint64(length) / uint64(sizeOfdevstat)) buf = buf[8:] // devstat.all has version in the head. // parse buf to devstat for i := 0; i < count; i++ { b := buf[i*sizeOfdevstat : i*sizeOfdevstat+sizeOfdevstat] d, err := parsedevstat(b) if err != nil { continue } un := strconv.Itoa(int(d.Unit_number)) name := common.IntToString(d.Device_name[:]) + un if len(names) > 0 && !common.StringsHas(names, name) { continue } ds := IOCountersStat{ ReadCount: d.Operations[devstat_READ], WriteCount: d.Operations[devstat_WRITE], ReadBytes: d.Bytes[devstat_READ], WriteBytes: d.Bytes[devstat_WRITE], ReadTime: uint64(d.Duration[devstat_READ].Compute() * 1000), WriteTime: uint64(d.Duration[devstat_WRITE].Compute() * 1000), IoTime: uint64(d.Busy_time.Compute() * 1000), Name: name, } ds.SerialNumber, _ = SerialNumberWithContext(ctx, name) ret[name] = ds } return ret, nil } func (b bintime) Compute() float64 { BINTIME_SCALE := 5.42101086242752217003726400434970855712890625e-20 return float64(b.Sec) + float64(b.Frac)*BINTIME_SCALE } // BT2LD(time) ((long double)(time).sec + (time).frac * BINTIME_SCALE) func parsedevstat(buf []byte) (devstat, error) { var ds devstat br := bytes.NewReader(buf) // err := binary.Read(br, binary.LittleEndian, &ds) err := common.Read(br, binary.LittleEndian, &ds) if err != nil { return ds, err } return ds, nil } func getFsType(stat unix.Statfs_t) string { return common.ByteToString(stat.Fstypename[:]) } func SerialNumberWithContext(ctx context.Context, name string) (string, error) { geomOut, err := invoke.CommandWithContext(ctx, "geom", "disk", "list", name) if err != nil { return "", fmt.Errorf("exec geom: %w", err) } s := bufio.NewScanner(bytes.NewReader(geomOut)) serial := "" for s.Scan() { flds := strings.Fields(s.Text()) if len(flds) == 2 && flds[0] == "ident:" { if flds[1] != "(null)" { serial = flds[1] } break } } if err = s.Err(); err != nil { return "", err } return serial, nil } func LabelWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } gopsutil-3.24.1/disk/disk_freebsd_386.go000066400000000000000000000021171455407747200177740ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go package disk const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeofLongDouble = 0x8 devstat_NO_DATA = 0x00 devstat_READ = 0x01 devstat_WRITE = 0x02 devstat_FREE = 0x03 ) const ( sizeOfdevstat = 0xf0 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 _C_long_double int64 ) type devstat struct { Sequence0 uint32 Allocated int32 Start_count uint32 End_count uint32 Busy_from bintime Dev_links _Ctype_struct___0 Device_number uint32 Device_name [16]int8 Unit_number int32 Bytes [4]uint64 Operations [4]uint64 Duration [4]bintime Busy_time bintime Creation_time bintime Block_size uint32 Tag_types [3]uint64 Flags uint32 Device_type uint32 Priority uint32 Id *byte Sequence1 uint32 } type bintime struct { Sec int32 Frac uint64 } type _Ctype_struct___0 struct { Empty uint32 } gopsutil-3.24.1/disk/disk_freebsd_amd64.go000066400000000000000000000022251455407747200203670ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go package disk const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeofLongDouble = 0x8 devstat_NO_DATA = 0x00 devstat_READ = 0x01 devstat_WRITE = 0x02 devstat_FREE = 0x03 ) const ( sizeOfdevstat = 0x120 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 _C_long_double int64 ) type devstat struct { Sequence0 uint32 Allocated int32 Start_count uint32 End_count uint32 Busy_from bintime Dev_links _Ctype_struct___0 Device_number uint32 Device_name [16]int8 Unit_number int32 Bytes [4]uint64 Operations [4]uint64 Duration [4]bintime Busy_time bintime Creation_time bintime Block_size uint32 Pad_cgo_0 [4]byte Tag_types [3]uint64 Flags uint32 Device_type uint32 Priority uint32 Pad_cgo_1 [4]byte ID *byte Sequence1 uint32 Pad_cgo_2 [4]byte } type bintime struct { Sec int64 Frac uint64 } type _Ctype_struct___0 struct { Empty uint64 } gopsutil-3.24.1/disk/disk_freebsd_arm.go000066400000000000000000000021171455407747200202330ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go package disk const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeofLongDouble = 0x8 devstat_NO_DATA = 0x00 devstat_READ = 0x01 devstat_WRITE = 0x02 devstat_FREE = 0x03 ) const ( sizeOfdevstat = 0xf0 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 _C_long_double int64 ) type devstat struct { Sequence0 uint32 Allocated int32 Start_count uint32 End_count uint32 Busy_from bintime Dev_links _Ctype_struct___0 Device_number uint32 Device_name [16]int8 Unit_number int32 Bytes [4]uint64 Operations [4]uint64 Duration [4]bintime Busy_time bintime Creation_time bintime Block_size uint32 Tag_types [3]uint64 Flags uint32 Device_type uint32 Priority uint32 Id *byte Sequence1 uint32 } type bintime struct { Sec int32 Frac uint64 } type _Ctype_struct___0 struct { Empty uint32 } gopsutil-3.24.1/disk/disk_freebsd_arm64.go000066400000000000000000000022531455407747200204060ustar00rootroot00000000000000//go:build freebsd && arm64 // +build freebsd,arm64 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs disk/types_freebsd.go package disk const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeofLongDouble = 0x8 devstat_NO_DATA = 0x00 devstat_READ = 0x01 devstat_WRITE = 0x02 devstat_FREE = 0x03 ) const ( sizeOfdevstat = 0x120 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 _C_long_double int64 ) type devstat struct { Sequence0 uint32 Allocated int32 Start_count uint32 End_count uint32 Busy_from bintime Dev_links _Ctype_struct___0 Device_number uint32 Device_name [16]int8 Unit_number int32 Bytes [4]uint64 Operations [4]uint64 Duration [4]bintime Busy_time bintime Creation_time bintime Block_size uint32 Tag_types [3]uint64 Flags uint32 Device_type uint32 Priority uint32 Id *byte Sequence1 uint32 Pad_cgo_0 [4]byte } type bintime struct { Sec int64 Frac uint64 } type _Ctype_struct___0 struct { Empty uint64 } gopsutil-3.24.1/disk/disk_linux.go000066400000000000000000000501451455407747200171250ustar00rootroot00000000000000//go:build linux // +build linux package disk import ( "bufio" "context" "errors" "fmt" "os" "path" "path/filepath" "strconv" "strings" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/internal/common" ) const ( sectorSize = 512 ) const ( // man statfs ADFS_SUPER_MAGIC = 0xadf5 AFFS_SUPER_MAGIC = 0xADFF BDEVFS_MAGIC = 0x62646576 BEFS_SUPER_MAGIC = 0x42465331 BFS_MAGIC = 0x1BADFACE BINFMTFS_MAGIC = 0x42494e4d BTRFS_SUPER_MAGIC = 0x9123683E CGROUP_SUPER_MAGIC = 0x27e0eb CIFS_MAGIC_NUMBER = 0xFF534D42 CODA_SUPER_MAGIC = 0x73757245 COH_SUPER_MAGIC = 0x012FF7B7 CRAMFS_MAGIC = 0x28cd3d45 DEBUGFS_MAGIC = 0x64626720 DEVFS_SUPER_MAGIC = 0x1373 DEVPTS_SUPER_MAGIC = 0x1cd1 EFIVARFS_MAGIC = 0xde5e81e4 EFS_SUPER_MAGIC = 0x00414A53 EXT_SUPER_MAGIC = 0x137D EXT2_OLD_SUPER_MAGIC = 0xEF51 EXT2_SUPER_MAGIC = 0xEF53 EXT3_SUPER_MAGIC = 0xEF53 EXT4_SUPER_MAGIC = 0xEF53 FUSE_SUPER_MAGIC = 0x65735546 FUTEXFS_SUPER_MAGIC = 0xBAD1DEA HFS_SUPER_MAGIC = 0x4244 HFSPLUS_SUPER_MAGIC = 0x482b HOSTFS_SUPER_MAGIC = 0x00c0ffee HPFS_SUPER_MAGIC = 0xF995E849 HUGETLBFS_MAGIC = 0x958458f6 ISOFS_SUPER_MAGIC = 0x9660 JFFS2_SUPER_MAGIC = 0x72b6 JFS_SUPER_MAGIC = 0x3153464a MINIX_SUPER_MAGIC = 0x137F /* orig. minix */ MINIX_SUPER_MAGIC2 = 0x138F /* 30 char minix */ MINIX2_SUPER_MAGIC = 0x2468 /* minix V2 */ MINIX2_SUPER_MAGIC2 = 0x2478 /* minix V2, 30 char names */ MINIX3_SUPER_MAGIC = 0x4d5a /* minix V3 fs, 60 char names */ MQUEUE_MAGIC = 0x19800202 MSDOS_SUPER_MAGIC = 0x4d44 NCP_SUPER_MAGIC = 0x564c NFS_SUPER_MAGIC = 0x6969 NILFS_SUPER_MAGIC = 0x3434 NTFS_SB_MAGIC = 0x5346544e OCFS2_SUPER_MAGIC = 0x7461636f OPENPROM_SUPER_MAGIC = 0x9fa1 PIPEFS_MAGIC = 0x50495045 PROC_SUPER_MAGIC = 0x9fa0 PSTOREFS_MAGIC = 0x6165676C QNX4_SUPER_MAGIC = 0x002f QNX6_SUPER_MAGIC = 0x68191122 RAMFS_MAGIC = 0x858458f6 REISERFS_SUPER_MAGIC = 0x52654973 ROMFS_MAGIC = 0x7275 SELINUX_MAGIC = 0xf97cff8c SMACK_MAGIC = 0x43415d53 SMB_SUPER_MAGIC = 0x517B SOCKFS_MAGIC = 0x534F434B SQUASHFS_MAGIC = 0x73717368 SYSFS_MAGIC = 0x62656572 SYSV2_SUPER_MAGIC = 0x012FF7B6 SYSV4_SUPER_MAGIC = 0x012FF7B5 TMPFS_MAGIC = 0x01021994 UDF_SUPER_MAGIC = 0x15013346 UFS_MAGIC = 0x00011954 USBDEVICE_SUPER_MAGIC = 0x9fa2 V9FS_MAGIC = 0x01021997 VXFS_SUPER_MAGIC = 0xa501FCF5 XENFS_SUPER_MAGIC = 0xabba1974 XENIX_SUPER_MAGIC = 0x012FF7B4 XFS_SUPER_MAGIC = 0x58465342 _XIAFS_SUPER_MAGIC = 0x012FD16D AFS_SUPER_MAGIC = 0x5346414F AUFS_SUPER_MAGIC = 0x61756673 ANON_INODE_FS_SUPER_MAGIC = 0x09041934 BPF_FS_MAGIC = 0xCAFE4A11 CEPH_SUPER_MAGIC = 0x00C36400 CGROUP2_SUPER_MAGIC = 0x63677270 CONFIGFS_MAGIC = 0x62656570 ECRYPTFS_SUPER_MAGIC = 0xF15F F2FS_SUPER_MAGIC = 0xF2F52010 FAT_SUPER_MAGIC = 0x4006 FHGFS_SUPER_MAGIC = 0x19830326 FUSEBLK_SUPER_MAGIC = 0x65735546 FUSECTL_SUPER_MAGIC = 0x65735543 GFS_SUPER_MAGIC = 0x1161970 GPFS_SUPER_MAGIC = 0x47504653 MTD_INODE_FS_SUPER_MAGIC = 0x11307854 INOTIFYFS_SUPER_MAGIC = 0x2BAD1DEA ISOFS_R_WIN_SUPER_MAGIC = 0x4004 ISOFS_WIN_SUPER_MAGIC = 0x4000 JFFS_SUPER_MAGIC = 0x07C0 KAFS_SUPER_MAGIC = 0x6B414653 LUSTRE_SUPER_MAGIC = 0x0BD00BD0 NFSD_SUPER_MAGIC = 0x6E667364 NSFS_MAGIC = 0x6E736673 PANFS_SUPER_MAGIC = 0xAAD7AAEA RPC_PIPEFS_SUPER_MAGIC = 0x67596969 SECURITYFS_SUPER_MAGIC = 0x73636673 TRACEFS_MAGIC = 0x74726163 UFS_BYTESWAPPED_SUPER_MAGIC = 0x54190100 VMHGFS_SUPER_MAGIC = 0xBACBACBC VZFS_SUPER_MAGIC = 0x565A4653 ZFS_SUPER_MAGIC = 0x2FC12FC1 ) // coreutils/src/stat.c var fsTypeMap = map[int64]string{ ADFS_SUPER_MAGIC: "adfs", /* 0xADF5 local */ AFFS_SUPER_MAGIC: "affs", /* 0xADFF local */ AFS_SUPER_MAGIC: "afs", /* 0x5346414F remote */ ANON_INODE_FS_SUPER_MAGIC: "anon-inode FS", /* 0x09041934 local */ AUFS_SUPER_MAGIC: "aufs", /* 0x61756673 remote */ // AUTOFS_SUPER_MAGIC: "autofs", /* 0x0187 local */ BEFS_SUPER_MAGIC: "befs", /* 0x42465331 local */ BDEVFS_MAGIC: "bdevfs", /* 0x62646576 local */ BFS_MAGIC: "bfs", /* 0x1BADFACE local */ BINFMTFS_MAGIC: "binfmt_misc", /* 0x42494E4D local */ BPF_FS_MAGIC: "bpf", /* 0xCAFE4A11 local */ BTRFS_SUPER_MAGIC: "btrfs", /* 0x9123683E local */ CEPH_SUPER_MAGIC: "ceph", /* 0x00C36400 remote */ CGROUP_SUPER_MAGIC: "cgroupfs", /* 0x0027E0EB local */ CGROUP2_SUPER_MAGIC: "cgroup2fs", /* 0x63677270 local */ CIFS_MAGIC_NUMBER: "cifs", /* 0xFF534D42 remote */ CODA_SUPER_MAGIC: "coda", /* 0x73757245 remote */ COH_SUPER_MAGIC: "coh", /* 0x012FF7B7 local */ CONFIGFS_MAGIC: "configfs", /* 0x62656570 local */ CRAMFS_MAGIC: "cramfs", /* 0x28CD3D45 local */ DEBUGFS_MAGIC: "debugfs", /* 0x64626720 local */ DEVFS_SUPER_MAGIC: "devfs", /* 0x1373 local */ DEVPTS_SUPER_MAGIC: "devpts", /* 0x1CD1 local */ ECRYPTFS_SUPER_MAGIC: "ecryptfs", /* 0xF15F local */ EFIVARFS_MAGIC: "efivarfs", /* 0xDE5E81E4 local */ EFS_SUPER_MAGIC: "efs", /* 0x00414A53 local */ EXT_SUPER_MAGIC: "ext", /* 0x137D local */ EXT2_SUPER_MAGIC: "ext2/ext3", /* 0xEF53 local */ EXT2_OLD_SUPER_MAGIC: "ext2", /* 0xEF51 local */ F2FS_SUPER_MAGIC: "f2fs", /* 0xF2F52010 local */ FAT_SUPER_MAGIC: "fat", /* 0x4006 local */ FHGFS_SUPER_MAGIC: "fhgfs", /* 0x19830326 remote */ FUSEBLK_SUPER_MAGIC: "fuseblk", /* 0x65735546 remote */ FUSECTL_SUPER_MAGIC: "fusectl", /* 0x65735543 remote */ FUTEXFS_SUPER_MAGIC: "futexfs", /* 0x0BAD1DEA local */ GFS_SUPER_MAGIC: "gfs/gfs2", /* 0x1161970 remote */ GPFS_SUPER_MAGIC: "gpfs", /* 0x47504653 remote */ HFS_SUPER_MAGIC: "hfs", /* 0x4244 local */ HFSPLUS_SUPER_MAGIC: "hfsplus", /* 0x482b local */ HPFS_SUPER_MAGIC: "hpfs", /* 0xF995E849 local */ HUGETLBFS_MAGIC: "hugetlbfs", /* 0x958458F6 local */ MTD_INODE_FS_SUPER_MAGIC: "inodefs", /* 0x11307854 local */ INOTIFYFS_SUPER_MAGIC: "inotifyfs", /* 0x2BAD1DEA local */ ISOFS_SUPER_MAGIC: "isofs", /* 0x9660 local */ ISOFS_R_WIN_SUPER_MAGIC: "isofs", /* 0x4004 local */ ISOFS_WIN_SUPER_MAGIC: "isofs", /* 0x4000 local */ JFFS_SUPER_MAGIC: "jffs", /* 0x07C0 local */ JFFS2_SUPER_MAGIC: "jffs2", /* 0x72B6 local */ JFS_SUPER_MAGIC: "jfs", /* 0x3153464A local */ KAFS_SUPER_MAGIC: "k-afs", /* 0x6B414653 remote */ LUSTRE_SUPER_MAGIC: "lustre", /* 0x0BD00BD0 remote */ MINIX_SUPER_MAGIC: "minix", /* 0x137F local */ MINIX_SUPER_MAGIC2: "minix (30 char.)", /* 0x138F local */ MINIX2_SUPER_MAGIC: "minix v2", /* 0x2468 local */ MINIX2_SUPER_MAGIC2: "minix v2 (30 char.)", /* 0x2478 local */ MINIX3_SUPER_MAGIC: "minix3", /* 0x4D5A local */ MQUEUE_MAGIC: "mqueue", /* 0x19800202 local */ MSDOS_SUPER_MAGIC: "msdos", /* 0x4D44 local */ NCP_SUPER_MAGIC: "novell", /* 0x564C remote */ NFS_SUPER_MAGIC: "nfs", /* 0x6969 remote */ NFSD_SUPER_MAGIC: "nfsd", /* 0x6E667364 remote */ NILFS_SUPER_MAGIC: "nilfs", /* 0x3434 local */ NSFS_MAGIC: "nsfs", /* 0x6E736673 local */ NTFS_SB_MAGIC: "ntfs", /* 0x5346544E local */ OPENPROM_SUPER_MAGIC: "openprom", /* 0x9FA1 local */ OCFS2_SUPER_MAGIC: "ocfs2", /* 0x7461636f remote */ PANFS_SUPER_MAGIC: "panfs", /* 0xAAD7AAEA remote */ PIPEFS_MAGIC: "pipefs", /* 0x50495045 remote */ PROC_SUPER_MAGIC: "proc", /* 0x9FA0 local */ PSTOREFS_MAGIC: "pstorefs", /* 0x6165676C local */ QNX4_SUPER_MAGIC: "qnx4", /* 0x002F local */ QNX6_SUPER_MAGIC: "qnx6", /* 0x68191122 local */ RAMFS_MAGIC: "ramfs", /* 0x858458F6 local */ REISERFS_SUPER_MAGIC: "reiserfs", /* 0x52654973 local */ ROMFS_MAGIC: "romfs", /* 0x7275 local */ RPC_PIPEFS_SUPER_MAGIC: "rpc_pipefs", /* 0x67596969 local */ SECURITYFS_SUPER_MAGIC: "securityfs", /* 0x73636673 local */ SELINUX_MAGIC: "selinux", /* 0xF97CFF8C local */ SMB_SUPER_MAGIC: "smb", /* 0x517B remote */ SOCKFS_MAGIC: "sockfs", /* 0x534F434B local */ SQUASHFS_MAGIC: "squashfs", /* 0x73717368 local */ SYSFS_MAGIC: "sysfs", /* 0x62656572 local */ SYSV2_SUPER_MAGIC: "sysv2", /* 0x012FF7B6 local */ SYSV4_SUPER_MAGIC: "sysv4", /* 0x012FF7B5 local */ TMPFS_MAGIC: "tmpfs", /* 0x01021994 local */ TRACEFS_MAGIC: "tracefs", /* 0x74726163 local */ UDF_SUPER_MAGIC: "udf", /* 0x15013346 local */ UFS_MAGIC: "ufs", /* 0x00011954 local */ UFS_BYTESWAPPED_SUPER_MAGIC: "ufs", /* 0x54190100 local */ USBDEVICE_SUPER_MAGIC: "usbdevfs", /* 0x9FA2 local */ V9FS_MAGIC: "v9fs", /* 0x01021997 local */ VMHGFS_SUPER_MAGIC: "vmhgfs", /* 0xBACBACBC remote */ VXFS_SUPER_MAGIC: "vxfs", /* 0xA501FCF5 local */ VZFS_SUPER_MAGIC: "vzfs", /* 0x565A4653 local */ XENFS_SUPER_MAGIC: "xenfs", /* 0xABBA1974 local */ XENIX_SUPER_MAGIC: "xenix", /* 0x012FF7B4 local */ XFS_SUPER_MAGIC: "xfs", /* 0x58465342 local */ _XIAFS_SUPER_MAGIC: "xia", /* 0x012FD16D local */ ZFS_SUPER_MAGIC: "zfs", /* 0x2FC12FC1 local */ } // readMountFile reads mountinfo or mounts file under the specified root path // (eg, /proc/1, /proc/self, etc) func readMountFile(root string) (lines []string, useMounts bool, filename string, err error) { filename = path.Join(root, "mountinfo") lines, err = common.ReadLines(filename) if err != nil { var pathErr *os.PathError if !errors.As(err, &pathErr) { return } // if kernel does not support 1/mountinfo, fallback to 1/mounts (<2.6.26) useMounts = true filename = path.Join(root, "mounts") lines, err = common.ReadLines(filename) if err != nil { return } return } return } func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { // by default, try "/proc/1/..." first root := common.HostProcWithContext(ctx, path.Join("1")) // force preference for dirname of HOST_PROC_MOUNTINFO, if set #1271 hpmPath := common.HostProcMountInfoWithContext(ctx) if hpmPath != "" { root = filepath.Dir(hpmPath) } lines, useMounts, filename, err := readMountFile(root) if err != nil { if hpmPath != "" { // don't fallback with HOST_PROC_MOUNTINFO return nil, err } // fallback to "/proc/self/..." #1159 lines, useMounts, filename, err = readMountFile(common.HostProcWithContext(ctx, path.Join("self"))) if err != nil { return nil, err } } fs, err := getFileSystems(ctx) if err != nil && !all { return nil, err } ret := make([]PartitionStat, 0, len(lines)) for _, line := range lines { var d PartitionStat if useMounts { fields := strings.Fields(line) d = PartitionStat{ Device: fields[0], Mountpoint: unescapeFstab(fields[1]), Fstype: fields[2], Opts: strings.Fields(fields[3]), } if !all { if d.Device == "none" || !common.StringsHas(fs, d.Fstype) { continue } } } else { // a line of 1/mountinfo has the following structure: // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue // (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) // split the mountinfo line by the separator hyphen parts := strings.Split(line, " - ") if len(parts) != 2 { return nil, fmt.Errorf("found invalid mountinfo line in file %s: %s ", filename, line) } fields := strings.Fields(parts[0]) blockDeviceID := fields[2] mountPoint := fields[4] mountOpts := strings.Split(fields[5], ",") if rootDir := fields[3]; rootDir != "" && rootDir != "/" { mountOpts = append(mountOpts, "bind") } fields = strings.Fields(parts[1]) fstype := fields[0] device := fields[1] d = PartitionStat{ Device: device, Mountpoint: unescapeFstab(mountPoint), Fstype: fstype, Opts: mountOpts, } if !all { if d.Device == "none" || !common.StringsHas(fs, d.Fstype) { continue } } if strings.HasPrefix(d.Device, "/dev/mapper/") { devpath, err := filepath.EvalSymlinks(common.HostDevWithContext(ctx, strings.Replace(d.Device, "/dev", "", 1))) if err == nil { d.Device = devpath } } // /dev/root is not the real device name // so we get the real device name from its major/minor number if d.Device == "/dev/root" { devpath, err := os.Readlink(common.HostSysWithContext(ctx, "/dev/block/"+blockDeviceID)) if err == nil { d.Device = strings.Replace(d.Device, "root", filepath.Base(devpath), 1) } } } ret = append(ret, d) } return ret, nil } // getFileSystems returns supported filesystems from /proc/filesystems func getFileSystems(ctx context.Context) ([]string, error) { filename := common.HostProcWithContext(ctx, "filesystems") lines, err := common.ReadLines(filename) if err != nil { return nil, err } var ret []string for _, line := range lines { if !strings.HasPrefix(line, "nodev") { ret = append(ret, strings.TrimSpace(line)) continue } t := strings.Split(line, "\t") if len(t) != 2 || t[1] != "zfs" { continue } ret = append(ret, strings.TrimSpace(t[1])) } return ret, nil } func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { filename := common.HostProcWithContext(ctx, "diskstats") lines, err := common.ReadLines(filename) if err != nil { return nil, err } ret := make(map[string]IOCountersStat) empty := IOCountersStat{} // use only basename such as "/dev/sda1" to "sda1" for i, name := range names { names[i] = filepath.Base(name) } for _, line := range lines { fields := strings.Fields(line) if len(fields) < 14 { // malformed line in /proc/diskstats, avoid panic by ignoring. continue } name := fields[2] if len(names) > 0 && !common.StringsHas(names, name) { continue } reads, err := strconv.ParseUint((fields[3]), 10, 64) if err != nil { return ret, err } mergedReads, err := strconv.ParseUint((fields[4]), 10, 64) if err != nil { return ret, err } rbytes, err := strconv.ParseUint((fields[5]), 10, 64) if err != nil { return ret, err } rtime, err := strconv.ParseUint((fields[6]), 10, 64) if err != nil { return ret, err } writes, err := strconv.ParseUint((fields[7]), 10, 64) if err != nil { return ret, err } mergedWrites, err := strconv.ParseUint((fields[8]), 10, 64) if err != nil { return ret, err } wbytes, err := strconv.ParseUint((fields[9]), 10, 64) if err != nil { return ret, err } wtime, err := strconv.ParseUint((fields[10]), 10, 64) if err != nil { return ret, err } iopsInProgress, err := strconv.ParseUint((fields[11]), 10, 64) if err != nil { return ret, err } iotime, err := strconv.ParseUint((fields[12]), 10, 64) if err != nil { return ret, err } weightedIO, err := strconv.ParseUint((fields[13]), 10, 64) if err != nil { return ret, err } d := IOCountersStat{ ReadBytes: rbytes * sectorSize, WriteBytes: wbytes * sectorSize, ReadCount: reads, WriteCount: writes, MergedReadCount: mergedReads, MergedWriteCount: mergedWrites, ReadTime: rtime, WriteTime: wtime, IopsInProgress: iopsInProgress, IoTime: iotime, WeightedIO: weightedIO, } if d == empty { continue } d.Name = name // Names passed in can be full paths (/dev/sda) or just device names (sda). // Since `name` here is already a basename, re-add the /dev path. // This is not ideal, but we may break the API by changing how SerialNumberWithContext // works. d.SerialNumber, _ = SerialNumberWithContext(ctx, common.HostDevWithContext(ctx, name)) d.Label, _ = LabelWithContext(ctx, name) ret[name] = d } 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) { var stat unix.Stat_t if err := unix.Stat(name, &stat); err != nil { return "", err } major := unix.Major(uint64(stat.Rdev)) minor := unix.Minor(uint64(stat.Rdev)) sserial, _ := udevData(ctx, major, minor, "E:ID_SERIAL") if sserial != "" { return sserial, nil } // 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 devicePath := common.HostSysWithContext(ctx, fmt.Sprintf("dev/block/%d:0/device", major)) model, _ := os.ReadFile(filepath.Join(devicePath, "model")) serial, _ := os.ReadFile(filepath.Join(devicePath, "serial")) if len(model) > 0 && len(serial) > 0 { return fmt.Sprintf("%s_%s", string(model), string(serial)), nil } return "", nil } func LabelWithContext(ctx context.Context, name string) (string, error) { // Try label based on devicemapper 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) { 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)) label, err := udevData(ctx, major, minor, "E:ID_FS_LABEL") if err != nil { return "", err } return label, nil } func getFsType(stat unix.Statfs_t) string { t := int64(stat.Type) ret, ok := fsTypeMap[t] if !ok { return "" } return ret } gopsutil-3.24.1/disk/disk_netbsd.go000066400000000000000000000100251455407747200172360ustar00rootroot00000000000000//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 } gopsutil-3.24.1/disk/disk_netbsd_amd64.go000066400000000000000000000015171455407747200202370ustar00rootroot00000000000000//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 } gopsutil-3.24.1/disk/disk_netbsd_arm64.go000066400000000000000000000015171455407747200202550ustar00rootroot00000000000000//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 } gopsutil-3.24.1/disk/disk_openbsd.go000066400000000000000000000073161455407747200174220ustar00rootroot00000000000000//go:build openbsd // +build openbsd package disk import ( "bytes" "context" "encoding/binary" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/unix" ) func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { var ret []PartitionStat // get length count, err := unix.Getfsstat(nil, unix.MNT_WAIT) if err != nil { return ret, err } fs := make([]unix.Statfs_t, count) if _, err = unix.Getfsstat(fs, unix.MNT_WAIT); err != nil { return ret, err } for _, stat := range fs { opts := []string{"rw"} if stat.F_flags&unix.MNT_RDONLY != 0 { opts = []string{"rw"} } if stat.F_flags&unix.MNT_SYNCHRONOUS != 0 { opts = append(opts, "sync") } if stat.F_flags&unix.MNT_NOEXEC != 0 { opts = append(opts, "noexec") } if stat.F_flags&unix.MNT_NOSUID != 0 { opts = append(opts, "nosuid") } if stat.F_flags&unix.MNT_NODEV != 0 { opts = append(opts, "nodev") } if stat.F_flags&unix.MNT_ASYNC != 0 { opts = append(opts, "async") } if stat.F_flags&unix.MNT_SOFTDEP != 0 { opts = append(opts, "softdep") } if stat.F_flags&unix.MNT_NOATIME != 0 { opts = append(opts, "noatime") } if stat.F_flags&unix.MNT_WXALLOWED != 0 { opts = append(opts, "wxallowed") } d := PartitionStat{ Device: common.ByteToString(stat.F_mntfromname[:]), Mountpoint: common.ByteToString(stat.F_mntonname[:]), Fstype: common.ByteToString(stat.F_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) r, err := unix.SysctlRaw("hw.diskstats") if err != nil { return nil, err } buf := []byte(r) length := len(buf) count := int(uint64(length) / uint64(sizeOfDiskstats)) // parse buf to Diskstats for i := 0; i < count; i++ { b := buf[i*sizeOfDiskstats : i*sizeOfDiskstats+sizeOfDiskstats] d, err := parseDiskstats(b) if err != nil { continue } name := common.IntToString(d.Name[:]) if len(names) > 0 && !common.StringsHas(names, name) { continue } ds := IOCountersStat{ ReadCount: d.Rxfer, WriteCount: d.Wxfer, ReadBytes: d.Rbytes, WriteBytes: d.Wbytes, Name: name, } ret[name] = ds } return ret, nil } // BT2LD(time) ((long double)(time).sec + (time).frac * BINTIME_SCALE) func parseDiskstats(buf []byte) (Diskstats, error) { var ds Diskstats br := bytes.NewReader(buf) // err := binary.Read(br, binary.LittleEndian, &ds) err := common.Read(br, binary.LittleEndian, &ds) if err != nil { return ds, err } return ds, nil } func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) { stat := unix.Statfs_t{} err := unix.Statfs(path, &stat) if err != nil { return nil, err } bsize := stat.F_bsize ret := &UsageStat{ Path: path, Fstype: getFsType(stat), Total: (uint64(stat.F_blocks) * uint64(bsize)), Free: (uint64(stat.F_bavail) * uint64(bsize)), InodesTotal: (uint64(stat.F_files)), InodesFree: (uint64(stat.F_ffree)), } ret.InodesUsed = (ret.InodesTotal - ret.InodesFree) ret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0 ret.Used = (uint64(stat.F_blocks) - uint64(stat.F_bfree)) * uint64(bsize) ret.UsedPercent = (float64(ret.Used) / float64(ret.Total)) * 100.0 return ret, nil } func getFsType(stat unix.Statfs_t) string { return common.ByteToString(stat.F_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 } gopsutil-3.24.1/disk/disk_openbsd_386.go000066400000000000000000000011401455407747200200070ustar00rootroot00000000000000//go:build openbsd && 386 // +build openbsd,386 // 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 = 0x60 ) type Diskstats struct { Name [16]int8 Busy int32 Rxfer uint64 Wxfer uint64 Seek uint64 Rbytes uint64 Wbytes uint64 Attachtime Timeval Timestamp Timeval Time Timeval } type Timeval struct { Sec int64 Usec int32 } type Diskstat struct{} type bintime struct{} gopsutil-3.24.1/disk/disk_openbsd_amd64.go000066400000000000000000000010761455407747200204120ustar00rootroot00000000000000// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs 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 Pad_cgo_0 [4]byte Rxfer uint64 Wxfer uint64 Seek uint64 Rbytes uint64 Wbytes uint64 Attachtime Timeval Timestamp Timeval Time Timeval } type Timeval struct { Sec int64 Usec int64 } type Diskstat struct{} type bintime struct{} gopsutil-3.24.1/disk/disk_openbsd_arm.go000066400000000000000000000011401455407747200202460ustar00rootroot00000000000000//go:build openbsd && arm // +build openbsd,arm // 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 = 0x60 ) type Diskstats struct { Name [16]int8 Busy int32 Rxfer uint64 Wxfer uint64 Seek uint64 Rbytes uint64 Wbytes uint64 Attachtime Timeval Timestamp Timeval Time Timeval } type Timeval struct { Sec int64 Usec int32 } type Diskstat struct{} type bintime struct{} gopsutil-3.24.1/disk/disk_openbsd_arm64.go000066400000000000000000000011441455407747200204240ustar00rootroot00000000000000//go:build openbsd && arm64 // +build openbsd,arm64 // 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 } type Timeval struct { Sec int64 Usec int64 } type Diskstat struct{} type bintime struct{} gopsutil-3.24.1/disk/disk_solaris.go000066400000000000000000000156761455407747200174540ustar00rootroot00000000000000//go:build solaris // +build solaris package disk import ( "bufio" "bytes" "context" "fmt" "math" "os" "path/filepath" "regexp" "runtime" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/unix" ) const ( // _DEFAULT_NUM_MOUNTS is set to `cat /etc/mnttab | wc -l` rounded up to the // nearest power of two. _DEFAULT_NUM_MOUNTS = 32 // _MNTTAB default place to read mount information _MNTTAB = "/etc/mnttab" ) // A blacklist of read-only virtual filesystems. Writable filesystems are of // operational concern and must not be included in this list. var fsTypeBlacklist = map[string]struct{}{ "ctfs": {}, "dev": {}, "fd": {}, "lofs": {}, "lxproc": {}, "mntfs": {}, "objfs": {}, "proc": {}, } func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { ret := make([]PartitionStat, 0, _DEFAULT_NUM_MOUNTS) // Scan mnttab(4) f, err := os.Open(_MNTTAB) if err != nil { } defer func() { if err == nil { err = f.Close() } else { f.Close() } }() scanner := bufio.NewScanner(f) for scanner.Scan() { fields := strings.Split(scanner.Text(), "\t") if _, found := fsTypeBlacklist[fields[2]]; found { continue } ret = append(ret, PartitionStat{ // NOTE(seanc@): Device isn't exactly accurate: from mnttab(4): "The name // of the resource that has been mounted." Ideally this value would come // from Statvfs_t.Fsid but I'm leaving it to the caller to traverse // unix.Statvfs(). Device: fields[0], Mountpoint: fields[1], Fstype: fields[2], Opts: strings.Split(fields[3], ","), }) } if err := scanner.Err(); err != nil { return nil, fmt.Errorf("unable to scan %q: %w", _MNTTAB, err) } return ret, err } var kstatSplit = regexp.MustCompile(`[:\s]+`) func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { var issolaris bool if runtime.GOOS == "illumos" { issolaris = false } else { issolaris = true } // check disks instead of zfs pools filterstr := "/[^zfs]/:::/^nread$|^nwritten$|^reads$|^writes$|^rtime$|^wtime$/" kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-c", "disk", "-p", filterstr) if err != nil { return nil, fmt.Errorf("cannot execute kstat: %w", err) } lines := strings.Split(strings.TrimSpace(string(kstatSysOut)), "\n") if len(lines) == 0 { return nil, fmt.Errorf("no disk class found") } dnamearr := make(map[string]string) nreadarr := make(map[string]uint64) nwrittenarr := make(map[string]uint64) readsarr := make(map[string]uint64) writesarr := make(map[string]uint64) rtimearr := make(map[string]uint64) wtimearr := make(map[string]uint64) // in case the name is "/dev/sda1", then convert to "sda1" for i, name := range names { names[i] = filepath.Base(name) } for _, line := range lines { fields := kstatSplit.Split(line, -1) if len(fields) == 0 { continue } moduleName := fields[0] instance := fields[1] dname := fields[2] if len(names) > 0 && !common.StringsHas(names, dname) { continue } dnamearr[moduleName+instance] = dname // fields[3] is the statistic label, fields[4] is the value switch fields[3] { case "nread": nreadarr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64) if err != nil { return nil, err } case "nwritten": nwrittenarr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64) if err != nil { return nil, err } case "reads": readsarr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64) if err != nil { return nil, err } case "writes": writesarr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64) if err != nil { return nil, err } case "rtime": if issolaris { // from sec to milli secs var frtime float64 frtime, err = strconv.ParseFloat((fields[4]), 64) rtimearr[moduleName+instance] = uint64(frtime * 1000) } else { // from nano to milli secs rtimearr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64) rtimearr[moduleName+instance] = rtimearr[moduleName+instance] / 1000 / 1000 } if err != nil { return nil, err } case "wtime": if issolaris { // from sec to milli secs var fwtime float64 fwtime, err = strconv.ParseFloat((fields[4]), 64) wtimearr[moduleName+instance] = uint64(fwtime * 1000) } else { // from nano to milli secs wtimearr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64) wtimearr[moduleName+instance] = wtimearr[moduleName+instance] / 1000 / 1000 } if err != nil { return nil, err } } } ret := make(map[string]IOCountersStat, 0) for k := range dnamearr { d := IOCountersStat{ Name: dnamearr[k], ReadBytes: nreadarr[k], WriteBytes: nwrittenarr[k], ReadCount: readsarr[k], WriteCount: writesarr[k], ReadTime: rtimearr[k], WriteTime: wtimearr[k], } ret[d.Name] = d } return ret, nil } func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) { statvfs := unix.Statvfs_t{} if err := unix.Statvfs(path, &statvfs); err != nil { return nil, fmt.Errorf("unable to call statvfs(2) on %q: %w", path, err) } usageStat := &UsageStat{ Path: path, Fstype: common.IntToString(statvfs.Basetype[:]), Total: statvfs.Blocks * statvfs.Frsize, Free: statvfs.Bfree * statvfs.Frsize, Used: (statvfs.Blocks - statvfs.Bfree) * statvfs.Frsize, // NOTE: ZFS (and FreeBZSD's UFS2) use dynamic inode/dnode allocation. // Explicitly return a near-zero value for InodesUsedPercent so that nothing // attempts to garbage collect based on a lack of available inodes/dnodes. // Similarly, don't use the zero value to prevent divide-by-zero situations // and inject a faux near-zero value. Filesystems evolve. Has your // filesystem evolved? Probably not if you care about the number of // available inodes. InodesTotal: 1024.0 * 1024.0, InodesUsed: 1024.0, InodesFree: math.MaxUint64, InodesUsedPercent: (1024.0 / (1024.0 * 1024.0)) * 100.0, } usageStat.UsedPercent = (float64(usageStat.Used) / float64(usageStat.Total)) * 100.0 return usageStat, nil } func SerialNumberWithContext(ctx context.Context, name string) (string, error) { out, err := invoke.CommandWithContext(ctx, "cfgadm", "-ls", "select=type(disk),cols=ap_id:info,cols2=,noheadings") if err != nil { return "", fmt.Errorf("exec cfgadm: %w", err) } suf := "::" + strings.TrimPrefix(name, "/dev/") s := bufio.NewScanner(bytes.NewReader(out)) for s.Scan() { flds := strings.Fields(s.Text()) if strings.HasSuffix(flds[0], suf) { flen := len(flds) if flen >= 3 { for i, f := range flds { if i > 0 && i < flen-1 && f == "SN:" { return flds[i+1], nil } } } return "", nil } } if err := s.Err(); err != nil { return "", err } return "", nil } func LabelWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } gopsutil-3.24.1/disk/disk_test.go000066400000000000000000000057311455407747200167460ustar00rootroot00000000000000package disk import ( "errors" "fmt" "runtime" "sync" "testing" "github.com/shirou/gopsutil/v3/internal/common" ) func skipIfNotImplementedErr(t *testing.T, err error) { if errors.Is(err, common.ErrNotImplementedError) { t.Skip("not implemented") } } func TestDisk_usage(t *testing.T) { path := "/" if runtime.GOOS == "windows" { path = "C:" } v, err := Usage(path) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if v.Path != path { t.Errorf("error %v", err) } } func TestDisk_partitions(t *testing.T) { ret, err := Partitions(false) skipIfNotImplementedErr(t, err) if err != nil || len(ret) == 0 { t.Errorf("error %v", err) } t.Log(ret) if len(ret) == 0 { t.Errorf("ret is empty") } for _, disk := range ret { if disk.Device == "" { t.Errorf("Could not get device info %v", disk) } } } func TestDisk_io_counters(t *testing.T) { ret, err := IOCounters() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if len(ret) == 0 { t.Errorf("ret is empty") } empty := IOCountersStat{} for part, io := range ret { t.Log(part, io) if io == empty { t.Errorf("io_counter error %v, %v", part, io) } } } // https://github.com/shirou/gopsutil/issues/560 regression test func TestDisk_io_counters_concurrency_on_darwin_cgo(t *testing.T) { if runtime.GOOS != "darwin" { t.Skip("darwin only") } var wg sync.WaitGroup const max = 1000 for i := 1; i < max; i++ { wg.Add(1) go func() { defer wg.Done() IOCounters() }() } wg.Wait() } func TestDiskUsageStat_String(t *testing.T) { v := UsageStat{ Path: "/", Total: 1000, Free: 2000, Used: 3000, UsedPercent: 50.1, InodesTotal: 4000, InodesUsed: 5000, InodesFree: 6000, InodesUsedPercent: 49.1, Fstype: "ext4", } e := `{"path":"/","fstype":"ext4","total":1000,"free":2000,"used":3000,"usedPercent":50.1,"inodesTotal":4000,"inodesUsed":5000,"inodesFree":6000,"inodesUsedPercent":49.1}` if e != fmt.Sprintf("%v", v) { t.Errorf("DiskUsageStat string is invalid: %v", v) } } func TestDiskPartitionStat_String(t *testing.T) { v := PartitionStat{ Device: "sd01", Mountpoint: "/", Fstype: "ext4", Opts: []string{"ro"}, } e := `{"device":"sd01","mountpoint":"/","fstype":"ext4","opts":["ro"]}` if e != fmt.Sprintf("%v", v) { t.Errorf("DiskUsageStat string is invalid: %v", v) } } func TestDiskIOCountersStat_String(t *testing.T) { v := IOCountersStat{ Name: "sd01", ReadCount: 100, WriteCount: 200, ReadBytes: 300, WriteBytes: 400, SerialNumber: "SERIAL", } e := `{"readCount":100,"mergedReadCount":0,"writeCount":200,"mergedWriteCount":0,"readBytes":300,"writeBytes":400,"readTime":0,"writeTime":0,"iopsInProgress":0,"ioTime":0,"weightedIO":0,"name":"sd01","serialNumber":"SERIAL","label":""}` if e != fmt.Sprintf("%v", v) { t.Errorf("DiskUsageStat string is invalid: %v", v) } } gopsutil-3.24.1/disk/disk_unix.go000066400000000000000000000030451455407747200167460ustar00rootroot00000000000000//go:build freebsd || linux || darwin || (aix && !cgo) // +build freebsd linux darwin aix,!cgo package disk import ( "context" "strconv" "golang.org/x/sys/unix" ) func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) { stat := unix.Statfs_t{} err := unix.Statfs(path, &stat) if err != nil { return nil, err } bsize := stat.Bsize ret := &UsageStat{ Path: unescapeFstab(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.Used = (uint64(stat.Blocks) - uint64(stat.Bfree)) * uint64(bsize) if (ret.Used + ret.Free) == 0 { ret.UsedPercent = 0 } else { // We don't use ret.Total to calculate percent. // see https://github.com/shirou/gopsutil/issues/562 ret.UsedPercent = (float64(ret.Used) / float64(ret.Used+ret.Free)) * 100.0 } // if could not get InodesTotal, return empty if ret.InodesTotal < ret.InodesFree { return ret, nil } ret.InodesUsed = (ret.InodesTotal - ret.InodesFree) if ret.InodesTotal == 0 { ret.InodesUsedPercent = 0 } else { ret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0 } return ret, nil } // Unescape escaped octal chars (like space 040, ampersand 046 and backslash 134) to their real value in fstab fields issue#555 func unescapeFstab(path string) string { escaped, err := strconv.Unquote(`"` + path + `"`) if err != nil { return path } return escaped } gopsutil-3.24.1/disk/disk_windows.go000066400000000000000000000167071455407747200174660ustar00rootroot00000000000000//go:build windows // +build windows package disk import ( "bytes" "context" "fmt" "syscall" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/windows" "golang.org/x/sys/windows/registry" ) var ( procGetDiskFreeSpaceExW = common.Modkernel32.NewProc("GetDiskFreeSpaceExW") procGetLogicalDriveStringsW = common.Modkernel32.NewProc("GetLogicalDriveStringsW") procGetDriveType = common.Modkernel32.NewProc("GetDriveTypeW") procGetVolumeInformation = common.Modkernel32.NewProc("GetVolumeInformationW") ) var ( fileFileCompression = int64(16) // 0x00000010 fileReadOnlyVolume = int64(524288) // 0x00080000 ) // diskPerformance is an equivalent representation of DISK_PERFORMANCE in the Windows API. // https://docs.microsoft.com/fr-fr/windows/win32/api/winioctl/ns-winioctl-disk_performance type diskPerformance struct { BytesRead int64 BytesWritten int64 ReadTime int64 WriteTime int64 IdleTime int64 ReadCount uint32 WriteCount uint32 QueueDepth uint32 SplitCount uint32 QueryTime int64 StorageDeviceNumber uint32 StorageManagerName [8]uint16 alignmentPadding uint32 // necessary for 32bit support, see https://github.com/elastic/beats/pull/16553 } func init() { // enable disk performance counters on Windows Server editions (needs to run as admin) key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Services\PartMgr`, registry.SET_VALUE) if err == nil { key.SetDWordValue("EnableCounterForIoctl", 1) key.Close() } } func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) { lpFreeBytesAvailable := int64(0) lpTotalNumberOfBytes := int64(0) lpTotalNumberOfFreeBytes := int64(0) diskret, _, err := procGetDiskFreeSpaceExW.Call( uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))), uintptr(unsafe.Pointer(&lpFreeBytesAvailable)), uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)), uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes))) if diskret == 0 { return nil, err } ret := &UsageStat{ Path: path, Total: uint64(lpTotalNumberOfBytes), Free: uint64(lpTotalNumberOfFreeBytes), Used: uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes), UsedPercent: (float64(lpTotalNumberOfBytes) - float64(lpTotalNumberOfFreeBytes)) / float64(lpTotalNumberOfBytes) * 100, // InodesTotal: 0, // InodesFree: 0, // InodesUsed: 0, // InodesUsedPercent: 0, } return ret, nil } // PartitionsWithContext returns disk partitions. // Since GetVolumeInformation doesn't have a timeout, this method uses context to set deadline by users. func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) { warnings := Warnings{ Verbose: true, } var errLogicalDrives error retChan := make(chan PartitionStat) quitChan := make(chan struct{}) defer close(quitChan) getPartitions := func() { defer close(retChan) lpBuffer := make([]byte, 254) diskret, _, err := procGetLogicalDriveStringsW.Call( uintptr(len(lpBuffer)), uintptr(unsafe.Pointer(&lpBuffer[0]))) if diskret == 0 { errLogicalDrives = err return } for _, v := range lpBuffer { if v >= 65 && v <= 90 { path := string(v) + ":" typepath, _ := windows.UTF16PtrFromString(path) typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath))) if typeret == 0 { err := windows.GetLastError() warnings.Add(err) continue } // 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 4: DRIVE_REMOTE 5: DRIVE_CDROM if typeret == 2 || typeret == 3 || typeret == 4 || typeret == 5 { lpVolumeNameBuffer := make([]byte, 256) lpVolumeSerialNumber := int64(0) lpMaximumComponentLength := int64(0) lpFileSystemFlags := int64(0) lpFileSystemNameBuffer := make([]byte, 256) volpath, _ := windows.UTF16PtrFromString(string(v) + ":/") driveret, _, err := procGetVolumeInformation.Call( uintptr(unsafe.Pointer(volpath)), uintptr(unsafe.Pointer(&lpVolumeNameBuffer[0])), uintptr(len(lpVolumeNameBuffer)), uintptr(unsafe.Pointer(&lpVolumeSerialNumber)), uintptr(unsafe.Pointer(&lpMaximumComponentLength)), uintptr(unsafe.Pointer(&lpFileSystemFlags)), uintptr(unsafe.Pointer(&lpFileSystemNameBuffer[0])), uintptr(len(lpFileSystemNameBuffer))) if driveret == 0 { if typeret == 5 || typeret == 2 { continue // device is not ready will happen if there is no disk in the drive } warnings.Add(err) continue } opts := []string{"rw"} if lpFileSystemFlags&fileReadOnlyVolume != 0 { opts = []string{"ro"} } if lpFileSystemFlags&fileFileCompression != 0 { opts = append(opts, "compress") } select { case retChan <- PartitionStat{ Mountpoint: path, Device: path, Fstype: string(bytes.ReplaceAll(lpFileSystemNameBuffer, []byte("\x00"), []byte(""))), Opts: opts, }: case <-quitChan: return } } } } } go getPartitions() var ret []PartitionStat for { select { case p, ok := <-retChan: if !ok { if errLogicalDrives != nil { return ret, errLogicalDrives } return ret, warnings.Reference() } ret = append(ret, p) case <-ctx.Done(): return ret, ctx.Err() } } } func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { // https://github.com/giampaolo/psutil/blob/544e9daa4f66a9f80d7bf6c7886d693ee42f0a13/psutil/arch/windows/disk.c#L83 drivemap := make(map[string]IOCountersStat, 0) var diskPerformance diskPerformance lpBuffer := make([]uint16, 254) lpBufferLen, err := windows.GetLogicalDriveStrings(uint32(len(lpBuffer)), &lpBuffer[0]) if err != nil { return drivemap, err } for _, v := range lpBuffer[:lpBufferLen] { if 'A' <= v && v <= 'Z' { path := string(rune(v)) + ":" typepath, _ := windows.UTF16PtrFromString(path) typeret := windows.GetDriveType(typepath) if typeret == 0 { return drivemap, windows.GetLastError() } if typeret != windows.DRIVE_FIXED { continue } 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 err == windows.ERROR_FILE_NOT_FOUND { continue } return drivemap, err } defer windows.CloseHandle(h) var diskPerformanceSize uint32 err = windows.DeviceIoControl(h, IOCTL_DISK_PERFORMANCE, nil, 0, (*byte)(unsafe.Pointer(&diskPerformance)), uint32(unsafe.Sizeof(diskPerformance)), &diskPerformanceSize, nil) if err != nil { return drivemap, err } drivemap[path] = IOCountersStat{ ReadBytes: uint64(diskPerformance.BytesRead), WriteBytes: uint64(diskPerformance.BytesWritten), ReadCount: uint64(diskPerformance.ReadCount), WriteCount: uint64(diskPerformance.WriteCount), ReadTime: uint64(diskPerformance.ReadTime / 10000 / 1000), // convert to ms: https://github.com/giampaolo/psutil/issues/1012 WriteTime: uint64(diskPerformance.WriteTime / 10000 / 1000), Name: path, } } } return drivemap, nil } func SerialNumberWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } func LabelWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } gopsutil-3.24.1/disk/iostat_darwin.c000066400000000000000000000074201455407747200174360ustar00rootroot00000000000000// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.c #include #include #include "iostat_darwin.h" #define IOKIT 1 /* to get io_name_t in device_types.h */ #include #include #include #include #include static int getdrivestat(io_registry_entry_t d, DriveStats *stat); static int fillstat(io_registry_entry_t d, DriveStats *stat); int gopsutil_v3_readdrivestat(DriveStats a[], int n) { CFMutableDictionaryRef match; io_iterator_t drives; io_registry_entry_t d; kern_return_t status; int na, rv; match = IOServiceMatching("IOMedia"); CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue); status = IOServiceGetMatchingServices(0, match, &drives); if(status != KERN_SUCCESS) return -1; na = 0; while(na < n && (d=IOIteratorNext(drives)) > 0){ rv = getdrivestat(d, &a[na]); if(rv < 0) return -1; if(rv > 0) na++; IOObjectRelease(d); } IOObjectRelease(drives); return na; } static int getdrivestat(io_registry_entry_t d, DriveStats *stat) { io_registry_entry_t parent; kern_return_t status; CFDictionaryRef props; CFStringRef name; CFNumberRef num; int rv; memset(stat, 0, sizeof *stat); status = IORegistryEntryGetParentEntry(d, kIOServicePlane, &parent); if(status != KERN_SUCCESS) return -1; if(!IOObjectConformsTo(parent, "IOBlockStorageDriver")){ IOObjectRelease(parent); return 0; } status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions); if(status != KERN_SUCCESS){ IOObjectRelease(parent); return -1; } name = (CFStringRef)CFDictionaryGetValue(props, CFSTR(kIOBSDNameKey)); CFStringGetCString(name, stat->name, NAMELEN, CFStringGetSystemEncoding()); num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaSizeKey)); CFNumberGetValue(num, kCFNumberSInt64Type, &stat->size); num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaPreferredBlockSizeKey)); CFNumberGetValue(num, kCFNumberSInt64Type, &stat->blocksize); CFRelease(props); rv = fillstat(parent, stat); IOObjectRelease(parent); if(rv < 0) return -1; return 1; } static struct { char *key; size_t off; } statstab[] = { {kIOBlockStorageDriverStatisticsBytesReadKey, offsetof(DriveStats, read)}, {kIOBlockStorageDriverStatisticsBytesWrittenKey, offsetof(DriveStats, written)}, {kIOBlockStorageDriverStatisticsReadsKey, offsetof(DriveStats, nread)}, {kIOBlockStorageDriverStatisticsWritesKey, offsetof(DriveStats, nwrite)}, {kIOBlockStorageDriverStatisticsTotalReadTimeKey, offsetof(DriveStats, readtime)}, {kIOBlockStorageDriverStatisticsTotalWriteTimeKey, offsetof(DriveStats, writetime)}, {kIOBlockStorageDriverStatisticsLatentReadTimeKey, offsetof(DriveStats, readlat)}, {kIOBlockStorageDriverStatisticsLatentWriteTimeKey, offsetof(DriveStats, writelat)}, }; static int fillstat(io_registry_entry_t d, DriveStats *stat) { CFDictionaryRef props, v; CFNumberRef num; kern_return_t status; typeof(statstab[0]) *bp, *ep; status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions); if(status != KERN_SUCCESS) return -1; v = (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOBlockStorageDriverStatisticsKey)); if(v == NULL){ CFRelease(props); return -1; } ep = &statstab[sizeof(statstab)/sizeof(statstab[0])]; for(bp = &statstab[0]; bp < ep; bp++){ CFStringRef s; s = CFStringCreateWithCString(kCFAllocatorDefault, bp->key, CFStringGetSystemEncoding()); num = (CFNumberRef)CFDictionaryGetValue(v, s); if(num) CFNumberGetValue(num, kCFNumberSInt64Type, ((char*)stat)+bp->off); CFRelease(s); } CFRelease(props); return 0; } gopsutil-3.24.1/disk/iostat_darwin.h000066400000000000000000000011101455407747200174310ustar00rootroot00000000000000// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.h typedef struct DriveStats DriveStats; typedef struct CPUStats CPUStats; enum { NDRIVE = 16, NAMELEN = 31 }; struct DriveStats { char name[NAMELEN+1]; int64_t size; int64_t blocksize; int64_t read; int64_t written; int64_t nread; int64_t nwrite; int64_t readtime; int64_t writetime; int64_t readlat; int64_t writelat; }; struct CPUStats { natural_t user; natural_t nice; natural_t sys; natural_t idle; }; extern int gopsutil_v3_readdrivestat(DriveStats a[], int n); gopsutil-3.24.1/disk/types_freebsd.go000066400000000000000000000021721455407747200176070ustar00rootroot00000000000000//go:build ignore // +build ignore // Hand writing: _Ctype_struct___0 /* Input to cgo -godefs. */ package disk /* #include #include #include enum { sizeofPtr = sizeof(void*), }; // because statinfo has long double snap_time, redefine with changing long long struct statinfo2 { long cp_time[CPUSTATES]; long tk_nin; long tk_nout; struct devinfo *dinfo; long long snap_time; }; */ import "C" // Machine characteristics; for internal use. const ( sizeofPtr = C.sizeofPtr sizeofShort = C.sizeof_short sizeofInt = C.sizeof_int sizeofLong = C.sizeof_long sizeofLongLong = C.sizeof_longlong sizeofLongDouble = C.sizeof_longlong devstat_NO_DATA = 0x00 devstat_READ = 0x01 devstat_WRITE = 0x02 devstat_FREE = 0x03 ) const ( sizeOfdevstat = C.sizeof_struct_devstat ) // Basic types type ( _C_short C.short _C_int C.int _C_long C.long _C_long_long C.longlong _C_long_double C.longlong ) type ( devstat C.struct_devstat bintime C.struct_bintime ) gopsutil-3.24.1/disk/types_netbsd.go000066400000000000000000000006111455407747200174500ustar00rootroot00000000000000//go:build ignore // +build ignore // Hand writing: _Ctype_struct___0 /* Input to cgo -godefs. */ package disk /* #include #include #include #include #include #include #include */ import "C" const ( sizeOfStatvfs = C.sizeof_struct_statvfs ) type ( Statvfs C.struct_statvfs ) gopsutil-3.24.1/disk/types_openbsd.go000066400000000000000000000007601455407747200176300ustar00rootroot00000000000000//go:build ignore // +build ignore // Hand writing: _Ctype_struct___0 /* Input to cgo -godefs. */ package disk /* #include #include #include */ import "C" const ( devstat_NO_DATA = 0x00 devstat_READ = 0x01 devstat_WRITE = 0x02 devstat_FREE = 0x03 ) const ( sizeOfDiskstats = C.sizeof_struct_diskstats ) type ( Diskstats C.struct_diskstats Timeval C.struct_timeval ) type ( Diskstat C.struct_diskstat bintime C.struct_bintime ) gopsutil-3.24.1/doc.go000066400000000000000000000000211455407747200145530ustar00rootroot00000000000000package gopsutil gopsutil-3.24.1/docker/000077500000000000000000000000001455407747200147355ustar00rootroot00000000000000gopsutil-3.24.1/docker/docker.go000066400000000000000000000047711455407747200165440ustar00rootroot00000000000000package docker import ( "encoding/json" "errors" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" ) var ( ErrDockerNotAvailable = errors.New("docker not available") ErrCgroupNotAvailable = errors.New("cgroup not available") ) var invoke common.Invoker = common.Invoke{} const nanoseconds = 1e9 type CgroupCPUStat struct { cpu.TimesStat Usage float64 } type CgroupMemStat struct { ContainerID string `json:"containerID"` Cache uint64 `json:"cache"` RSS uint64 `json:"rss"` RSSHuge uint64 `json:"rssHuge"` MappedFile uint64 `json:"mappedFile"` Pgpgin uint64 `json:"pgpgin"` Pgpgout uint64 `json:"pgpgout"` Pgfault uint64 `json:"pgfault"` Pgmajfault uint64 `json:"pgmajfault"` InactiveAnon uint64 `json:"inactiveAnon"` ActiveAnon uint64 `json:"activeAnon"` InactiveFile uint64 `json:"inactiveFile"` ActiveFile uint64 `json:"activeFile"` Unevictable uint64 `json:"unevictable"` HierarchicalMemoryLimit uint64 `json:"hierarchicalMemoryLimit"` TotalCache uint64 `json:"totalCache"` TotalRSS uint64 `json:"totalRss"` TotalRSSHuge uint64 `json:"totalRssHuge"` TotalMappedFile uint64 `json:"totalMappedFile"` TotalPgpgIn uint64 `json:"totalPgpgin"` TotalPgpgOut uint64 `json:"totalPgpgout"` TotalPgFault uint64 `json:"totalPgfault"` TotalPgMajFault uint64 `json:"totalPgmajfault"` TotalInactiveAnon uint64 `json:"totalInactiveAnon"` TotalActiveAnon uint64 `json:"totalActiveAnon"` TotalInactiveFile uint64 `json:"totalInactiveFile"` TotalActiveFile uint64 `json:"totalActiveFile"` TotalUnevictable uint64 `json:"totalUnevictable"` MemUsageInBytes uint64 `json:"memUsageInBytes"` MemMaxUsageInBytes uint64 `json:"memMaxUsageInBytes"` MemLimitInBytes uint64 `json:"memoryLimitInBytes"` MemFailCnt uint64 `json:"memoryFailcnt"` } func (m CgroupMemStat) String() string { s, _ := json.Marshal(m) return string(s) } type CgroupDockerStat struct { ContainerID string `json:"containerID"` Name string `json:"name"` Image string `json:"image"` Status string `json:"status"` Running bool `json:"running"` } func (c CgroupDockerStat) String() string { s, _ := json.Marshal(c) return string(s) } gopsutil-3.24.1/docker/docker_linux.go000066400000000000000000000213141455407747200177530ustar00rootroot00000000000000//go:build linux // +build linux package docker import ( "context" "errors" "fmt" "os" "os/exec" "path" "strconv" "strings" cpu "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" ) // GetDockerStat returns a list of Docker basic stats. // This requires certain permission. func GetDockerStat() ([]CgroupDockerStat, error) { return GetDockerStatWithContext(context.Background()) } func GetDockerStatWithContext(ctx context.Context) ([]CgroupDockerStat, error) { out, err := invoke.CommandWithContext(ctx, "docker", "ps", "-a", "--no-trunc", "--format", "{{.ID}}|{{.Image}}|{{.Names}}|{{.Status}}") if err != nil { if errors.Is(err, exec.ErrNotFound) { return nil, ErrDockerNotAvailable } return []CgroupDockerStat{}, err } lines := strings.Split(string(out), "\n") ret := make([]CgroupDockerStat, 0, len(lines)) for _, l := range lines { if l == "" { continue } cols := strings.Split(l, "|") if len(cols) != 4 { continue } names := strings.Split(cols[2], ",") stat := CgroupDockerStat{ ContainerID: cols[0], Name: names[0], Image: cols[1], Status: cols[3], Running: strings.Contains(cols[3], "Up"), } ret = append(ret, stat) } return ret, nil } // GetDockerIDList returns a list of DockerID. // This requires certain permission. func GetDockerIDList() ([]string, error) { return GetDockerIDListWithContext(context.Background()) } func GetDockerIDListWithContext(ctx context.Context) ([]string, error) { out, err := invoke.CommandWithContext(ctx, "docker", "ps", "-q", "--no-trunc") if err != nil { if errors.Is(err, exec.ErrNotFound) { return nil, ErrDockerNotAvailable } return []string{}, err } lines := strings.Split(string(out), "\n") ret := make([]string, 0, len(lines)) for _, l := range lines { if l == "" { continue } ret = append(ret, l) } return ret, nil } // CgroupCPU returns specified cgroup id CPU status. // containerID is same as docker id if you use docker. // If you use container via systemd.slice, you could use // containerID = docker-.scope and base=/sys/fs/cgroup/cpuacct/system.slice/ func CgroupCPU(containerID string, base string) (*CgroupCPUStat, error) { return CgroupCPUWithContext(context.Background(), containerID, base) } // CgroupCPUUsage returns specified cgroup id CPU usage. // containerID is same as docker id if you use docker. // If you use container via systemd.slice, you could use // containerID = docker-.scope and base=/sys/fs/cgroup/cpuacct/system.slice/ func CgroupCPUUsage(containerID string, base string) (float64, error) { return CgroupCPUUsageWithContext(context.Background(), containerID, base) } func CgroupCPUWithContext(ctx context.Context, containerID string, base string) (*CgroupCPUStat, error) { statfile := getCgroupFilePath(ctx, containerID, base, "cpuacct", "cpuacct.stat") lines, err := common.ReadLines(statfile) if err != nil { return nil, err } // empty containerID means all cgroup if len(containerID) == 0 { containerID = "all" } ret := &CgroupCPUStat{} ret.CPU = containerID for _, line := range lines { fields := strings.Split(line, " ") if fields[0] == "user" { user, err := strconv.ParseFloat(fields[1], 64) if err == nil { ret.User = user / cpu.ClocksPerSec } } if fields[0] == "system" { system, err := strconv.ParseFloat(fields[1], 64) if err == nil { ret.System = system / cpu.ClocksPerSec } } } usage, err := CgroupCPUUsageWithContext(ctx, containerID, base) if err != nil { return nil, err } ret.Usage = usage return ret, nil } func CgroupCPUUsageWithContext(ctx context.Context, containerID, base string) (float64, error) { usagefile := getCgroupFilePath(ctx, containerID, base, "cpuacct", "cpuacct.usage") lines, err := common.ReadLinesOffsetN(usagefile, 0, 1) if err != nil { return 0.0, err } ns, err := strconv.ParseFloat(lines[0], 64) if err != nil { return 0.0, err } return ns / nanoseconds, nil } func CgroupCPUDocker(containerid string) (*CgroupCPUStat, error) { return CgroupCPUDockerWithContext(context.Background(), containerid) } func CgroupCPUUsageDocker(containerid string) (float64, error) { return CgroupCPUDockerUsageWithContext(context.Background(), containerid) } func CgroupCPUDockerWithContext(ctx context.Context, containerid string) (*CgroupCPUStat, error) { return CgroupCPUWithContext(ctx, containerid, common.HostSysWithContext(ctx, "fs/cgroup/cpuacct/docker")) } func CgroupCPUDockerUsageWithContext(ctx context.Context, containerid string) (float64, error) { return CgroupCPUUsageWithContext(ctx, containerid, common.HostSysWithContext(ctx, "fs/cgroup/cpuacct/docker")) } func CgroupMem(containerID string, base string) (*CgroupMemStat, error) { return CgroupMemWithContext(context.Background(), containerID, base) } func CgroupMemWithContext(ctx context.Context, containerID string, base string) (*CgroupMemStat, error) { statfile := getCgroupFilePath(ctx, containerID, base, "memory", "memory.stat") // empty containerID means all cgroup if len(containerID) == 0 { containerID = "all" } lines, err := common.ReadLines(statfile) if err != nil { return nil, err } ret := &CgroupMemStat{ContainerID: containerID} for _, line := range lines { fields := strings.Split(line, " ") v, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } switch fields[0] { case "cache": ret.Cache = v case "rss": ret.RSS = v case "rssHuge": ret.RSSHuge = v case "mappedFile": ret.MappedFile = v case "pgpgin": ret.Pgpgin = v case "pgpgout": ret.Pgpgout = v case "pgfault": ret.Pgfault = v case "pgmajfault": ret.Pgmajfault = v case "inactiveAnon", "inactive_anon": ret.InactiveAnon = v case "activeAnon", "active_anon": ret.ActiveAnon = v case "inactiveFile", "inactive_file": ret.InactiveFile = v case "activeFile", "active_file": ret.ActiveFile = v case "unevictable": ret.Unevictable = v case "hierarchicalMemoryLimit", "hierarchical_memory_limit": ret.HierarchicalMemoryLimit = v case "totalCache", "total_cache": ret.TotalCache = v case "totalRss", "total_rss": ret.TotalRSS = v case "totalRssHuge", "total_rss_huge": ret.TotalRSSHuge = v case "totalMappedFile", "total_mapped_file": ret.TotalMappedFile = v case "totalPgpgin", "total_pgpgin": ret.TotalPgpgIn = v case "totalPgpgout", "total_pgpgout": ret.TotalPgpgOut = v case "totalPgfault", "total_pgfault": ret.TotalPgFault = v case "totalPgmajfault", "total_pgmajfault": ret.TotalPgMajFault = v case "totalInactiveAnon", "total_inactive_anon": ret.TotalInactiveAnon = v case "totalActiveAnon", "total_active_anon": ret.TotalActiveAnon = v case "totalInactiveFile", "total_inactive_file": ret.TotalInactiveFile = v case "totalActiveFile", "total_active_file": ret.TotalActiveFile = v case "totalUnevictable", "total_unevictable": ret.TotalUnevictable = v } } r, err := getCgroupMemFile(ctx, containerID, base, "memory.usage_in_bytes") if err == nil { ret.MemUsageInBytes = r } r, err = getCgroupMemFile(ctx, containerID, base, "memory.max_usage_in_bytes") if err == nil { ret.MemMaxUsageInBytes = r } r, err = getCgroupMemFile(ctx, containerID, base, "memory.limit_in_bytes") if err == nil { ret.MemLimitInBytes = r } r, err = getCgroupMemFile(ctx, containerID, base, "memory.failcnt") if err == nil { ret.MemFailCnt = r } return ret, nil } func CgroupMemDocker(containerID string) (*CgroupMemStat, error) { return CgroupMemDockerWithContext(context.Background(), containerID) } func CgroupMemDockerWithContext(ctx context.Context, containerID string) (*CgroupMemStat, error) { return CgroupMemWithContext(ctx, containerID, common.HostSysWithContext(ctx, "fs/cgroup/memory/docker")) } // getCgroupFilePath constructs file path to get targeted stats file. func getCgroupFilePath(ctx context.Context, containerID, base, target, file string) string { if len(base) == 0 { base = common.HostSysWithContext(ctx, fmt.Sprintf("fs/cgroup/%s/docker", target)) } statfile := path.Join(base, containerID, file) if _, err := os.Stat(statfile); os.IsNotExist(err) { statfile = path.Join( common.HostSysWithContext(ctx, fmt.Sprintf("fs/cgroup/%s/system.slice", target)), "docker-"+containerID+".scope", file) } return statfile } // getCgroupMemFile reads a cgroup file and return the contents as uint64. func getCgroupMemFile(ctx context.Context, containerID, base, file string) (uint64, error) { statfile := getCgroupFilePath(ctx, containerID, base, "memory", file) lines, err := common.ReadLines(statfile) if err != nil { return 0, err } if len(lines) != 1 { return 0, fmt.Errorf("wrong format file: %s", statfile) } return strconv.ParseUint(lines[0], 10, 64) } gopsutil-3.24.1/docker/docker_linux_test.go000066400000000000000000000031621455407747200210130ustar00rootroot00000000000000//go:build linux // +build linux package docker import ( "context" "testing" ) func TestGetDockerIDList(t *testing.T) { // If there is not docker environment, this test always fail. // not tested here /* _, err := GetDockerIDList() if err != nil { t.Errorf("error %v", err) } */ } func TestGetDockerStat(t *testing.T) { // If there is not docker environment, this test always fail. // not tested here /* ret, err := GetDockerStat() if err != nil { t.Errorf("error %v", err) } if len(ret) == 0 { t.Errorf("ret is empty") } empty := CgroupDockerStat{} for _, v := range ret { if empty == v { t.Errorf("empty CgroupDockerStat") } if v.ContainerID == "" { t.Errorf("Could not get container id") } } */ } func TestCgroupCPU(t *testing.T) { v, _ := GetDockerIDList() for _, id := range v { v, err := CgroupCPUDockerWithContext(context.Background(), id) if err != nil { t.Errorf("error %v", err) } if v.CPU == "" { t.Errorf("could not get CgroupCPU %v", v) } } } func TestCgroupCPUInvalidId(t *testing.T) { _, err := CgroupCPUDockerWithContext(context.Background(), "bad id") if err == nil { t.Error("Expected path does not exist error") } } func TestCgroupMem(t *testing.T) { v, _ := GetDockerIDList() for _, id := range v { v, err := CgroupMemDocker(id) if err != nil { t.Errorf("error %v", err) } empty := &CgroupMemStat{} if v == empty { t.Errorf("Could not CgroupMemStat %v", v) } } } func TestCgroupMemInvalidId(t *testing.T) { _, err := CgroupMemDocker("bad id") if err == nil { t.Error("Expected path does not exist error") } } gopsutil-3.24.1/docker/docker_notlinux.go000066400000000000000000000043451455407747200205010ustar00rootroot00000000000000//go:build !linux // +build !linux package docker import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) // GetDockerStat returns a list of Docker basic stats. // This requires certain permission. func GetDockerStat() ([]CgroupDockerStat, error) { return GetDockerStatWithContext(context.Background()) } func GetDockerStatWithContext(ctx context.Context) ([]CgroupDockerStat, error) { return nil, ErrDockerNotAvailable } // GetDockerIDList returns a list of DockerID. // This requires certain permission. func GetDockerIDList() ([]string, error) { return GetDockerIDListWithContext(context.Background()) } func GetDockerIDListWithContext(ctx context.Context) ([]string, error) { return nil, ErrDockerNotAvailable } // CgroupCPU returns specified cgroup id CPU status. // containerid is same as docker id if you use docker. // If you use container via systemd.slice, you could use // containerid = docker-.scope and base=/sys/fs/cgroup/cpuacct/system.slice/ func CgroupCPU(containerid string, base string) (*CgroupCPUStat, error) { return CgroupCPUWithContext(context.Background(), containerid, base) } func CgroupCPUWithContext(ctx context.Context, containerid string, base string) (*CgroupCPUStat, error) { return nil, ErrCgroupNotAvailable } func CgroupCPUDocker(containerid string) (*CgroupCPUStat, error) { return CgroupCPUDockerWithContext(context.Background(), containerid) } func CgroupCPUDockerWithContext(ctx context.Context, containerid string) (*CgroupCPUStat, error) { return CgroupCPUWithContext(ctx, containerid, common.HostSysWithContext(ctx, "fs/cgroup/cpuacct/docker")) } func CgroupMem(containerid string, base string) (*CgroupMemStat, error) { return CgroupMemWithContext(context.Background(), containerid, base) } func CgroupMemWithContext(ctx context.Context, containerid string, base string) (*CgroupMemStat, error) { return nil, ErrCgroupNotAvailable } func CgroupMemDocker(containerid string) (*CgroupMemStat, error) { return CgroupMemDockerWithContext(context.Background(), containerid) } func CgroupMemDockerWithContext(ctx context.Context, containerid string) (*CgroupMemStat, error) { return CgroupMemWithContext(ctx, containerid, common.HostSysWithContext(ctx, "fs/cgroup/memory/docker")) } gopsutil-3.24.1/docker/main_test.go000066400000000000000000000005041455407747200172460ustar00rootroot00000000000000package docker import ( "fmt" "testing" ) func TestSysAdvancedDockerInfo(t *testing.T) { list, err := GetDockerIDList() if err != nil { fmt.Println(err) } for _, item := range list { fmt.Println(item) } /*docker,err := SysAdvancedDockerInfo() if err!= nil{ fmt.Println(err) } fmt.Printf("%#v",docker)*/ } gopsutil-3.24.1/go.mod000066400000000000000000000006411455407747200145750ustar00rootroot00000000000000module github.com/shirou/gopsutil/v3 go 1.15 require ( 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/shoenig/go-m1cpu v0.1.6 github.com/stretchr/testify v1.8.4 github.com/tklauser/go-sysconf v0.3.12 github.com/yusufpapurcu/wmi v1.2.3 golang.org/x/sys v0.16.0 ) retract v3.22.11 gopsutil-3.24.1/go.sum000066400000000000000000000076341455407747200146330ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/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.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/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= 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/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/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-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopsutil-3.24.1/host/000077500000000000000000000000001455407747200144435ustar00rootroot00000000000000gopsutil-3.24.1/host/freebsd_headers/000077500000000000000000000000001455407747200175505ustar00rootroot00000000000000gopsutil-3.24.1/host/freebsd_headers/utxdb.h000066400000000000000000000043171455407747200210540ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2010 Ed Schouten * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _UTXDB_H_ #define _UTXDB_H_ #include #define _PATH_UTX_ACTIVE "/var/run/utx.active" #define _PATH_UTX_LASTLOGIN "/var/log/utx.lastlogin" #define _PATH_UTX_LOG "/var/log/utx.log" /* * Entries in struct futx are ordered by how often they are used. In * utx.log only entries will be written until the last non-zero byte, * which means we want to put the hostname at the end. Most primitive * records only store a ut_type and ut_tv, which means we want to store * those at the front. */ struct utmpx; struct futx { uint8_t fu_type; uint64_t fu_tv; char fu_id[8]; uint32_t fu_pid; char fu_user[32]; char fu_line[16]; char fu_host[128]; } __packed; void utx_to_futx(const struct utmpx *, struct futx *); struct utmpx *futx_to_utx(const struct futx *); #endif /* !_UTXDB_H_ */ gopsutil-3.24.1/host/host.go000066400000000000000000000111671455407747200157550ustar00rootroot00000000000000package host import ( "context" "encoding/json" "errors" "os" "runtime" "time" "github.com/shirou/gopsutil/v3/internal/common" ) type Warnings = common.Warnings var invoke common.Invoker = common.Invoke{} // A HostInfoStat describes the host status. // This is not in the psutil but it useful. type InfoStat struct { Hostname string `json:"hostname"` Uptime uint64 `json:"uptime"` BootTime uint64 `json:"bootTime"` Procs uint64 `json:"procs"` // number of processes OS string `json:"os"` // ex: freebsd, linux Platform string `json:"platform"` // ex: ubuntu, linuxmint PlatformFamily string `json:"platformFamily"` // ex: debian, rhel PlatformVersion string `json:"platformVersion"` // version of the complete OS KernelVersion string `json:"kernelVersion"` // version of the OS kernel (if available) KernelArch string `json:"kernelArch"` // native cpu architecture queried at runtime, as returned by `uname -m` or empty string in case of error VirtualizationSystem string `json:"virtualizationSystem"` VirtualizationRole string `json:"virtualizationRole"` // guest or host HostID string `json:"hostId"` // ex: uuid } type UserStat struct { User string `json:"user"` Terminal string `json:"terminal"` Host string `json:"host"` Started int `json:"started"` } type TemperatureStat struct { SensorKey string `json:"sensorKey"` Temperature float64 `json:"temperature"` High float64 `json:"sensorHigh"` Critical float64 `json:"sensorCritical"` } func (h InfoStat) String() string { s, _ := json.Marshal(h) return string(s) } func (u UserStat) String() string { s, _ := json.Marshal(u) return string(s) } func (t TemperatureStat) String() string { s, _ := json.Marshal(t) 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) { return InfoWithContext(context.Background()) } func InfoWithContext(ctx context.Context) (*InfoStat, error) { var err error ret := &InfoStat{ OS: runtime.GOOS, } ret.Hostname, err = os.Hostname() if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } ret.Platform, ret.PlatformFamily, ret.PlatformVersion, err = PlatformInformationWithContext(ctx) if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } ret.KernelVersion, err = KernelVersionWithContext(ctx) if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } ret.KernelArch, err = KernelArch() if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } ret.VirtualizationSystem, ret.VirtualizationRole, err = VirtualizationWithContext(ctx) if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } ret.BootTime, err = BootTimeWithContext(ctx) if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } ret.Uptime, err = UptimeWithContext(ctx) if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } ret.Procs, err = numProcs(ctx) if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } ret.HostID, err = HostIDWithContext(ctx) if err != nil && !errors.Is(err, common.ErrNotImplementedError) { return nil, err } return ret, nil } // BootTime returns the system boot time expressed in seconds since the epoch. func BootTime() (uint64, error) { return BootTimeWithContext(context.Background()) } func Uptime() (uint64, error) { return UptimeWithContext(context.Background()) } func Users() ([]UserStat, error) { return UsersWithContext(context.Background()) } func PlatformInformation() (string, string, string, error) { return PlatformInformationWithContext(context.Background()) } // HostID returns the unique host ID provided by the OS. func HostID() (string, error) { return HostIDWithContext(context.Background()) } func Virtualization() (string, string, error) { return VirtualizationWithContext(context.Background()) } func KernelVersion() (string, error) { return KernelVersionWithContext(context.Background()) } func SensorsTemperatures() ([]TemperatureStat, error) { return SensorsTemperaturesWithContext(context.Background()) } func timeSince(ts uint64) uint64 { return uint64(time.Now().Unix()) - ts } func timeSinceMillis(ts uint64) uint64 { return uint64(time.Now().UnixMilli()) - ts } gopsutil-3.24.1/host/host_bsd.go000066400000000000000000000014351455407747200166020ustar00rootroot00000000000000//go:build darwin || freebsd || openbsd || netbsd // +build darwin freebsd openbsd netbsd package host import ( "context" "sync/atomic" "golang.org/x/sys/unix" ) // cachedBootTime must be accessed via atomic.Load/StoreUint64 var cachedBootTime uint64 func BootTimeWithContext(ctx context.Context) (uint64, error) { if enableBootTimeCache { t := atomic.LoadUint64(&cachedBootTime) if t != 0 { return t, nil } } tv, err := unix.SysctlTimeval("kern.boottime") if err != nil { return 0, err } if enableBootTimeCache { atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec)) } return uint64(tv.Sec), nil } func UptimeWithContext(ctx context.Context) (uint64, error) { boot, err := BootTimeWithContext(ctx) if err != nil { return 0, err } return timeSince(boot), nil } gopsutil-3.24.1/host/host_darwin.go000066400000000000000000000054041455407747200173160ustar00rootroot00000000000000//go:build darwin // +build darwin package host import ( "bytes" "context" "encoding/binary" "errors" "io" "os" "strings" "unsafe" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/process" ) // from utmpx.h const user_PROCESS = 7 func HostIDWithContext(ctx context.Context) (string, error) { out, err := invoke.CommandWithContext(ctx, "ioreg", "-rd1", "-c", "IOPlatformExpertDevice") if err != nil { return "", err } for _, line := range strings.Split(string(out), "\n") { if strings.Contains(line, "IOPlatformUUID") { parts := strings.SplitAfter(line, `" = "`) if len(parts) == 2 { uuid := strings.TrimRight(parts[1], `"`) return strings.ToLower(uuid), nil } } } return "", errors.New("cannot find host id") } func numProcs(ctx context.Context) (uint64, error) { procs, err := process.PidsWithContext(ctx) if err != nil { return 0, err } return uint64(len(procs)), nil } func UsersWithContext(ctx context.Context) ([]UserStat, error) { utmpfile := "/var/run/utmpx" var ret []UserStat file, err := os.Open(utmpfile) if err != nil { return ret, err } defer file.Close() buf, err := io.ReadAll(file) if err != nil { return ret, err } // Skip macOS utmpx header part buf = buf[604:] u := Utmpx{} entrySize := int(unsafe.Sizeof(u)) count := len(buf) / entrySize for i := 0; i < count; i++ { b := buf[i*entrySize : i*entrySize+entrySize] var u Utmpx br := bytes.NewReader(b) err := binary.Read(br, binary.LittleEndian, &u) if err != nil { continue } if u.Type != user_PROCESS { continue } user := UserStat{ User: common.IntToString(u.User[:]), Terminal: common.IntToString(u.Line[:]), Host: common.IntToString(u.Host[:]), Started: int(u.Tv.Sec), } ret = append(ret, user) } return ret, nil } func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) { platform := "" family := "" pver := "" p, err := unix.Sysctl("kern.ostype") if err == nil { platform = strings.ToLower(p) } out, err := invoke.CommandWithContext(ctx, "sw_vers", "-productVersion") if err == nil { pver = strings.ToLower(strings.TrimSpace(string(out))) } // check if the macos server version file exists _, err = os.Stat("/System/Library/CoreServices/ServerVersion.plist") // server file doesn't exist if os.IsNotExist(err) { family = "Standalone Workstation" } else { family = "Server" } return platform, family, pver, nil } func VirtualizationWithContext(ctx context.Context) (string, string, error) { return "", "", common.ErrNotImplementedError } func KernelVersionWithContext(ctx context.Context) (string, error) { version, err := unix.Sysctl("kern.osrelease") return strings.ToLower(version), err } gopsutil-3.24.1/host/host_darwin_amd64.go000066400000000000000000000004771455407747200203160ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_darwin.go package host type Utmpx struct { User [256]int8 ID [4]int8 Line [32]int8 Pid int32 Type int16 Pad_cgo_0 [6]byte Tv Timeval Host [256]int8 Pad [16]uint32 } type Timeval struct { Sec int32 } gopsutil-3.24.1/host/host_darwin_arm64.go000066400000000000000000000005601455407747200203250ustar00rootroot00000000000000//go:build darwin && arm64 // +build darwin,arm64 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs host/types_darwin.go package host type Utmpx struct { User [256]int8 Id [4]int8 Line [32]int8 Pid int32 Type int16 Tv Timeval Host [256]int8 Pad [16]uint32 } type Timeval struct { Sec int64 Usec int32 Pad_cgo_0 [4]byte } gopsutil-3.24.1/host/host_darwin_cgo.go000066400000000000000000000020011455407747200201340ustar00rootroot00000000000000//go:build darwin && cgo // +build darwin,cgo package host // #cgo LDFLAGS: -framework IOKit // #include "smc_darwin.h" import "C" import "context" func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { temperatureKeys := []string{ C.AMBIENT_AIR_0, C.AMBIENT_AIR_1, C.CPU_0_DIODE, C.CPU_0_HEATSINK, C.CPU_0_PROXIMITY, C.ENCLOSURE_BASE_0, C.ENCLOSURE_BASE_1, C.ENCLOSURE_BASE_2, C.ENCLOSURE_BASE_3, C.GPU_0_DIODE, C.GPU_0_HEATSINK, C.GPU_0_PROXIMITY, C.HARD_DRIVE_BAY, C.MEMORY_SLOT_0, C.MEMORY_SLOTS_PROXIMITY, C.NORTHBRIDGE, C.NORTHBRIDGE_DIODE, C.NORTHBRIDGE_PROXIMITY, C.THUNDERBOLT_0, C.THUNDERBOLT_1, C.WIRELESS_MODULE, } var temperatures []TemperatureStat C.gopsutil_v3_open_smc() defer C.gopsutil_v3_close_smc() for _, key := range temperatureKeys { temperatures = append(temperatures, TemperatureStat{ SensorKey: key, Temperature: float64(C.gopsutil_v3_get_temperature(C.CString(key))), }) } return temperatures, nil } gopsutil-3.24.1/host/host_darwin_nocgo.go000066400000000000000000000004331455407747200205000ustar00rootroot00000000000000//go:build darwin && !cgo // +build darwin,!cgo package host import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { return []TemperatureStat{}, common.ErrNotImplementedError } gopsutil-3.24.1/host/host_fallback.go000066400000000000000000000025641455407747200175750ustar00rootroot00000000000000//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows // +build !darwin,!linux,!freebsd,!openbsd,!netbsd,!solaris,!windows package host import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func HostIDWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func numProcs(ctx context.Context) (uint64, error) { return 0, common.ErrNotImplementedError } func BootTimeWithContext(ctx context.Context) (uint64, error) { return 0, common.ErrNotImplementedError } func UptimeWithContext(ctx context.Context) (uint64, error) { return 0, common.ErrNotImplementedError } func UsersWithContext(ctx context.Context) ([]UserStat, error) { return []UserStat{}, common.ErrNotImplementedError } func VirtualizationWithContext(ctx context.Context) (string, string, error) { return "", "", common.ErrNotImplementedError } func KernelVersionWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) { return "", "", "", common.ErrNotImplementedError } func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { return []TemperatureStat{}, common.ErrNotImplementedError } func KernelArch() (string, error) { return "", common.ErrNotImplementedError } gopsutil-3.24.1/host/host_freebsd.go000066400000000000000000000062121455407747200174420ustar00rootroot00000000000000//go:build freebsd // +build freebsd package host import ( "bytes" "context" "encoding/binary" "io" "math" "os" "strings" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/process" "golang.org/x/sys/unix" ) const ( UTNameSize = 16 /* see MAXLOGNAME in */ UTLineSize = 8 UTHostSize = 16 ) func HostIDWithContext(ctx context.Context) (string, error) { uuid, err := unix.Sysctl("kern.hostuuid") if err != nil { return "", err } return strings.ToLower(uuid), err } func numProcs(ctx context.Context) (uint64, error) { procs, err := process.PidsWithContext(ctx) if err != nil { return 0, err } return uint64(len(procs)), nil } func UsersWithContext(ctx context.Context) ([]UserStat, error) { utmpfile := "/var/run/utx.active" if !common.PathExists(utmpfile) { utmpfile = "/var/run/utmp" // before 9.0 return getUsersFromUtmp(utmpfile) } var ret []UserStat file, err := os.Open(utmpfile) if err != nil { return ret, err } defer file.Close() buf, err := io.ReadAll(file) if err != nil { return ret, err } entrySize := sizeOfUtmpx count := len(buf) / entrySize for i := 0; i < count; i++ { b := buf[i*sizeOfUtmpx : (i+1)*sizeOfUtmpx] var u Utmpx br := bytes.NewReader(b) err := binary.Read(br, binary.BigEndian, &u) if err != nil || u.Type != 4 { continue } sec := math.Floor(float64(u.Tv) / 1000000) user := UserStat{ User: common.IntToString(u.User[:]), Terminal: common.IntToString(u.Line[:]), Host: common.IntToString(u.Host[:]), Started: int(sec), } ret = append(ret, user) } return ret, nil } func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) { platform, err := unix.Sysctl("kern.ostype") if err != nil { return "", "", "", err } version, err := unix.Sysctl("kern.osrelease") if err != nil { return "", "", "", err } return strings.ToLower(platform), "", strings.ToLower(version), nil } func VirtualizationWithContext(ctx context.Context) (string, string, error) { return "", "", common.ErrNotImplementedError } // before 9.0 func getUsersFromUtmp(utmpfile string) ([]UserStat, error) { var ret []UserStat file, err := os.Open(utmpfile) if err != nil { return ret, err } defer file.Close() buf, err := io.ReadAll(file) if err != nil { return ret, err } u := Utmp{} entrySize := int(unsafe.Sizeof(u)) count := len(buf) / entrySize for i := 0; i < count; i++ { b := buf[i*entrySize : i*entrySize+entrySize] var u Utmp br := bytes.NewReader(b) err := binary.Read(br, binary.LittleEndian, &u) if err != nil || u.Time == 0 { continue } user := UserStat{ User: common.IntToString(u.Name[:]), Terminal: common.IntToString(u.Line[:]), Host: common.IntToString(u.Host[:]), Started: int(u.Time), } ret = append(ret, user) } return ret, nil } 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 } gopsutil-3.24.1/host/host_freebsd_386.go000066400000000000000000000010221455407747200200340ustar00rootroot00000000000000// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs types_freebsd.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmpx = 0xc5 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type Utmp struct { Line [8]int8 Name [16]int8 Host [16]int8 Time int32 } type Utmpx struct { Type uint8 Tv uint64 Id [8]int8 Pid uint32 User [32]int8 Line [16]int8 Host [128]int8 } gopsutil-3.24.1/host/host_freebsd_amd64.go000066400000000000000000000010221455407747200204270ustar00rootroot00000000000000// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs types_freebsd.go package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmpx = 0xc5 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type Utmp struct { Line [8]int8 Name [16]int8 Host [16]int8 Time int32 } type Utmpx struct { Type uint8 Tv uint64 Id [8]int8 Pid uint32 User [32]int8 Line [16]int8 Host [128]int8 } gopsutil-3.24.1/host/host_freebsd_arm.go000066400000000000000000000010221455407747200202730ustar00rootroot00000000000000// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs types_freebsd.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmpx = 0xc5 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type Utmp struct { Line [8]int8 Name [16]int8 Host [16]int8 Time int32 } type Utmpx struct { Type uint8 Tv uint64 Id [8]int8 Pid uint32 User [32]int8 Line [16]int8 Host [128]int8 } gopsutil-3.24.1/host/host_freebsd_arm64.go000066400000000000000000000011141455407747200204470ustar00rootroot00000000000000//go:build freebsd && arm64 // +build freebsd,arm64 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs host/types_freebsd.go package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmpx = 0xc5 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type Utmp struct { Line [8]int8 Name [16]int8 Host [16]int8 Time int32 } type Utmpx struct { Type uint8 Tv uint64 Id [8]int8 Pid uint32 User [32]int8 Line [16]int8 Host [128]int8 } gopsutil-3.24.1/host/host_linux.go000066400000000000000000000366221455407747200171770ustar00rootroot00000000000000//go:build linux // +build linux package host import ( "bytes" "context" "encoding/binary" "fmt" "io" "os" "path/filepath" "regexp" "strconv" "strings" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/internal/common" ) type lsbStruct struct { ID string Release string Codename string Description string } // from utmp.h const ( user_PROCESS = 7 hostTemperatureScale = 1000.0 ) func HostIDWithContext(ctx context.Context) (string, error) { sysProductUUID := common.HostSysWithContext(ctx, "class/dmi/id/product_uuid") machineID := common.HostEtcWithContext(ctx, "machine-id") procSysKernelRandomBootID := common.HostProcWithContext(ctx, "sys/kernel/random/boot_id") switch { // In order to read this file, needs to be supported by kernel/arch and run as root // so having fallback is important case common.PathExists(sysProductUUID): lines, err := common.ReadLines(sysProductUUID) if err == nil && len(lines) > 0 && lines[0] != "" { return strings.ToLower(lines[0]), nil } fallthrough // Fallback on GNU Linux systems with systemd, readable by everyone case common.PathExists(machineID): lines, err := common.ReadLines(machineID) if err == nil && len(lines) > 0 && len(lines[0]) == 32 { st := lines[0] return fmt.Sprintf("%s-%s-%s-%s-%s", st[0:8], st[8:12], st[12:16], st[16:20], st[20:32]), nil } fallthrough // Not stable between reboot, but better than nothing default: lines, err := common.ReadLines(procSysKernelRandomBootID) if err == nil && len(lines) > 0 && lines[0] != "" { return strings.ToLower(lines[0]), nil } } return "", nil } func numProcs(ctx context.Context) (uint64, error) { return common.NumProcsWithContext(ctx) } func BootTimeWithContext(ctx context.Context) (uint64, error) { return common.BootTimeWithContext(ctx, enableBootTimeCache) } func UptimeWithContext(ctx context.Context) (uint64, error) { sysinfo := &unix.Sysinfo_t{} if err := unix.Sysinfo(sysinfo); err != nil { return 0, err } return uint64(sysinfo.Uptime), nil } func UsersWithContext(ctx context.Context) ([]UserStat, error) { utmpfile := common.HostVarWithContext(ctx, "run/utmp") file, err := os.Open(utmpfile) if err != nil { return nil, err } defer file.Close() buf, err := io.ReadAll(file) if err != nil { return nil, err } count := len(buf) / sizeOfUtmp ret := make([]UserStat, 0, count) for i := 0; i < count; i++ { b := buf[i*sizeOfUtmp : (i+1)*sizeOfUtmp] var u utmp br := bytes.NewReader(b) err := binary.Read(br, binary.LittleEndian, &u) if err != nil { continue } if u.Type != user_PROCESS { continue } user := UserStat{ User: common.IntToString(u.User[:]), Terminal: common.IntToString(u.Line[:]), Host: common.IntToString(u.Host[:]), Started: int(u.Tv.Sec), } ret = append(ret, user) } return ret, nil } func getlsbStruct(ctx context.Context) (*lsbStruct, error) { ret := &lsbStruct{} if common.PathExists(common.HostEtcWithContext(ctx, "lsb-release")) { contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "lsb-release")) if err != nil { return ret, err // return empty } for _, line := range contents { field := strings.Split(line, "=") if len(field) < 2 { continue } switch field[0] { case "DISTRIB_ID": ret.ID = strings.ReplaceAll(field[1], `"`, ``) case "DISTRIB_RELEASE": ret.Release = strings.ReplaceAll(field[1], `"`, ``) case "DISTRIB_CODENAME": ret.Codename = strings.ReplaceAll(field[1], `"`, ``) case "DISTRIB_DESCRIPTION": ret.Description = strings.ReplaceAll(field[1], `"`, ``) } } } else if common.PathExists("/usr/bin/lsb_release") { out, err := invoke.Command("/usr/bin/lsb_release") if err != nil { return ret, err } for _, line := range strings.Split(string(out), "\n") { field := strings.Split(line, ":") if len(field) < 2 { continue } switch field[0] { case "Distributor ID": ret.ID = strings.ReplaceAll(field[1], `"`, ``) case "Release": ret.Release = strings.ReplaceAll(field[1], `"`, ``) case "Codename": ret.Codename = strings.ReplaceAll(field[1], `"`, ``) case "Description": ret.Description = strings.ReplaceAll(field[1], `"`, ``) } } } return ret, nil } func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) { lsb, err := getlsbStruct(ctx) if err != nil { lsb = &lsbStruct{} } if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "oracle-release")) { platform = "oracle" contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "oracle-release")) if err == nil { version = getRedhatishVersion(contents) } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "enterprise-release")) { platform = "oracle" contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "enterprise-release")) if err == nil { version = getRedhatishVersion(contents) } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "slackware-version")) { platform = "slackware" contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "slackware-version")) if err == nil { version = getSlackwareVersion(contents) } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "debian_version")) { if lsb.ID == "Ubuntu" { platform = "ubuntu" version = lsb.Release } else if lsb.ID == "LinuxMint" { platform = "linuxmint" version = lsb.Release } else if lsb.ID == "Kylin" { platform = "Kylin" version = lsb.Release } else if lsb.ID == `"Cumulus Linux"` { platform = "cumuluslinux" version = lsb.Release } else if lsb.ID == "uos" { platform = "uos" version = lsb.Release } else if lsb.ID == "Deepin" { platform = "Deepin" version = lsb.Release } else { if common.PathExistsWithContents("/usr/bin/raspi-config") { platform = "raspbian" } else { platform = "debian" } contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "debian_version")) if err == nil && len(contents) > 0 && contents[0] != "" { version = contents[0] } } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "neokylin-release")) { contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "neokylin-release")) if err == nil { version = getRedhatishVersion(contents) platform = getRedhatishPlatform(contents) } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "redhat-release")) { contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "redhat-release")) if err == nil { version = getRedhatishVersion(contents) platform = getRedhatishPlatform(contents) } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "system-release")) { contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "system-release")) if err == nil { version = getRedhatishVersion(contents) platform = getRedhatishPlatform(contents) } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "gentoo-release")) { platform = "gentoo" contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "gentoo-release")) if err == nil { version = getRedhatishVersion(contents) } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "SuSE-release")) { contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "SuSE-release")) if err == nil { version = getSuseVersion(contents) platform = getSusePlatform(contents) } // TODO: slackware detecion } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "arch-release")) { platform = "arch" version = lsb.Release } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "alpine-release")) { platform = "alpine" contents, err := common.ReadLines(common.HostEtcWithContext(ctx, "alpine-release")) if err == nil && len(contents) > 0 && contents[0] != "" { version = contents[0] } } else if common.PathExistsWithContents(common.HostEtcWithContext(ctx, "os-release")) { p, v, err := common.GetOSReleaseWithContext(ctx) if err == nil { platform = p version = v } } else if lsb.ID == "RedHat" { platform = "redhat" version = lsb.Release } else if lsb.ID == "Amazon" { platform = "amazon" version = lsb.Release } else if lsb.ID == "ScientificSL" { platform = "scientific" version = lsb.Release } else if lsb.ID == "XenServer" { platform = "xenserver" version = lsb.Release } else if lsb.ID != "" { platform = strings.ToLower(lsb.ID) version = lsb.Release } platform = strings.Trim(platform, `"`) switch platform { case "debian", "ubuntu", "linuxmint", "raspbian", "Kylin", "cumuluslinux", "uos", "Deepin": family = "debian" case "fedora": family = "fedora" case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm", "rocky", "almalinux": family = "rhel" case "suse", "opensuse", "opensuse-leap", "opensuse-tumbleweed", "opensuse-tumbleweed-kubic", "sles", "sled", "caasp": family = "suse" case "gentoo": family = "gentoo" case "slackware": family = "slackware" case "arch": family = "arch" case "exherbo": family = "exherbo" case "alpine": family = "alpine" case "coreos": family = "coreos" case "solus": family = "solus" case "neokylin": family = "neokylin" } return platform, family, version, nil } func KernelVersionWithContext(ctx context.Context) (version string, err error) { var utsname unix.Utsname err = unix.Uname(&utsname) if err != nil { return "", err } return unix.ByteSliceToString(utsname.Release[:]), nil } func getSlackwareVersion(contents []string) string { c := strings.ToLower(strings.Join(contents, "")) c = strings.Replace(c, "slackware ", "", 1) return c } var redhatishReleaseMatch = regexp.MustCompile(`release (\w[\d.]*)`) func getRedhatishVersion(contents []string) string { c := strings.ToLower(strings.Join(contents, "")) if strings.Contains(c, "rawhide") { return "rawhide" } if matches := redhatishReleaseMatch.FindStringSubmatch(c); matches != nil { return matches[1] } return "" } func getRedhatishPlatform(contents []string) string { c := strings.ToLower(strings.Join(contents, "")) if strings.Contains(c, "red hat") { return "redhat" } f := strings.Split(c, " ") return f[0] } var ( suseVersionMatch = regexp.MustCompile(`VERSION = ([\d.]+)`) susePatchLevelMatch = regexp.MustCompile(`PATCHLEVEL = (\d+)`) ) func getSuseVersion(contents []string) string { version := "" for _, line := range contents { if matches := suseVersionMatch.FindStringSubmatch(line); matches != nil { version = matches[1] } else if matches = susePatchLevelMatch.FindStringSubmatch(line); matches != nil { version = version + "." + matches[1] } } return version } func getSusePlatform(contents []string) string { c := strings.ToLower(strings.Join(contents, "")) if strings.Contains(c, "opensuse") { return "opensuse" } return "suse" } func VirtualizationWithContext(ctx context.Context) (string, string, error) { return common.VirtualizationWithContext(ctx) } func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { var err error var files []string temperatures := make([]TemperatureStat, 0) // Only the temp*_input file provides current temperature // value in millidegree Celsius as reported by the temperature to the device: // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface if files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/hwmon/hwmon*/temp*_input")); err != nil { return temperatures, err } if len(files) == 0 { // CentOS has an intermediate /device directory: // https://github.com/giampaolo/psutil/issues/971 if files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/hwmon/hwmon*/device/temp*_input")); err != nil { return temperatures, err } } var warns Warnings if len(files) == 0 { // handle distributions without hwmon, like raspbian #391, parse legacy thermal_zone files files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/thermal/thermal_zone*/")) if err != nil { return temperatures, err } for _, file := range files { // Get the name of the temperature you are reading name, err := os.ReadFile(filepath.Join(file, "type")) if err != nil { warns.Add(err) continue } // Get the temperature reading current, err := os.ReadFile(filepath.Join(file, "temp")) if err != nil { warns.Add(err) continue } temperature, err := strconv.ParseInt(strings.TrimSpace(string(current)), 10, 64) if err != nil { warns.Add(err) continue } temperatures = append(temperatures, TemperatureStat{ SensorKey: strings.TrimSpace(string(name)), Temperature: float64(temperature) / 1000.0, }) } return temperatures, warns.Reference() } temperatures = make([]TemperatureStat, 0, len(files)) // example directory // device/ temp1_crit_alarm temp2_crit_alarm temp3_crit_alarm temp4_crit_alarm temp5_crit_alarm temp6_crit_alarm temp7_crit_alarm // name temp1_input temp2_input temp3_input temp4_input temp5_input temp6_input temp7_input // power/ temp1_label temp2_label temp3_label temp4_label temp5_label temp6_label temp7_label // subsystem/ temp1_max temp2_max temp3_max temp4_max temp5_max temp6_max temp7_max // temp1_crit temp2_crit temp3_crit temp4_crit temp5_crit temp6_crit temp7_crit uevent for _, file := range files { var raw []byte var temperature float64 // Get the base directory location directory := filepath.Dir(file) // Get the base filename prefix like temp1 basename := strings.Split(filepath.Base(file), "_")[0] // Get the base path like /temp1 basepath := filepath.Join(directory, basename) // Get the label of the temperature you are reading label := "" if raw, _ = os.ReadFile(basepath + "_label"); len(raw) != 0 { // Format the label from "Core 0" to "core_0" label = strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(raw))), " "), "_") } // Get the name of the temperature you are reading if raw, err = os.ReadFile(filepath.Join(directory, "name")); err != nil { warns.Add(err) continue } name := strings.TrimSpace(string(raw)) if label != "" { name = name + "_" + label } // Get the temperature reading if raw, err = os.ReadFile(file); err != nil { warns.Add(err) continue } if temperature, err = strconv.ParseFloat(strings.TrimSpace(string(raw)), 64); err != nil { warns.Add(err) continue } // Add discovered temperature sensor to the list temperatures = append(temperatures, TemperatureStat{ SensorKey: name, Temperature: temperature / hostTemperatureScale, High: optionalValueReadFromFile(basepath+"_max") / hostTemperatureScale, Critical: optionalValueReadFromFile(basepath+"_crit") / hostTemperatureScale, }) } return temperatures, warns.Reference() } func optionalValueReadFromFile(filename string) float64 { var raw []byte var err error var value float64 // Check if file exists if _, err := os.Stat(filename); os.IsNotExist(err) { return 0 } if raw, err = os.ReadFile(filename); err != nil { return 0 } if value, err = strconv.ParseFloat(strings.TrimSpace(string(raw)), 64); err != nil { return 0 } return value } gopsutil-3.24.1/host/host_linux_386.go000066400000000000000000000014141455407747200175660ustar00rootroot00000000000000// ATTENTION - FILE MANUAL FIXED AFTER CGO. // Fixed line: Tv _Ctype_struct_timeval -> Tv UtTv // Created by cgo -godefs, MANUAL FIXED // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 ID [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv UtTv Addr_v6 [4]int32 X__unused [20]int8 } type exit_status struct { Termination int16 Exit int16 } type UtTv struct { Sec int32 Usec int32 } gopsutil-3.24.1/host/host_linux_amd64.go000066400000000000000000000015261455407747200201650ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv _Ctype_struct___0 Addr_v6 [4]int32 X__glibc_reserved [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int64 Usec int64 } type _Ctype_struct___0 struct { Sec int32 Usec int32 } gopsutil-3.24.1/host/host_linux_arm.go000066400000000000000000000014501455407747200200250ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go | sed "s/uint8/int8/g" package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__glibc_reserved [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int32 Usec int32 } gopsutil-3.24.1/host/host_linux_arm64.go000066400000000000000000000014211455407747200201750ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__glibc_reserved [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int64 Usec int64 } gopsutil-3.24.1/host/host_linux_loong64.go000066400000000000000000000015441455407747200205420ustar00rootroot00000000000000// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs host/types_linux.go //go:build linux && loong64 // +build linux,loong64 package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmp = 0x190 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type ( utmp struct { Type int16 Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int64 Tv timeval Addr_v6 [4]int32 X__glibc_reserved [20]int8 Pad_cgo_0 [4]byte } exit_status struct { Termination int16 Exit int16 } timeval struct { Sec int64 Usec int64 } ) gopsutil-3.24.1/host/host_linux_mips.go000066400000000000000000000012611455407747200202160ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__unused [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int32 Usec int32 } gopsutil-3.24.1/host/host_linux_mips64.go000066400000000000000000000012611455407747200203700ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__unused [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int32 Usec int32 } gopsutil-3.24.1/host/host_linux_mips64le.go000066400000000000000000000012611455407747200207110ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__unused [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int32 Usec int32 } gopsutil-3.24.1/host/host_linux_mipsle.go000066400000000000000000000012611455407747200205370ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__unused [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int32 Usec int32 } gopsutil-3.24.1/host/host_linux_ppc64.go000066400000000000000000000015021455407747200202000ustar00rootroot00000000000000//go:build linux && ppc64 // +build linux,ppc64 // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__glibc_reserved [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int64 Usec int64 } gopsutil-3.24.1/host/host_linux_ppc64le.go000066400000000000000000000015061455407747200205250ustar00rootroot00000000000000//go:build linux && ppc64le // +build linux,ppc64le // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__glibc_reserved [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int64 Usec int64 } gopsutil-3.24.1/host/host_linux_riscv64.go000066400000000000000000000014741455407747200205540ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type utmp struct { Type int16 Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv _Ctype_struct___0 Addr_v6 [4]int32 X__glibc_reserved [20]uint8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int64 Usec int64 } type _Ctype_struct___0 struct { Sec int32 Usec int32 } gopsutil-3.24.1/host/host_linux_s390x.go000066400000000000000000000015021455407747200201320ustar00rootroot00000000000000//go:build linux && s390x // +build linux,s390x // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go package host const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 sizeOfUtmp = 0x180 ) type ( _C_short int16 _C_int int32 _C_long int64 _C_long_long int64 ) type utmp struct { Type int16 Pad_cgo_0 [2]byte Pid int32 Line [32]int8 Id [4]int8 User [32]int8 Host [256]int8 Exit exit_status Session int32 Tv timeval Addr_v6 [4]int32 X__glibc_reserved [20]int8 } type exit_status struct { Termination int16 Exit int16 } type timeval struct { Sec int64 Usec int64 } gopsutil-3.24.1/host/host_linux_test.go000066400000000000000000000046731455407747200202370ustar00rootroot00000000000000//go:build linux // +build linux package host import ( "context" "testing" "github.com/shirou/gopsutil/v3/common" ) func TestGetRedhatishVersion(t *testing.T) { var ret string c := []string{"Rawhide"} ret = getRedhatishVersion(c) if ret != "rawhide" { t.Errorf("Could not get version rawhide: %v", ret) } c = []string{"Fedora release 15 (Lovelock)"} ret = getRedhatishVersion(c) if ret != "15" { t.Errorf("Could not get version fedora: %v", ret) } c = []string{"Enterprise Linux Server release 5.5 (Carthage)"} ret = getRedhatishVersion(c) if ret != "5.5" { t.Errorf("Could not get version redhat enterprise: %v", ret) } c = []string{""} ret = getRedhatishVersion(c) if ret != "" { t.Errorf("Could not get version with no value: %v", ret) } } func TestGetRedhatishPlatform(t *testing.T) { var ret string c := []string{"red hat"} ret = getRedhatishPlatform(c) if ret != "redhat" { t.Errorf("Could not get platform redhat: %v", ret) } c = []string{"Fedora release 15 (Lovelock)"} ret = getRedhatishPlatform(c) if ret != "fedora" { t.Errorf("Could not get platform fedora: %v", ret) } c = []string{"Enterprise Linux Server release 5.5 (Carthage)"} ret = getRedhatishPlatform(c) if ret != "enterprise" { t.Errorf("Could not get platform redhat enterprise: %v", ret) } c = []string{""} ret = getRedhatishPlatform(c) if ret != "" { t.Errorf("Could not get platform with no value: %v", ret) } } func Test_getlsbStruct(t *testing.T) { cases := []struct { root string id string release string codename string description string }{ {"arch", "Arch", "rolling", "", "Arch Linux"}, {"ubuntu_22_04", "Ubuntu", "22.04", "jammy", "Ubuntu 22.04.2 LTS"}, } for _, tt := range cases { tt := tt t.Run(tt.root, func(t *testing.T) { ctx := context.WithValue(context.Background(), common.EnvKey, common.EnvMap{common.HostEtcEnvKey: "./testdata/linux/lsbStruct/" + tt.root}, ) v, err := getlsbStruct(ctx) if err != nil { t.Errorf("error %v", err) } if v.ID != tt.id { t.Errorf("ID: want %v, got %v", tt.id, v.ID) } if v.Release != tt.release { t.Errorf("Release: want %v, got %v", tt.release, v.Release) } if v.Codename != tt.codename { t.Errorf("Codename: want %v, got %v", tt.codename, v.Codename) } if v.Description != tt.description { t.Errorf("Description: want %v, got %v", tt.description, v.Description) } t.Log(v) }) } } gopsutil-3.24.1/host/host_netbsd.go000066400000000000000000000024021455407747200173040ustar00rootroot00000000000000//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 } gopsutil-3.24.1/host/host_openbsd.go000066400000000000000000000042751455407747200174710ustar00rootroot00000000000000//go:build openbsd // +build openbsd package host import ( "bytes" "context" "encoding/binary" "io" "os" "strings" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/process" "golang.org/x/sys/unix" ) const ( UTNameSize = 32 /* see MAXLOGNAME in */ UTLineSize = 8 UTHostSize = 16 ) func HostIDWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func numProcs(ctx context.Context) (uint64, error) { procs, err := process.PidsWithContext(ctx) if err != nil { return 0, err } return uint64(len(procs)), nil } 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 utmpfile := "/var/run/utmp" file, err := os.Open(utmpfile) if err != nil { return ret, err } defer file.Close() buf, err := io.ReadAll(file) if err != nil { return ret, err } u := Utmp{} entrySize := int(unsafe.Sizeof(u)) count := len(buf) / entrySize for i := 0; i < count; i++ { b := buf[i*entrySize : i*entrySize+entrySize] var u Utmp br := bytes.NewReader(b) err := binary.Read(br, binary.LittleEndian, &u) if err != nil || u.Time == 0 || u.Name[0] == 0 { continue } user := UserStat{ User: common.IntToString(u.Name[:]), Terminal: common.IntToString(u.Line[:]), Host: common.IntToString(u.Host[:]), Started: int(u.Time), } ret = append(ret, user) } return ret, nil } 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 } gopsutil-3.24.1/host/host_openbsd_386.go000066400000000000000000000010011455407747200200510ustar00rootroot00000000000000//go:build openbsd && 386 // +build openbsd,386 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs host/types_openbsd.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmp = 0x130 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type Utmp struct { Line [8]int8 Name [32]int8 Host [256]int8 Time int64 } type Timeval struct { Sec int64 Usec int32 } gopsutil-3.24.1/host/host_openbsd_amd64.go000066400000000000000000000007011455407747200204520ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs 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 } type Timeval struct { Sec int64 Usec int64 } gopsutil-3.24.1/host/host_openbsd_arm.go000066400000000000000000000010011455407747200203100ustar00rootroot00000000000000//go:build openbsd && arm // +build openbsd,arm // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs host/types_openbsd.go package host const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 sizeOfUtmp = 0x130 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type Utmp struct { Line [8]int8 Name [32]int8 Host [256]int8 Time int64 } type Timeval struct { Sec int64 Usec int32 } gopsutil-3.24.1/host/host_openbsd_arm64.go000066400000000000000000000010051455407747200204660ustar00rootroot00000000000000//go:build openbsd && arm64 // +build openbsd,arm64 // 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 } type Timeval struct { Sec int64 Usec int64 } gopsutil-3.24.1/host/host_posix.go000066400000000000000000000005451455407747200171750ustar00rootroot00000000000000//go:build linux || freebsd || openbsd || netbsd || darwin || solaris // +build linux freebsd openbsd netbsd darwin solaris package host import "golang.org/x/sys/unix" func KernelArch() (string, error) { var utsname unix.Utsname err := unix.Uname(&utsname) if err != nil { return "", err } return unix.ByteSliceToString(utsname.Machine[:]), nil } gopsutil-3.24.1/host/host_solaris.go000066400000000000000000000113701455407747200175050ustar00rootroot00000000000000package host import ( "bufio" "bytes" "context" "encoding/csv" "fmt" "io" "os" "regexp" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" ) func HostIDWithContext(ctx context.Context) (string, error) { platform, err := parseReleaseFile() if err != nil { return "", err } if platform == "SmartOS" { // If everything works, use the current zone ID as the HostID if present. out, err := invoke.CommandWithContext(ctx, "zonename") if err == nil { sc := bufio.NewScanner(bytes.NewReader(out)) for sc.Scan() { line := sc.Text() // If we're in the global zone, rely on the hostname. if line == "global" { hostname, err := os.Hostname() if err == nil { return hostname, nil } } else { return strings.TrimSpace(line), nil } } } } // If HostID is still unknown, use hostid(1), which can lie to callers but at // this point there are no hardware facilities available. This behavior // matches that of other supported OSes. out, err := invoke.CommandWithContext(ctx, "hostid") if err == nil { sc := bufio.NewScanner(bytes.NewReader(out)) for sc.Scan() { line := sc.Text() return strings.TrimSpace(line), nil } } return "", nil } // Count number of processes based on the number of entries in /proc func numProcs(ctx context.Context) (uint64, error) { dirs, err := os.ReadDir("/proc") if err != nil { return 0, err } return uint64(len(dirs)), nil } var kstatMatch = regexp.MustCompile(`([^\s]+)[\s]+([^\s]*)`) func BootTimeWithContext(ctx context.Context) (uint64, error) { out, err := invoke.CommandWithContext(ctx, "kstat", "-p", "unix:0:system_misc:boot_time") if err != nil { return 0, err } kstats := kstatMatch.FindAllStringSubmatch(string(out), -1) if len(kstats) != 1 { return 0, fmt.Errorf("expected 1 kstat, found %d", len(kstats)) } return strconv.ParseUint(kstats[0][2], 10, 64) } func UptimeWithContext(ctx context.Context) (uint64, error) { bootTime, err := BootTime() if err != nil { return 0, err } return timeSince(bootTime), nil } func UsersWithContext(ctx context.Context) ([]UserStat, error) { return []UserStat{}, common.ErrNotImplementedError } func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { var ret []TemperatureStat out, err := invoke.CommandWithContext(ctx, "ipmitool", "-c", "sdr", "list") if err != nil { return ret, err } r := csv.NewReader(strings.NewReader(string(out))) // Output may contain errors, e.g. "bmc_send_cmd: Permission denied", don't expect a consistent number of records r.FieldsPerRecord = -1 for { record, err := r.Read() if err == io.EOF { break } if err != nil { return ret, err } // CPU1 Temp,40,degrees C,ok if len(record) < 3 || record[1] == "" || record[2] != "degrees C" { continue } v, err := strconv.ParseFloat(record[1], 64) if err != nil { return ret, err } ts := TemperatureStat{ SensorKey: strings.TrimSuffix(record[0], " Temp"), Temperature: v, } ret = append(ret, ts) } return ret, nil } func VirtualizationWithContext(ctx context.Context) (string, string, error) { return "", "", common.ErrNotImplementedError } // Find distribution name from /etc/release func parseReleaseFile() (string, error) { b, err := os.ReadFile("/etc/release") if err != nil { return "", err } s := string(b) s = strings.TrimSpace(s) var platform string switch { case strings.HasPrefix(s, "SmartOS"): platform = "SmartOS" case strings.HasPrefix(s, "OpenIndiana"): platform = "OpenIndiana" case strings.HasPrefix(s, "OmniOS"): platform = "OmniOS" case strings.HasPrefix(s, "Open Storage"): platform = "NexentaStor" case strings.HasPrefix(s, "Solaris"): platform = "Solaris" case strings.HasPrefix(s, "Oracle Solaris"): platform = "Solaris" default: platform = strings.Fields(s)[0] } return platform, nil } // parseUnameOutput returns platformFamily, kernelVersion and platformVersion func parseUnameOutput(ctx context.Context) (string, string, string, error) { out, err := invoke.CommandWithContext(ctx, "uname", "-srv") if err != nil { return "", "", "", err } fields := strings.Fields(string(out)) if len(fields) < 3 { return "", "", "", fmt.Errorf("malformed `uname` output") } return fields[0], fields[1], fields[2], nil } func KernelVersionWithContext(ctx context.Context) (string, error) { _, kernelVersion, _, err := parseUnameOutput(ctx) return kernelVersion, err } func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) { platform, err := parseReleaseFile() if err != nil { return "", "", "", err } platformFamily, _, platformVersion, err := parseUnameOutput(ctx) if err != nil { return "", "", "", err } return platform, platformFamily, platformVersion, nil } gopsutil-3.24.1/host/host_test.go000066400000000000000000000107161455407747200170130ustar00rootroot00000000000000package host import ( "errors" "fmt" "os" "sync" "testing" "github.com/shirou/gopsutil/v3/internal/common" ) func skipIfNotImplementedErr(t *testing.T, err error) { if errors.Is(err, common.ErrNotImplementedError) { t.Skip("not implemented") } } func TestHostInfo(t *testing.T) { v, err := Info() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } empty := &InfoStat{} if v == empty { t.Errorf("Could not get hostinfo %v", v) } if v.Procs == 0 { t.Errorf("Could not determine the number of host processes") } t.Log(v) } func TestUptime(t *testing.T) { if os.Getenv("CI") == "true" { t.Skip("Skip CI") } v, err := Uptime() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if v == 0 { t.Errorf("Could not get up time %v", v) } } func TestBoot_time(t *testing.T) { if os.Getenv("CI") == "true" { t.Skip("Skip CI") } v, err := BootTime() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if v == 0 { t.Errorf("Could not get boot time %v", v) } if v < 946652400 { t.Errorf("Invalid Boottime, older than 2000-01-01") } t.Logf("first boot time: %d", v) v2, err := BootTime() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if v != v2 { t.Errorf("cached boot time is different") } t.Logf("second boot time: %d", v2) } func TestUsers(t *testing.T) { v, err := Users() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } empty := UserStat{} if len(v) == 0 { t.Skip("Users is empty") } for _, u := range v { if u == empty { t.Errorf("Could not Users %v", v) } t.Log(u) } } func TestHostInfoStat_String(t *testing.T) { v := InfoStat{ Hostname: "test", Uptime: 3000, Procs: 100, OS: "linux", Platform: "ubuntu", BootTime: 1447040000, HostID: "edfd25ff-3c9c-b1a4-e660-bd826495ad35", KernelArch: "x86_64", } e := `{"hostname":"test","uptime":3000,"bootTime":1447040000,"procs":100,"os":"linux","platform":"ubuntu","platformFamily":"","platformVersion":"","kernelVersion":"","kernelArch":"x86_64","virtualizationSystem":"","virtualizationRole":"","hostId":"edfd25ff-3c9c-b1a4-e660-bd826495ad35"}` if e != fmt.Sprintf("%v", v) { t.Errorf("HostInfoStat string is invalid:\ngot %v\nwant %v", v, e) } } func TestUserStat_String(t *testing.T) { v := UserStat{ User: "user", Terminal: "term", Host: "host", Started: 100, } e := `{"user":"user","terminal":"term","host":"host","started":100}` if e != fmt.Sprintf("%v", v) { t.Errorf("UserStat string is invalid: %v", v) } } func TestHostGuid(t *testing.T) { id, err := HostID() skipIfNotImplementedErr(t, err) if err != nil { t.Error(err) } if id == "" { t.Error("Host id is empty") } else { t.Logf("Host id value: %v", id) } } func TestTemperatureStat_String(t *testing.T) { v := TemperatureStat{ SensorKey: "CPU", Temperature: 1.1, High: 30.1, Critical: 0.1, } s := `{"sensorKey":"CPU","temperature":1.1,"sensorHigh":30.1,"sensorCritical":0.1}` if s != fmt.Sprintf("%v", v) { t.Errorf("TemperatureStat string is invalid, %v", fmt.Sprintf("%v", v)) } } func TestVirtualization(t *testing.T) { wg := sync.WaitGroup{} testCount := 10 wg.Add(testCount) for i := 0; i < testCount; i++ { go func(j int) { system, role, err := Virtualization() wg.Done() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("Virtualization() failed, %v", err) } if j == 9 { t.Logf("Virtualization(): %s, %s", system, role) } }(i) } wg.Wait() } func TestKernelVersion(t *testing.T) { version, err := KernelVersion() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("KernelVersion() failed, %v", err) } if version == "" { t.Errorf("KernelVersion() returns empty: %s", version) } t.Logf("KernelVersion(): %s", version) } func TestPlatformInformation(t *testing.T) { platform, family, version, err := PlatformInformation() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("PlatformInformation() failed, %v", err) } if platform == "" { t.Errorf("PlatformInformation() returns empty: %v", platform) } 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() } } gopsutil-3.24.1/host/host_windows.go000066400000000000000000000231521455407747200175240ustar00rootroot00000000000000//go:build windows // +build windows package host import ( "context" "fmt" "math" "strconv" "strings" "sync/atomic" "syscall" "time" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/process" "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows" ) var ( procGetSystemTimeAsFileTime = common.Modkernel32.NewProc("GetSystemTimeAsFileTime") procGetTickCount32 = common.Modkernel32.NewProc("GetTickCount") procGetTickCount64 = common.Modkernel32.NewProc("GetTickCount64") procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo") procRtlGetVersion = common.ModNt.NewProc("RtlGetVersion") ) // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ns-wdm-_osversioninfoexw type osVersionInfoExW struct { dwOSVersionInfoSize uint32 dwMajorVersion uint32 dwMinorVersion uint32 dwBuildNumber uint32 dwPlatformId uint32 szCSDVersion [128]uint16 wServicePackMajor uint16 wServicePackMinor uint16 wSuiteMask uint16 wProductType uint8 wReserved uint8 } type systemInfo struct { wProcessorArchitecture uint16 wReserved uint16 dwPageSize uint32 lpMinimumApplicationAddress uintptr lpMaximumApplicationAddress uintptr dwActiveProcessorMask uintptr dwNumberOfProcessors uint32 dwProcessorType uint32 dwAllocationGranularity uint32 wProcessorLevel uint16 wProcessorRevision uint16 } type msAcpi_ThermalZoneTemperature struct { Active bool CriticalTripPoint uint32 CurrentTemperature uint32 InstanceName string } func HostIDWithContext(ctx context.Context) (string, error) { // there has been reports of issues on 32bit using golang.org/x/sys/windows/registry, see https://github.com/shirou/gopsutil/pull/312#issuecomment-277422612 // for rationale of using windows.RegOpenKeyEx/RegQueryValueEx instead of registry.OpenKey/GetStringValue var h windows.Handle err := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h) if err != nil { return "", err } defer windows.RegCloseKey(h) const windowsRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16 const uuidLen = 36 var regBuf [windowsRegBufLen]uint16 bufLen := uint32(windowsRegBufLen) var valType uint32 err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) if err != nil { return "", err } hostID := windows.UTF16ToString(regBuf[:]) hostIDLen := len(hostID) if hostIDLen != uuidLen { return "", fmt.Errorf("HostID incorrect: %q\n", hostID) } return strings.ToLower(hostID), nil } func numProcs(ctx context.Context) (uint64, error) { procs, err := process.PidsWithContext(ctx) if err != nil { return 0, err } return uint64(len(procs)), nil } func UptimeWithContext(ctx context.Context) (uint64, error) { up, err := uptimeMillis() if err != nil { return 0, err } return uint64((time.Duration(up) * time.Millisecond).Seconds()), nil } func uptimeMillis() (uint64, error) { procGetTickCount := procGetTickCount64 err := procGetTickCount64.Find() if err != nil { procGetTickCount = procGetTickCount32 // handle WinXP, but keep in mind that "the time will wrap around to zero if the system is run continuously for 49.7 days." from MSDN } r1, _, lastErr := syscall.Syscall(procGetTickCount.Addr(), 0, 0, 0, 0) if lastErr != 0 { return 0, lastErr } return uint64(r1), nil } // cachedBootTime must be accessed via atomic.Load/StoreUint64 var cachedBootTime uint64 func BootTimeWithContext(ctx context.Context) (uint64, error) { if enableBootTimeCache { t := atomic.LoadUint64(&cachedBootTime) if t != 0 { return t, nil } } up, err := uptimeMillis() if err != nil { return 0, err } t := uint64((time.Duration(timeSinceMillis(up)) * time.Millisecond).Seconds()) if enableBootTimeCache { atomic.StoreUint64(&cachedBootTime, t) } return t, nil } func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version 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 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ns-wdm-_osversioninfoexw var osInfo osVersionInfoExW osInfo.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osInfo)) ret, _, err := procRtlGetVersion.Call(uintptr(unsafe.Pointer(&osInfo))) if ret != 0 { 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 } 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 } regBuf := make([]uint16, bufLen/2+1) err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`ProductName`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) if err != nil { return } platform = windows.UTF16ToString(regBuf[:]) if strings.Contains(platform, "Windows 10") { // check build number to determine whether it's actually Windows 11 err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CurrentBuildNumber`), nil, &valType, nil, &bufLen) if err == nil { regBuf = make([]uint16, bufLen/2+1) err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CurrentBuildNumber`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) if err == nil { buildNumberStr := windows.UTF16ToString(regBuf[:]) if buildNumber, err := strconv.Atoi(buildNumberStr); err == nil && buildNumber >= 22000 { platform = strings.Replace(platform, "Windows 10", "Windows 11", 1) } } } } if !strings.HasPrefix(platform, "Microsoft") { platform = "Microsoft " + platform } err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CSDVersion`), nil, &valType, nil, &bufLen) // append Service Pack number, only on success if err == nil { // don't return an error if only the Service Pack retrieval fails regBuf = make([]uint16, bufLen/2+1) err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CSDVersion`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) if err == nil { platform += " " + windows.UTF16ToString(regBuf[:]) } } var UBR uint32 // Update Build Revision err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`UBR`), nil, &valType, nil, &bufLen) if err == nil { regBuf := make([]byte, 4) err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`UBR`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) copy((*[4]byte)(unsafe.Pointer(&UBR))[:], regBuf) } // PlatformFamily switch osInfo.wProductType { case 1: family = "Standalone Workstation" case 2: family = "Server (Domain Controller)" case 3: family = "Server" } // Platform Version version = fmt.Sprintf("%d.%d.%d.%d Build %d.%d", osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.dwBuildNumber, UBR, osInfo.dwBuildNumber, UBR) return platform, family, version, nil } func UsersWithContext(ctx context.Context) ([]UserStat, error) { var ret []UserStat return ret, common.ErrNotImplementedError } func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { var ret []TemperatureStat var dst []msAcpi_ThermalZoneTemperature q := wmi.CreateQuery(&dst, "") if err := common.WMIQueryWithContext(ctx, q, &dst, nil, "root/wmi"); err != nil { return ret, err } for _, v := range dst { ts := TemperatureStat{ SensorKey: v.InstanceName, Temperature: kelvinToCelsius(v.CurrentTemperature, 2), } ret = append(ret, ts) } return ret, nil } func kelvinToCelsius(temp uint32, n int) float64 { // wmi return temperature Kelvin * 10, so need to divide the result by 10, // and then minus 273.15 to get °Celsius. t := float64(temp/10) - 273.15 n10 := math.Pow10(n) return math.Trunc((t+0.5/n10)*n10) / n10 } func VirtualizationWithContext(ctx context.Context) (string, string, error) { return "", "", common.ErrNotImplementedError } func KernelVersionWithContext(ctx context.Context) (string, error) { _, _, version, err := PlatformInformationWithContext(ctx) return version, err } func KernelArch() (string, error) { var systemInfo systemInfo procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo))) const ( PROCESSOR_ARCHITECTURE_INTEL = 0 PROCESSOR_ARCHITECTURE_ARM = 5 PROCESSOR_ARCHITECTURE_ARM64 = 12 PROCESSOR_ARCHITECTURE_IA64 = 6 PROCESSOR_ARCHITECTURE_AMD64 = 9 ) switch systemInfo.wProcessorArchitecture { case PROCESSOR_ARCHITECTURE_INTEL: if systemInfo.wProcessorLevel < 3 { return "i386", nil } if systemInfo.wProcessorLevel > 6 { return "i686", nil } return fmt.Sprintf("i%d86", systemInfo.wProcessorLevel), nil case PROCESSOR_ARCHITECTURE_ARM: return "arm", nil case PROCESSOR_ARCHITECTURE_ARM64: return "aarch64", nil case PROCESSOR_ARCHITECTURE_IA64: return "ia64", nil case PROCESSOR_ARCHITECTURE_AMD64: return "x86_64", nil } return "", nil } gopsutil-3.24.1/host/smc_darwin.c000066400000000000000000000074041455407747200167420ustar00rootroot00000000000000#include #include #include "smc_darwin.h" #define IOSERVICE_SMC "AppleSMC" #define IOSERVICE_MODEL "IOPlatformExpertDevice" #define DATA_TYPE_SP78 "sp78" typedef enum { kSMCUserClientOpen = 0, kSMCUserClientClose = 1, kSMCHandleYPCEvent = 2, kSMCReadKey = 5, kSMCWriteKey = 6, kSMCGetKeyCount = 7, kSMCGetKeyFromIndex = 8, kSMCGetKeyInfo = 9, } selector_t; typedef struct { unsigned char major; unsigned char minor; unsigned char build; unsigned char reserved; unsigned short release; } SMCVersion; typedef struct { uint16_t version; uint16_t length; uint32_t cpuPLimit; uint32_t gpuPLimit; uint32_t memPLimit; } SMCPLimitData; typedef struct { IOByteCount data_size; uint32_t data_type; uint8_t data_attributes; } SMCKeyInfoData; typedef struct { uint32_t key; SMCVersion vers; SMCPLimitData p_limit_data; SMCKeyInfoData key_info; uint8_t result; uint8_t status; uint8_t data8; uint32_t data32; uint8_t bytes[32]; } SMCParamStruct; typedef enum { kSMCSuccess = 0, kSMCError = 1, kSMCKeyNotFound = 0x84, } kSMC_t; typedef struct { uint8_t data[32]; uint32_t data_type; uint32_t data_size; kSMC_t kSMC; } smc_return_t; static const int SMC_KEY_SIZE = 4; // number of characters in an SMC key. static io_connect_t conn; // our connection to the SMC. kern_return_t gopsutil_v3_open_smc(void) { kern_return_t result; io_service_t service; service = IOServiceGetMatchingService(0, IOServiceMatching(IOSERVICE_SMC)); if (service == 0) { // Note: IOServiceMatching documents 0 on failure printf("ERROR: %s NOT FOUND\n", IOSERVICE_SMC); return kIOReturnError; } result = IOServiceOpen(service, mach_task_self(), 0, &conn); IOObjectRelease(service); return result; } kern_return_t gopsutil_v3_close_smc(void) { return IOServiceClose(conn); } static uint32_t to_uint32(char *key) { uint32_t ans = 0; uint32_t shift = 24; if (strlen(key) != SMC_KEY_SIZE) { return 0; } for (int i = 0; i < SMC_KEY_SIZE; i++) { ans += key[i] << shift; shift -= 8; } return ans; } static kern_return_t call_smc(SMCParamStruct *input, SMCParamStruct *output) { kern_return_t result; size_t input_cnt = sizeof(SMCParamStruct); size_t output_cnt = sizeof(SMCParamStruct); result = IOConnectCallStructMethod(conn, kSMCHandleYPCEvent, input, input_cnt, output, &output_cnt); if (result != kIOReturnSuccess) { result = err_get_code(result); } return result; } static kern_return_t read_smc(char *key, smc_return_t *result_smc) { kern_return_t result; SMCParamStruct input; SMCParamStruct output; memset(&input, 0, sizeof(SMCParamStruct)); memset(&output, 0, sizeof(SMCParamStruct)); memset(result_smc, 0, sizeof(smc_return_t)); input.key = to_uint32(key); input.data8 = kSMCGetKeyInfo; result = call_smc(&input, &output); result_smc->kSMC = output.result; if (result != kIOReturnSuccess || output.result != kSMCSuccess) { return result; } result_smc->data_size = output.key_info.data_size; result_smc->data_type = output.key_info.data_type; input.key_info.data_size = output.key_info.data_size; input.data8 = kSMCReadKey; result = call_smc(&input, &output); result_smc->kSMC = output.result; if (result != kIOReturnSuccess || output.result != kSMCSuccess) { return result; } memcpy(result_smc->data, output.bytes, sizeof(output.bytes)); return result; } double gopsutil_v3_get_temperature(char *key) { kern_return_t result; smc_return_t result_smc; result = read_smc(key, &result_smc); if (!(result == kIOReturnSuccess) && result_smc.data_size == 2 && result_smc.data_type == to_uint32(DATA_TYPE_SP78)) { return 0.0; } return (double)result_smc.data[0]; } gopsutil-3.24.1/host/smc_darwin.h000066400000000000000000000017711455407747200167500ustar00rootroot00000000000000#ifndef __SMC_H__ #define __SMC_H__ 1 #include #define AMBIENT_AIR_0 "TA0P" #define AMBIENT_AIR_1 "TA1P" #define CPU_0_DIODE "TC0D" #define CPU_0_HEATSINK "TC0H" #define CPU_0_PROXIMITY "TC0P" #define ENCLOSURE_BASE_0 "TB0T" #define ENCLOSURE_BASE_1 "TB1T" #define ENCLOSURE_BASE_2 "TB2T" #define ENCLOSURE_BASE_3 "TB3T" #define GPU_0_DIODE "TG0D" #define GPU_0_HEATSINK "TG0H" #define GPU_0_PROXIMITY "TG0P" #define HARD_DRIVE_BAY "TH0P" #define MEMORY_SLOT_0 "TM0S" #define MEMORY_SLOTS_PROXIMITY "TM0P" #define NORTHBRIDGE "TN0H" #define NORTHBRIDGE_DIODE "TN0D" #define NORTHBRIDGE_PROXIMITY "TN0P" #define THUNDERBOLT_0 "TI0P" #define THUNDERBOLT_1 "TI1P" #define WIRELESS_MODULE "TW0P" kern_return_t gopsutil_v3_open_smc(void); kern_return_t gopsutil_v3_close_smc(void); double gopsutil_v3_get_temperature(char *); #endif // __SMC_H__ gopsutil-3.24.1/host/testdata/000077500000000000000000000000001455407747200162545ustar00rootroot00000000000000gopsutil-3.24.1/host/testdata/linux/000077500000000000000000000000001455407747200174135ustar00rootroot00000000000000gopsutil-3.24.1/host/testdata/linux/lsbStruct/000077500000000000000000000000001455407747200214005ustar00rootroot00000000000000gopsutil-3.24.1/host/testdata/linux/lsbStruct/arch/000077500000000000000000000000001455407747200223155ustar00rootroot00000000000000gopsutil-3.24.1/host/testdata/linux/lsbStruct/arch/lsb-release000066400000000000000000000001151455407747200244330ustar00rootroot00000000000000DISTRIB_ID="Arch" DISTRIB_RELEASE="rolling" DISTRIB_DESCRIPTION="Arch Linux" gopsutil-3.24.1/host/testdata/linux/lsbStruct/ubuntu_22_04/000077500000000000000000000000001455407747200235305ustar00rootroot00000000000000gopsutil-3.24.1/host/testdata/linux/lsbStruct/ubuntu_22_04/lsb-release000066400000000000000000000001471455407747200256530ustar00rootroot00000000000000DISTRIB_ID=Ubuntu DISTRIB_RELEASE=22.04 DISTRIB_CODENAME=jammy DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"gopsutil-3.24.1/host/types_darwin.go000066400000000000000000000003511455407747200175010ustar00rootroot00000000000000//go:build ignore // +build ignore // plus hand editing about timeval /* Input to cgo -godefs. */ package host /* #include #include */ import "C" type ( Utmpx C.struct_utmpx Timeval C.struct_timeval ) gopsutil-3.24.1/host/types_freebsd.go000066400000000000000000000013041455407747200176260ustar00rootroot00000000000000//go:build ignore // +build ignore /* Input to cgo -godefs. */ package host /* #define KERNEL #include #include #include #include "freebsd_headers/utxdb.h" enum { sizeofPtr = sizeof(void*), }; */ import "C" // Machine characteristics; for internal use. const ( sizeofPtr = C.sizeofPtr sizeofShort = C.sizeof_short sizeofInt = C.sizeof_int sizeofLong = C.sizeof_long sizeofLongLong = C.sizeof_longlong sizeOfUtmpx = C.sizeof_struct_futx ) // Basic types type ( _C_short C.short _C_int C.int _C_long C.long _C_long_long C.longlong ) type ( Utmp C.struct_utmp // for FreeBSD 9.0 compatibility Utmpx C.struct_futx ) gopsutil-3.24.1/host/types_linux.go000066400000000000000000000012211455407747200173510ustar00rootroot00000000000000//go:build ignore // +build ignore /* Input to cgo -godefs. */ package host /* #include #include enum { sizeofPtr = sizeof(void*), }; */ import "C" // Machine characteristics; for internal use. const ( sizeofPtr = C.sizeofPtr sizeofShort = C.sizeof_short sizeofInt = C.sizeof_int sizeofLong = C.sizeof_long sizeofLongLong = C.sizeof_longlong sizeOfUtmp = C.sizeof_struct_utmp ) // Basic types type ( _C_short C.short _C_int C.int _C_long C.long _C_long_long C.longlong ) type ( utmp C.struct_utmp exit_status C.struct_exit_status timeval C.struct_timeval ) gopsutil-3.24.1/host/types_openbsd.go000066400000000000000000000012061455407747200176470ustar00rootroot00000000000000//go:build ignore // +build ignore /* Input to cgo -godefs. */ package host /* #define KERNEL #include #include #include enum { sizeofPtr = sizeof(void*), }; */ import "C" // Machine characteristics; for internal use. const ( sizeofPtr = C.sizeofPtr sizeofShort = C.sizeof_short sizeofInt = C.sizeof_int sizeofLong = C.sizeof_long sizeofLongLong = C.sizeof_longlong sizeOfUtmp = C.sizeof_struct_utmp ) // Basic types type ( _C_short C.short _C_int C.int _C_long C.long _C_long_long C.longlong ) type ( Utmp C.struct_utmp Timeval C.struct_timeval ) gopsutil-3.24.1/internal/000077500000000000000000000000001455407747200153025ustar00rootroot00000000000000gopsutil-3.24.1/internal/common/000077500000000000000000000000001455407747200165725ustar00rootroot00000000000000gopsutil-3.24.1/internal/common/binary.go000066400000000000000000000360121455407747200204070ustar00rootroot00000000000000package common // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package binary implements simple translation between numbers and byte // sequences and encoding and decoding of varints. // // Numbers are translated by reading and writing fixed-size values. // A fixed-size value is either a fixed-size arithmetic // type (int8, uint8, int16, float32, complex64, ...) // or an array or struct containing only fixed-size values. // // The varint functions encode and decode single integer values using // a variable-length encoding; smaller values require fewer bytes. // For a specification, see // http://code.google.com/apis/protocolbuffers/docs/encoding.html. // // This package favors simplicity over efficiency. Clients that require // high-performance serialization, especially for large data structures, // should look at more advanced solutions such as the encoding/gob // package or protocol buffers. import ( "errors" "io" "math" "reflect" ) // A ByteOrder specifies how to convert byte sequences into // 16-, 32-, or 64-bit unsigned integers. type ByteOrder interface { Uint16([]byte) uint16 Uint32([]byte) uint32 Uint64([]byte) uint64 PutUint16([]byte, uint16) PutUint32([]byte, uint32) PutUint64([]byte, uint64) String() string } // LittleEndian is the little-endian implementation of ByteOrder. var LittleEndian littleEndian // BigEndian is the big-endian implementation of ByteOrder. var BigEndian bigEndian type littleEndian struct{} func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 } func (littleEndian) PutUint16(b []byte, v uint16) { b[0] = byte(v) b[1] = byte(v >> 8) } func (littleEndian) Uint32(b []byte) uint32 { return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 } func (littleEndian) PutUint32(b []byte, v uint32) { b[0] = byte(v) b[1] = byte(v >> 8) b[2] = byte(v >> 16) b[3] = byte(v >> 24) } func (littleEndian) Uint64(b []byte) uint64 { return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 } func (littleEndian) PutUint64(b []byte, v uint64) { b[0] = byte(v) b[1] = byte(v >> 8) b[2] = byte(v >> 16) b[3] = byte(v >> 24) b[4] = byte(v >> 32) b[5] = byte(v >> 40) b[6] = byte(v >> 48) b[7] = byte(v >> 56) } func (littleEndian) String() string { return "LittleEndian" } func (littleEndian) GoString() string { return "binary.LittleEndian" } type bigEndian struct{} func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 } func (bigEndian) PutUint16(b []byte, v uint16) { b[0] = byte(v >> 8) b[1] = byte(v) } func (bigEndian) Uint32(b []byte) uint32 { return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 } func (bigEndian) PutUint32(b []byte, v uint32) { b[0] = byte(v >> 24) b[1] = byte(v >> 16) b[2] = byte(v >> 8) b[3] = byte(v) } func (bigEndian) Uint64(b []byte) uint64 { return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 } func (bigEndian) PutUint64(b []byte, v uint64) { b[0] = byte(v >> 56) b[1] = byte(v >> 48) b[2] = byte(v >> 40) b[3] = byte(v >> 32) b[4] = byte(v >> 24) b[5] = byte(v >> 16) b[6] = byte(v >> 8) b[7] = byte(v) } func (bigEndian) String() string { return "BigEndian" } func (bigEndian) GoString() string { return "binary.BigEndian" } // Read reads structured binary data from r into data. // Data must be a pointer to a fixed-size value or a slice // of fixed-size values. // Bytes read from r are decoded using the specified byte order // and written to successive fields of the data. // When reading into structs, the field data for fields with // 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 interface{}) error { // Fast path for basic types and slices. if n := intDataSize(data); n != 0 { var b [8]byte var bs []byte if n > len(b) { bs = make([]byte, n) } else { bs = b[:n] } if _, err := io.ReadFull(r, bs); err != nil { return err } switch data := data.(type) { case *int8: *data = int8(b[0]) case *uint8: *data = b[0] case *int16: *data = int16(order.Uint16(bs)) case *uint16: *data = order.Uint16(bs) case *int32: *data = int32(order.Uint32(bs)) case *uint32: *data = order.Uint32(bs) case *int64: *data = int64(order.Uint64(bs)) case *uint64: *data = order.Uint64(bs) case []int8: for i, x := range bs { // Easier to loop over the input for 8-bit values. data[i] = int8(x) } case []uint8: copy(data, bs) case []int16: for i := range data { data[i] = int16(order.Uint16(bs[2*i:])) } case []uint16: for i := range data { data[i] = order.Uint16(bs[2*i:]) } case []int32: for i := range data { data[i] = int32(order.Uint32(bs[4*i:])) } case []uint32: for i := range data { data[i] = order.Uint32(bs[4*i:]) } case []int64: for i := range data { data[i] = int64(order.Uint64(bs[8*i:])) } case []uint64: for i := range data { data[i] = order.Uint64(bs[8*i:]) } } return nil } // Fallback to reflect-based decoding. v := reflect.ValueOf(data) size := -1 switch v.Kind() { case reflect.Ptr: v = v.Elem() size = dataSize(v) case reflect.Slice: size = dataSize(v) } if size < 0 { return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String()) } d := &decoder{order: order, buf: make([]byte, size)} if _, err := io.ReadFull(r, d.buf); err != nil { return err } d.value(v) return nil } // Write writes the binary representation of data into w. // Data must be a fixed-size value or a slice of fixed-size // values, or a pointer to such data. // Bytes written to w are encoded using the specified byte order // 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 interface{}) error { // Fast path for basic types and slices. if n := intDataSize(data); n != 0 { var b [8]byte var bs []byte if n > len(b) { bs = make([]byte, n) } else { bs = b[:n] } switch v := data.(type) { case *int8: bs = b[:1] b[0] = byte(*v) case int8: bs = b[:1] b[0] = byte(v) case []int8: for i, x := range v { bs[i] = byte(x) } case *uint8: bs = b[:1] b[0] = *v case uint8: bs = b[:1] b[0] = byte(v) case []uint8: bs = v case *int16: bs = b[:2] order.PutUint16(bs, uint16(*v)) case int16: bs = b[:2] order.PutUint16(bs, uint16(v)) case []int16: for i, x := range v { order.PutUint16(bs[2*i:], uint16(x)) } case *uint16: bs = b[:2] order.PutUint16(bs, *v) case uint16: bs = b[:2] order.PutUint16(bs, v) case []uint16: for i, x := range v { order.PutUint16(bs[2*i:], x) } case *int32: bs = b[:4] order.PutUint32(bs, uint32(*v)) case int32: bs = b[:4] order.PutUint32(bs, uint32(v)) case []int32: for i, x := range v { order.PutUint32(bs[4*i:], uint32(x)) } case *uint32: bs = b[:4] order.PutUint32(bs, *v) case uint32: bs = b[:4] order.PutUint32(bs, v) case []uint32: for i, x := range v { order.PutUint32(bs[4*i:], x) } case *int64: bs = b[:8] order.PutUint64(bs, uint64(*v)) case int64: bs = b[:8] order.PutUint64(bs, uint64(v)) case []int64: for i, x := range v { order.PutUint64(bs[8*i:], uint64(x)) } case *uint64: bs = b[:8] order.PutUint64(bs, *v) case uint64: bs = b[:8] order.PutUint64(bs, v) case []uint64: for i, x := range v { order.PutUint64(bs[8*i:], x) } } _, err := w.Write(bs) return err } // Fallback to reflect-based encoding. v := reflect.Indirect(reflect.ValueOf(data)) size := dataSize(v) if size < 0 { return errors.New("binary.Write: invalid type " + reflect.TypeOf(data).String()) } buf := make([]byte, size) e := &encoder{order: order, buf: buf} e.value(v) _, err := w.Write(buf) return err } // 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 interface{}) int { return dataSize(reflect.Indirect(reflect.ValueOf(v))) } // dataSize returns the number of bytes the actual data represented by v occupies in memory. // For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice // it returns the length of the slice times the element size and does not count the memory // occupied by the header. If the type of v is not acceptable, dataSize returns -1. func dataSize(v reflect.Value) int { if v.Kind() == reflect.Slice { if s := sizeof(v.Type().Elem()); s >= 0 { return s * v.Len() } return -1 } return sizeof(v.Type()) } // sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable. func sizeof(t reflect.Type) int { switch t.Kind() { case reflect.Array: if s := sizeof(t.Elem()); s >= 0 { return s * t.Len() } case reflect.Struct: sum := 0 for i, n := 0, t.NumField(); i < n; i++ { s := sizeof(t.Field(i).Type) if s < 0 { return -1 } sum += s } return sum case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Ptr: return int(t.Size()) } return -1 } type coder struct { order ByteOrder buf []byte } type ( decoder coder encoder coder ) func (d *decoder) uint8() uint8 { x := d.buf[0] d.buf = d.buf[1:] return x } func (e *encoder) uint8(x uint8) { e.buf[0] = x e.buf = e.buf[1:] } func (d *decoder) uint16() uint16 { x := d.order.Uint16(d.buf[0:2]) d.buf = d.buf[2:] return x } func (e *encoder) uint16(x uint16) { e.order.PutUint16(e.buf[0:2], x) e.buf = e.buf[2:] } func (d *decoder) uint32() uint32 { x := d.order.Uint32(d.buf[0:4]) d.buf = d.buf[4:] return x } func (e *encoder) uint32(x uint32) { e.order.PutUint32(e.buf[0:4], x) e.buf = e.buf[4:] } func (d *decoder) uint64() uint64 { x := d.order.Uint64(d.buf[0:8]) d.buf = d.buf[8:] return x } func (e *encoder) uint64(x uint64) { e.order.PutUint64(e.buf[0:8], x) e.buf = e.buf[8:] } func (d *decoder) int8() int8 { return int8(d.uint8()) } func (e *encoder) int8(x int8) { e.uint8(uint8(x)) } func (d *decoder) int16() int16 { return int16(d.uint16()) } func (e *encoder) int16(x int16) { e.uint16(uint16(x)) } func (d *decoder) int32() int32 { return int32(d.uint32()) } func (e *encoder) int32(x int32) { e.uint32(uint32(x)) } func (d *decoder) int64() int64 { return int64(d.uint64()) } func (e *encoder) int64(x int64) { e.uint64(uint64(x)) } func (d *decoder) value(v reflect.Value) { switch v.Kind() { case reflect.Array: l := v.Len() for i := 0; i < l; i++ { d.value(v.Index(i)) } case reflect.Struct: t := v.Type() l := v.NumField() for i := 0; i < l; i++ { // Note: Calling v.CanSet() below is an optimization. // It would be sufficient to check the field name, // but creating the StructField info for each field is // costly (run "go test -bench=ReadStruct" and compare // results when making changes to this code). if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" { d.value(v) } else { d.skip(v) } } case reflect.Slice: l := v.Len() for i := 0; i < l; i++ { d.value(v.Index(i)) } case reflect.Int8: v.SetInt(int64(d.int8())) case reflect.Int16: v.SetInt(int64(d.int16())) case reflect.Int32: v.SetInt(int64(d.int32())) case reflect.Int64: v.SetInt(d.int64()) case reflect.Uint8: v.SetUint(uint64(d.uint8())) case reflect.Uint16: v.SetUint(uint64(d.uint16())) case reflect.Uint32: v.SetUint(uint64(d.uint32())) case reflect.Uint64: v.SetUint(d.uint64()) case reflect.Float32: v.SetFloat(float64(math.Float32frombits(d.uint32()))) case reflect.Float64: v.SetFloat(math.Float64frombits(d.uint64())) case reflect.Complex64: v.SetComplex(complex( float64(math.Float32frombits(d.uint32())), float64(math.Float32frombits(d.uint32())), )) case reflect.Complex128: v.SetComplex(complex( math.Float64frombits(d.uint64()), math.Float64frombits(d.uint64()), )) } } func (e *encoder) value(v reflect.Value) { switch v.Kind() { case reflect.Array: l := v.Len() for i := 0; i < l; i++ { e.value(v.Index(i)) } case reflect.Struct: t := v.Type() l := v.NumField() for i := 0; i < l; i++ { // see comment for corresponding code in decoder.value() if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" { e.value(v) } else { e.skip(v) } } case reflect.Slice: l := v.Len() for i := 0; i < l; i++ { e.value(v.Index(i)) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: switch v.Type().Kind() { case reflect.Int8: e.int8(int8(v.Int())) case reflect.Int16: e.int16(int16(v.Int())) case reflect.Int32: e.int32(int32(v.Int())) case reflect.Int64: e.int64(v.Int()) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: switch v.Type().Kind() { case reflect.Uint8: e.uint8(uint8(v.Uint())) case reflect.Uint16: e.uint16(uint16(v.Uint())) case reflect.Uint32: e.uint32(uint32(v.Uint())) case reflect.Uint64: e.uint64(v.Uint()) } case reflect.Float32, reflect.Float64: switch v.Type().Kind() { case reflect.Float32: e.uint32(math.Float32bits(float32(v.Float()))) case reflect.Float64: e.uint64(math.Float64bits(v.Float())) } case reflect.Complex64, reflect.Complex128: switch v.Type().Kind() { case reflect.Complex64: x := v.Complex() e.uint32(math.Float32bits(float32(real(x)))) e.uint32(math.Float32bits(float32(imag(x)))) case reflect.Complex128: x := v.Complex() e.uint64(math.Float64bits(real(x))) e.uint64(math.Float64bits(imag(x))) } } } func (d *decoder) skip(v reflect.Value) { d.buf = d.buf[dataSize(v):] } func (e *encoder) skip(v reflect.Value) { n := dataSize(v) for i := range e.buf[0:n] { e.buf[i] = 0 } e.buf = e.buf[n:] } // 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 interface{}) int { switch data := data.(type) { case int8, *int8, *uint8: return 1 case []int8: return len(data) case []uint8: return len(data) case int16, *int16, *uint16: return 2 case []int16: return 2 * len(data) case []uint16: return 2 * len(data) case int32, *int32, *uint32: return 4 case []int32: return 4 * len(data) case []uint32: return 4 * len(data) case int64, *int64, *uint64: return 8 case []int64: return 8 * len(data) case []uint64: return 8 * len(data) } return 0 } gopsutil-3.24.1/internal/common/common.go000066400000000000000000000244321455407747200204160ustar00rootroot00000000000000package common // // gopsutil is a port of psutil(http://pythonhosted.org/psutil/). // This covers these architectures. // - linux (amd64, arm) // - freebsd (amd64) // - windows (amd64) import ( "bufio" "bytes" "context" "errors" "fmt" "io" "net/url" "os" "os/exec" "path" "path/filepath" "reflect" "runtime" "strconv" "strings" "time" "github.com/shirou/gopsutil/v3/common" ) var ( Timeout = 3 * time.Second ErrTimeout = errors.New("command timed out") ) type Invoker interface { Command(string, ...string) ([]byte, error) CommandWithContext(context.Context, string, ...string) ([]byte, error) } type Invoke struct{} func (i Invoke) Command(name string, arg ...string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), Timeout) defer cancel() return i.CommandWithContext(ctx, name, arg...) } func (i Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) { cmd := exec.CommandContext(ctx, name, arg...) var buf bytes.Buffer cmd.Stdout = &buf cmd.Stderr = &buf if err := cmd.Start(); err != nil { return buf.Bytes(), err } if err := cmd.Wait(); err != nil { return buf.Bytes(), err } return buf.Bytes(), nil } type FakeInvoke struct { Suffix string // Suffix species expected file name suffix such as "fail" Error error // If Error specified, return the error. } // Command in FakeInvoke returns from expected file if exists. func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) { if i.Error != nil { return []byte{}, i.Error } arch := runtime.GOOS commandName := filepath.Base(name) fname := strings.Join(append([]string{commandName}, arg...), "") fname = url.QueryEscape(fname) fpath := path.Join("testdata", arch, fname) if i.Suffix != "" { fpath += "_" + i.Suffix } if PathExists(fpath) { return os.ReadFile(fpath) } return []byte{}, fmt.Errorf("could not find testdata: %s", fpath) } func (i FakeInvoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) { return i.Command(name, arg...) } var ErrNotImplementedError = errors.New("not implemented yet") // ReadFile reads contents from a file func ReadFile(filename string) (string, error) { content, err := os.ReadFile(filename) if err != nil { return "", err } return string(content), nil } // ReadLines reads contents from a file and splits them by new lines. // A convenience wrapper to ReadLinesOffsetN(filename, 0, -1). func ReadLines(filename string) ([]string, error) { return ReadLinesOffsetN(filename, 0, -1) } // ReadLine reads a file and returns the first occurrence of a line that is prefixed with prefix. func ReadLine(filename string, prefix string) (string, error) { f, err := os.Open(filename) if err != nil { return "", err } defer f.Close() r := bufio.NewReader(f) for { line, err := r.ReadString('\n') if err != nil { if err == io.EOF { break } return "", err } if strings.HasPrefix(line, prefix) { return line, nil } } return "", nil } // ReadLinesOffsetN reads contents from file and splits them by new line. // The offset tells at which line number to start. // The count determines the number of lines to read (starting from offset): // n >= 0: at most n lines // n < 0: whole file func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) { f, err := os.Open(filename) if err != nil { return []string{""}, err } defer f.Close() var ret []string r := bufio.NewReader(f) for i := 0; i < n+int(offset) || n < 0; i++ { line, err := r.ReadString('\n') if err != nil { if err == io.EOF && len(line) > 0 { ret = append(ret, strings.Trim(line, "\n")) } break } if i < int(offset) { continue } ret = append(ret, strings.Trim(line, "\n")) } return ret, nil } func IntToString(orig []int8) string { ret := make([]byte, len(orig)) size := -1 for i, o := range orig { if o == 0 { size = i break } ret[i] = byte(o) } if size == -1 { size = len(orig) } return string(ret[0:size]) } func UintToString(orig []uint8) string { ret := make([]byte, len(orig)) size := -1 for i, o := range orig { if o == 0 { size = i break } ret[i] = byte(o) } if size == -1 { size = len(orig) } return string(ret[0:size]) } func ByteToString(orig []byte) string { n := -1 l := -1 for i, b := range orig { // skip left side null if l == -1 && b == 0 { continue } if l == -1 { l = i } if b == 0 { break } n = i + 1 } if n == -1 { return string(orig) } return string(orig[l:n]) } // ReadInts reads contents from single line file and returns them as []int32. func ReadInts(filename string) ([]int64, error) { f, err := os.Open(filename) if err != nil { return []int64{}, err } defer f.Close() var ret []int64 r := bufio.NewReader(f) // The int files that this is concerned with should only be one liners. line, err := r.ReadString('\n') if err != nil { return []int64{}, err } i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32) if err != nil { return []int64{}, err } ret = append(ret, i) return ret, nil } // Parse Hex to uint32 without error func HexToUint32(hex string) uint32 { vv, _ := strconv.ParseUint(hex, 16, 32) return uint32(vv) } // Parse to int32 without error func mustParseInt32(val string) int32 { vv, _ := strconv.ParseInt(val, 10, 32) return int32(vv) } // Parse to uint64 without error func mustParseUint64(val string) uint64 { vv, _ := strconv.ParseInt(val, 10, 64) return uint64(vv) } // Parse to Float64 without error func mustParseFloat64(val string) float64 { vv, _ := strconv.ParseFloat(val, 64) return vv } // StringsHas checks the target string slice contains src or not func StringsHas(target []string, src string) bool { for _, t := range target { if strings.TrimSpace(t) == src { return true } } return false } // StringsContains checks the src in any string of the target string slice func StringsContains(target []string, src string) bool { for _, t := range target { if strings.Contains(t, src) { return true } } return false } // IntContains checks the src in any int of the target int slice. func IntContains(target []int, src int) bool { for _, t := range target { if src == t { return true } } return false } // get struct attributes. // This method is used only for debugging platform dependent code. func attributes(m interface{}) map[string]reflect.Type { typ := reflect.TypeOf(m) if typ.Kind() == reflect.Ptr { typ = typ.Elem() } attrs := make(map[string]reflect.Type) if typ.Kind() != reflect.Struct { return nil } for i := 0; i < typ.NumField(); i++ { p := typ.Field(i) if !p.Anonymous { attrs[p.Name] = p.Type } } return attrs } func PathExists(filename string) bool { if _, err := os.Stat(filename); err == nil { return true } return false } // PathExistsWithContents returns the filename exists and it is not empty func PathExistsWithContents(filename string) bool { info, err := os.Stat(filename) if err != nil { return false } 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. // The context may optionally contain a map superseding os.EnvKey. func GetEnvWithContext(ctx context.Context, key string, dfault string, combineWith ...string) string { var value string if env, ok := ctx.Value(common.EnvKey).(common.EnvMap); ok { value = env[common.EnvKeyType(key)] } if value == "" { value = os.Getenv(key) } if value == "" { value = dfault } return combine(value, combineWith) } // GetEnv retrieves the environment variable key. If it does not exist it returns the default. func GetEnv(key string, dfault string, combineWith ...string) string { value := os.Getenv(key) if value == "" { value = dfault } return combine(value, combineWith) } func combine(value string, combineWith []string) string { switch len(combineWith) { case 0: return value case 1: return filepath.Join(value, combineWith[0]) default: all := make([]string, len(combineWith)+1) all[0] = value copy(all[1:], combineWith) return filepath.Join(all...) } } func HostProc(combineWith ...string) string { return GetEnv("HOST_PROC", "/proc", combineWith...) } func HostSys(combineWith ...string) string { return GetEnv("HOST_SYS", "/sys", combineWith...) } func HostEtc(combineWith ...string) string { return GetEnv("HOST_ETC", "/etc", combineWith...) } func HostVar(combineWith ...string) string { return GetEnv("HOST_VAR", "/var", combineWith...) } func HostRun(combineWith ...string) string { return GetEnv("HOST_RUN", "/run", combineWith...) } func HostDev(combineWith ...string) string { return GetEnv("HOST_DEV", "/dev", combineWith...) } func HostRoot(combineWith ...string) string { return GetEnv("HOST_ROOT", "/", combineWith...) } func HostProcWithContext(ctx context.Context, combineWith ...string) string { return GetEnvWithContext(ctx, "HOST_PROC", "/proc", combineWith...) } func HostProcMountInfoWithContext(ctx context.Context, combineWith ...string) string { return GetEnvWithContext(ctx, "HOST_PROC_MOUNTINFO", "", combineWith...) } func HostSysWithContext(ctx context.Context, combineWith ...string) string { return GetEnvWithContext(ctx, "HOST_SYS", "/sys", combineWith...) } func HostEtcWithContext(ctx context.Context, combineWith ...string) string { return GetEnvWithContext(ctx, "HOST_ETC", "/etc", combineWith...) } func HostVarWithContext(ctx context.Context, combineWith ...string) string { return GetEnvWithContext(ctx, "HOST_VAR", "/var", combineWith...) } func HostRunWithContext(ctx context.Context, combineWith ...string) string { return GetEnvWithContext(ctx, "HOST_RUN", "/run", combineWith...) } func HostDevWithContext(ctx context.Context, combineWith ...string) string { return GetEnvWithContext(ctx, "HOST_DEV", "/dev", combineWith...) } func HostRootWithContext(ctx context.Context, combineWith ...string) string { return GetEnvWithContext(ctx, "HOST_ROOT", "/", combineWith...) } // getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running // sysctl commands (see DoSysctrl). func getSysctrlEnv(env []string) []string { foundLC := false for i, line := range env { if strings.HasPrefix(line, "LC_ALL") { env[i] = "LC_ALL=C" foundLC = true } } if !foundLC { env = append(env, "LC_ALL=C") } return env } gopsutil-3.24.1/internal/common/common_darwin.go000066400000000000000000000027221455407747200217600ustar00rootroot00000000000000//go:build darwin // +build darwin package common import ( "context" "os" "os/exec" "strings" "unsafe" "golang.org/x/sys/unix" ) func DoSysctrlWithContext(ctx context.Context, mib string) ([]string, error) { cmd := exec.CommandContext(ctx, "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) { miblen := uint64(len(mib)) // get required buffer size length := uint64(0) _, _, err := unix.Syscall6( 202, // unix.SYS___SYSCTL https://github.com/golang/sys/blob/76b94024e4b621e672466e8db3d7f084e7ddcad2/unix/zsysnum_darwin_amd64.go#L146 uintptr(unsafe.Pointer(&mib[0])), uintptr(miblen), 0, uintptr(unsafe.Pointer(&length)), 0, 0) if err != 0 { var b []byte return b, length, err } if length == 0 { var b []byte return b, length, err } // get proc info itself buf := make([]byte, length) _, _, err = unix.Syscall6( 202, // unix.SYS___SYSCTL https://github.com/golang/sys/blob/76b94024e4b621e672466e8db3d7f084e7ddcad2/unix/zsysnum_darwin_amd64.go#L146 uintptr(unsafe.Pointer(&mib[0])), uintptr(miblen), uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&length)), 0, 0) if err != 0 { return buf, length, err } return buf, length, nil } gopsutil-3.24.1/internal/common/common_freebsd.go000066400000000000000000000030721455407747200221050ustar00rootroot00000000000000//go:build freebsd || openbsd // +build freebsd openbsd package common import ( "fmt" "os" "os/exec" "strings" "unsafe" "golang.org/x/sys/unix" ) func SysctlUint(mib string) (uint64, error) { buf, err := unix.SysctlRaw(mib) if err != nil { return 0, err } if len(buf) == 8 { // 64 bit return *(*uint64)(unsafe.Pointer(&buf[0])), nil } if len(buf) == 4 { // 32bit t := *(*uint32)(unsafe.Pointer(&buf[0])) return uint64(t), nil } return 0, fmt.Errorf("unexpected size: %s, %d", mib, len(buf)) } 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 } gopsutil-3.24.1/internal/common/common_linux.go000066400000000000000000000176641455407747200216460ustar00rootroot00000000000000//go:build linux // +build linux package common import ( "context" "fmt" "os" "os/exec" "path/filepath" "strconv" "strings" "sync" "sync/atomic" "syscall" "time" ) // cachedBootTime must be accessed via atomic.Load/StoreUint64 var cachedBootTime uint64 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 NumProcs() (uint64, error) { return NumProcsWithContext(context.Background()) } func NumProcsWithContext(ctx context.Context) (uint64, error) { f, err := os.Open(HostProcWithContext(ctx)) if err != nil { return 0, err } defer f.Close() list, err := f.Readdirnames(-1) if err != nil { return 0, err } var cnt uint64 for _, v := range list { if _, err = strconv.ParseUint(v, 10, 64); err == nil { cnt++ } } return cnt, nil } 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) if err != nil { return 0, err } useStatFile := true if system == "lxc" && role == "guest" { // if lxc, /proc/uptime is used. useStatFile = false } else if system == "docker" && role == "guest" { // also docker, guest useStatFile = false } if useStatFile { t, err := readBootTimeStat(ctx) if err != nil { return 0, err } if enableCache { atomic.StoreUint64(&cachedBootTime, t) } } filename := HostProcWithContext(ctx, "uptime") lines, err := ReadLines(filename) if err != nil { return handleBootTimeFileReadErr(err) } if len(lines) != 1 { return 0, fmt.Errorf("wrong uptime format") } f := strings.Fields(lines[0]) b, err := strconv.ParseFloat(f[0], 64) if err != nil { return 0, err } currentTime := float64(time.Now().UnixNano()) / float64(time.Second) t := currentTime - b if enableCache { atomic.StoreUint64(&cachedBootTime, uint64(t)) } return uint64(t), nil } func handleBootTimeFileReadErr(err error) (uint64, error) { if os.IsPermission(err) { var info syscall.Sysinfo_t err := syscall.Sysinfo(&info) if err != nil { return 0, err } currentTime := time.Now().UnixNano() / int64(time.Second) t := currentTime - int64(info.Uptime) return uint64(t), nil } return 0, err } func readBootTimeStat(ctx context.Context) (uint64, error) { filename := HostProcWithContext(ctx, "stat") line, err := ReadLine(filename, "btime") if err != nil { return handleBootTimeFileReadErr(err) } if strings.HasPrefix(line, "btime") { f := strings.Fields(line) if len(f) != 2 { return 0, fmt.Errorf("wrong btime format") } b, err := strconv.ParseInt(f[1], 10, 64) if err != nil { return 0, err } t := uint64(b) return t, nil } return 0, fmt.Errorf("could not find btime") } func Virtualization() (string, string, error) { return VirtualizationWithContext(context.Background()) } // required variables for concurrency safe virtualization caching var ( cachedVirtMap map[string]string cachedVirtMutex sync.RWMutex cachedVirtOnce sync.Once ) func VirtualizationWithContext(ctx context.Context) (string, string, error) { var system, role string // if cached already, return from cache cachedVirtMutex.RLock() // unlock won't be deferred so concurrent reads don't wait for long if cachedVirtMap != nil { cachedSystem, cachedRole := cachedVirtMap["system"], cachedVirtMap["role"] cachedVirtMutex.RUnlock() return cachedSystem, cachedRole, nil } cachedVirtMutex.RUnlock() filename := HostProcWithContext(ctx, "xen") if PathExists(filename) { system = "xen" role = "guest" // assume guest if PathExists(filepath.Join(filename, "capabilities")) { contents, err := ReadLines(filepath.Join(filename, "capabilities")) if err == nil { if StringsContains(contents, "control_d") { role = "host" } } } } filename = HostProcWithContext(ctx, "modules") if PathExists(filename) { contents, err := ReadLines(filename) if err == nil { if StringsContains(contents, "kvm") { system = "kvm" role = "host" } else if StringsContains(contents, "hv_util") { system = "hyperv" role = "guest" } else if StringsContains(contents, "vboxdrv") { system = "vbox" role = "host" } else if StringsContains(contents, "vboxguest") { system = "vbox" role = "guest" } else if StringsContains(contents, "vmware") { system = "vmware" role = "guest" } } } filename = HostProcWithContext(ctx, "cpuinfo") if PathExists(filename) { contents, err := ReadLines(filename) if err == nil { if StringsContains(contents, "QEMU Virtual CPU") || StringsContains(contents, "Common KVM processor") || StringsContains(contents, "Common 32-bit KVM processor") { system = "kvm" role = "guest" } } } filename = HostProcWithContext(ctx, "bus/pci/devices") if PathExists(filename) { contents, err := ReadLines(filename) if err == nil { if StringsContains(contents, "virtio-pci") { role = "guest" } } } filename = HostProcWithContext(ctx) if PathExists(filepath.Join(filename, "bc", "0")) { system = "openvz" role = "host" } else if PathExists(filepath.Join(filename, "vz")) { system = "openvz" role = "guest" } // not use dmidecode because it requires root if PathExists(filepath.Join(filename, "self", "status")) { contents, err := ReadLines(filepath.Join(filename, "self", "status")) if err == nil { if StringsContains(contents, "s_context:") || StringsContains(contents, "VxID:") { system = "linux-vserver" } // TODO: guest or host } } if PathExists(filepath.Join(filename, "1", "environ")) { contents, err := ReadFile(filepath.Join(filename, "1", "environ")) if err == nil { if strings.Contains(contents, "container=lxc") { system = "lxc" role = "guest" } } } if PathExists(filepath.Join(filename, "self", "cgroup")) { contents, err := ReadLines(filepath.Join(filename, "self", "cgroup")) if err == nil { if StringsContains(contents, "lxc") { system = "lxc" role = "guest" } else if StringsContains(contents, "docker") { system = "docker" role = "guest" } else if StringsContains(contents, "machine-rkt") { system = "rkt" role = "guest" } else if PathExists("/usr/bin/lxc-version") { system = "lxc" role = "host" } } } if PathExists(HostEtcWithContext(ctx, "os-release")) { p, _, err := GetOSReleaseWithContext(ctx) if err == nil && p == "coreos" { system = "rkt" // Is it true? role = "host" } } if PathExists(HostRootWithContext(ctx, ".dockerenv")) { system = "docker" role = "guest" } // before returning for the first time, cache the system and role cachedVirtOnce.Do(func() { cachedVirtMutex.Lock() defer cachedVirtMutex.Unlock() cachedVirtMap = map[string]string{ "system": system, "role": role, } }) return system, role, nil } func GetOSRelease() (platform string, version string, err error) { return GetOSReleaseWithContext(context.Background()) } func GetOSReleaseWithContext(ctx context.Context) (platform string, version string, err error) { contents, err := ReadLines(HostEtcWithContext(ctx, "os-release")) if err != nil { return "", "", nil // return empty } for _, line := range contents { field := strings.Split(line, "=") if len(field) < 2 { continue } switch field[0] { case "ID": // use ID for lowercase platform = trimQuotes(field[1]) case "VERSION_ID": version = trimQuotes(field[1]) } } // cleanup amazon ID if platform == "amzn" { platform = "amazon" } return platform, version, nil } // Remove quotes of the source string func trimQuotes(s string) string { if len(s) >= 2 { if s[0] == '"' && s[len(s)-1] == '"' { return s[1 : len(s)-1] } } return s } gopsutil-3.24.1/internal/common/common_netbsd.go000066400000000000000000000022621455407747200217520ustar00rootroot00000000000000//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 } gopsutil-3.24.1/internal/common/common_openbsd.go000066400000000000000000000022641455407747200221270ustar00rootroot00000000000000//go:build openbsd // +build openbsd 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 } gopsutil-3.24.1/internal/common/common_test.go000066400000000000000000000104671455407747200214600ustar00rootroot00000000000000package common import ( "context" "fmt" "os" "reflect" "runtime" "strings" "testing" "github.com/shirou/gopsutil/v3/common" ) func TestReadlines(t *testing.T) { ret, err := ReadLines("common_test.go") if err != nil { t.Error(err) } if !strings.Contains(ret[0], "package common") { t.Error("could not read correctly") } } func TestReadLinesOffsetN(t *testing.T) { ret, err := ReadLinesOffsetN("common_test.go", 2, 1) if err != nil { t.Error(err) } fmt.Println(ret[0]) if !strings.Contains(ret[0], `import (`) { t.Error("could not read correctly") } } func TestIntToString(t *testing.T) { src := []int8{65, 66, 67} dst := IntToString(src) if dst != "ABC" { t.Error("could not convert") } } func TestByteToString(t *testing.T) { src := []byte{65, 66, 67} dst := ByteToString(src) if dst != "ABC" { t.Error("could not convert") } src = []byte{0, 65, 66, 67} dst = ByteToString(src) if dst != "ABC" { t.Error("could not convert") } } func TestHexToUint32(t *testing.T) { if HexToUint32("FFFFFFFF") != 4294967295 { t.Error("Could not convert") } } func TestMustParseInt32(t *testing.T) { ret := mustParseInt32("11111") if ret != int32(11111) { t.Error("could not parse") } } func TestMustParseUint64(t *testing.T) { ret := mustParseUint64("11111") if ret != uint64(11111) { t.Error("could not parse") } } func TestMustParseFloat64(t *testing.T) { ret := mustParseFloat64("11111.11") if ret != float64(11111.11) { t.Error("could not parse") } ret = mustParseFloat64("11111") if ret != float64(11111) { t.Error("could not parse") } } func TestStringsContains(t *testing.T) { target, err := ReadLines("common_test.go") if err != nil { t.Error(err) } if !StringsContains(target, "func TestStringsContains(t *testing.T) {") { t.Error("cloud not test correctly") } } func TestPathExists(t *testing.T) { if !PathExists("common_test.go") { t.Error("exists but return not exists") } if PathExists("should_not_exists.go") { t.Error("not exists but return exists") } } func TestPathExistsWithContents(t *testing.T) { if !PathExistsWithContents("common_test.go") { t.Error("exists but return not exists") } if PathExistsWithContents("should_not_exists.go") { t.Error("not exists but return exists") } f, err := os.CreateTemp("", "empty_test.txt") if err != nil { t.Errorf("CreateTemp failed, %s", err) } defer os.Remove(f.Name()) // clean up if PathExistsWithContents(f.Name()) { t.Error("exists but no content file return true") } } func TestHostEtc(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("windows doesn't have etc") } p := HostEtcWithContext(context.Background(), "mtab") if p != "/etc/mtab" { t.Errorf("invalid HostEtc, %s", p) } } func TestGetSysctrlEnv(t *testing.T) { // Append case env := getSysctrlEnv([]string{"FOO=bar"}) if !reflect.DeepEqual(env, []string{"FOO=bar", "LC_ALL=C"}) { t.Errorf("unexpected append result from getSysctrlEnv: %q", env) } // Replace case env = getSysctrlEnv([]string{"FOO=bar", "LC_ALL=en_US.UTF-8"}) if !reflect.DeepEqual(env, []string{"FOO=bar", "LC_ALL=C"}) { t.Errorf("unexpected replace result from getSysctrlEnv: %q", env) } // Test against real env env = getSysctrlEnv(os.Environ()) found := false for _, v := range env { if v == "LC_ALL=C" { found = true continue } if strings.HasPrefix(v, "LC_ALL") { t.Fatalf("unexpected LC_ALL value: %q", v) } } if !found { t.Errorf("unexpected real result from getSysctrlEnv: %q", env) } } func TestGetEnvDefault(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("windows doesn't have etc") } p := HostEtcWithContext(context.Background(), "mtab") if p != "/etc/mtab" { t.Errorf("invalid HostEtc, %s", p) } } func TestGetEnvWithNoContext(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("windows doesn't have etc") } t.Setenv("HOST_ETC", "/bar") p := HostEtcWithContext(context.Background(), "mtab") if p != "/bar/mtab" { t.Errorf("invalid HostEtc, %s", p) } } func TestGetEnvWithContextOverride(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("windows doesn't have etc") } t.Setenv("HOST_ETC", "/bar") ctx := context.WithValue(context.Background(), common.EnvKey, common.EnvMap{common.HostEtcEnvKey: "/foo"}) p := HostEtcWithContext(ctx, "mtab") if p != "/foo/mtab" { t.Errorf("invalid HostEtc, %s", p) } } gopsutil-3.24.1/internal/common/common_unix.go000066400000000000000000000026221455407747200214560ustar00rootroot00000000000000//go:build linux || freebsd || darwin || openbsd // +build linux freebsd darwin openbsd package common import ( "context" "errors" "os/exec" "strconv" "strings" ) func CallLsofWithContext(ctx context.Context, invoke Invoker, pid int32, args ...string) ([]string, error) { var cmd []string if pid == 0 { // will get from all processes. cmd = []string{"-a", "-n", "-P"} } else { cmd = []string{"-a", "-n", "-P", "-p", strconv.Itoa(int(pid))} } cmd = append(cmd, args...) out, err := invoke.CommandWithContext(ctx, "lsof", cmd...) if err != nil { if errors.Is(err, exec.ErrNotFound) { return []string{}, err } // if no pid found, lsof returns code 1. if err.Error() == "exit status 1" && len(out) == 0 { return []string{}, nil } } lines := strings.Split(string(out), "\n") var ret []string for _, l := range lines[1:] { if len(l) == 0 { continue } ret = append(ret, l) } return ret, nil } func CallPgrepWithContext(ctx context.Context, invoke Invoker, pid int32) ([]int32, error) { out, err := invoke.CommandWithContext(ctx, "pgrep", "-P", strconv.Itoa(int(pid))) if err != nil { return []int32{}, err } lines := strings.Split(string(out), "\n") ret := make([]int32, 0, len(lines)) for _, l := range lines { if len(l) == 0 { continue } i, err := strconv.ParseInt(l, 10, 32) if err != nil { continue } ret = append(ret, int32(i)) } return ret, nil } gopsutil-3.24.1/internal/common/common_windows.go000066400000000000000000000200561455407747200221660ustar00rootroot00000000000000//go:build windows // +build windows package common import ( "context" "fmt" "path/filepath" "reflect" "strings" "syscall" "unsafe" "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows" ) // for double values type PDH_FMT_COUNTERVALUE_DOUBLE struct { CStatus uint32 DoubleValue float64 } // for 64 bit integer values type PDH_FMT_COUNTERVALUE_LARGE struct { CStatus uint32 LargeValue int64 } // for long values type PDH_FMT_COUNTERVALUE_LONG struct { CStatus uint32 LongValue int32 padding [4]byte } // windows system const const ( ERROR_SUCCESS = 0 ERROR_FILE_NOT_FOUND = 2 DRIVE_REMOVABLE = 2 DRIVE_FIXED = 3 HKEY_LOCAL_MACHINE = 0x80000002 RRF_RT_REG_SZ = 0x00000002 RRF_RT_REG_DWORD = 0x00000010 PDH_FMT_LONG = 0x00000100 PDH_FMT_DOUBLE = 0x00000200 PDH_FMT_LARGE = 0x00000400 PDH_INVALID_DATA = 0xc0000bc6 PDH_INVALID_HANDLE = 0xC0000bbc PDH_NO_DATA = 0x800007d5 STATUS_BUFFER_OVERFLOW = 0x80000005 STATUS_BUFFER_TOO_SMALL = 0xC0000023 STATUS_INFO_LENGTH_MISMATCH = 0xC0000004 ) const ( ProcessBasicInformation = 0 ProcessWow64Information = 26 ProcessQueryInformation = windows.PROCESS_DUP_HANDLE | windows.PROCESS_QUERY_INFORMATION SystemExtendedHandleInformationClass = 64 ) var ( Modkernel32 = windows.NewLazySystemDLL("kernel32.dll") ModNt = windows.NewLazySystemDLL("ntdll.dll") ModPdh = windows.NewLazySystemDLL("pdh.dll") ModPsapi = windows.NewLazySystemDLL("psapi.dll") ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes") ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation") ProcRtlGetNativeSystemInformation = ModNt.NewProc("RtlGetNativeSystemInformation") ProcRtlNtStatusToDosError = ModNt.NewProc("RtlNtStatusToDosError") ProcNtQueryInformationProcess = ModNt.NewProc("NtQueryInformationProcess") ProcNtReadVirtualMemory = ModNt.NewProc("NtReadVirtualMemory") ProcNtWow64QueryInformationProcess64 = ModNt.NewProc("NtWow64QueryInformationProcess64") ProcNtWow64ReadVirtualMemory64 = ModNt.NewProc("NtWow64ReadVirtualMemory64") PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery") PdhAddEnglishCounterW = ModPdh.NewProc("PdhAddEnglishCounterW") PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData") PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue") PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery") procQueryDosDeviceW = Modkernel32.NewProc("QueryDosDeviceW") ) type FILETIME struct { DwLowDateTime uint32 DwHighDateTime uint32 } // borrowed from net/interface_windows.go func BytePtrToString(p *uint8) string { a := (*[10000]uint8)(unsafe.Pointer(p)) i := 0 for a[i] != 0 { i++ } return string(a[:i]) } // CounterInfo struct is used to track a windows performance counter // copied from https://github.com/mackerelio/mackerel-agent/ type CounterInfo struct { PostName string CounterName string Counter windows.Handle } // CreateQuery with a PdhOpenQuery call // copied from https://github.com/mackerelio/mackerel-agent/ func CreateQuery() (windows.Handle, error) { var query windows.Handle r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query))) if r != 0 { return 0, err } return query, nil } // CreateCounter with a PdhAddEnglishCounterW call func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) { var counter windows.Handle r, _, err := PdhAddEnglishCounterW.Call( uintptr(query), uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cname))), 0, uintptr(unsafe.Pointer(&counter))) if r != 0 { return nil, err } return &CounterInfo{ PostName: pname, CounterName: cname, Counter: counter, }, nil } // GetCounterValue get counter value from handle // adapted from https://github.com/mackerelio/mackerel-agent/ func GetCounterValue(counter windows.Handle) (float64, error) { var value PDH_FMT_COUNTERVALUE_DOUBLE r, _, err := PdhGetFormattedCounterValue.Call(uintptr(counter), PDH_FMT_DOUBLE, uintptr(0), uintptr(unsafe.Pointer(&value))) if r != 0 && r != PDH_INVALID_DATA { return 0.0, err } return value.DoubleValue, nil } type Win32PerformanceCounter struct { PostName string CounterName string Query windows.Handle Counter windows.Handle } func NewWin32PerformanceCounter(postName, counterName string) (*Win32PerformanceCounter, error) { query, err := CreateQuery() if err != nil { return nil, err } counter := Win32PerformanceCounter{ Query: query, PostName: postName, CounterName: counterName, } r, _, err := PdhAddEnglishCounterW.Call( uintptr(counter.Query), uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(counter.CounterName))), 0, uintptr(unsafe.Pointer(&counter.Counter)), ) if r != 0 { return nil, err } return &counter, nil } func (w *Win32PerformanceCounter) GetValue() (float64, error) { r, _, err := PdhCollectQueryData.Call(uintptr(w.Query)) if r != 0 && err != nil { if r == PDH_NO_DATA { return 0.0, fmt.Errorf("%w: this counter has not data", err) } return 0.0, err } return GetCounterValue(w.Counter) } func ProcessorQueueLengthCounter() (*Win32PerformanceCounter, error) { return NewWin32PerformanceCounter("processor_queue_length", `\System\Processor Queue Length`) } // WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging 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() ctx = ctxTimeout } errChan := make(chan error, 1) go func() { errChan <- wmi.Query(query, dst, connectServerArgs...) }() select { case <-ctx.Done(): return ctx.Err() case err := <-errChan: return err } } // Convert paths using native DOS format like: // // "\Device\HarddiskVolume1\Windows\systemew\file.txt" // // into: // // "C:\Windows\systemew\file.txt" func ConvertDOSPath(p string) string { rawDrive := strings.Join(strings.Split(p, `\`)[:3], `\`) for d := 'A'; d <= 'Z'; d++ { szDeviceName := string(d) + ":" szTarget := make([]uint16, 512) ret, _, _ := procQueryDosDeviceW.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(szDeviceName))), uintptr(unsafe.Pointer(&szTarget[0])), uintptr(len(szTarget))) if ret != 0 && windows.UTF16ToString(szTarget[:]) == rawDrive { return filepath.Join(szDeviceName, p[len(rawDrive):]) } } return p } type NtStatus uint32 func (s NtStatus) Error() error { if s == 0 { return nil } return fmt.Errorf("NtStatus 0x%08x", uint32(s)) } func (s NtStatus) IsError() bool { return s>>30 == 3 } type SystemExtendedHandleTableEntryInformation struct { Object uintptr UniqueProcessId uintptr HandleValue uintptr GrantedAccess uint32 CreatorBackTraceIndex uint16 ObjectTypeIndex uint16 HandleAttributes uint32 Reserved uint32 } type SystemExtendedHandleInformation struct { NumberOfHandles uintptr Reserved uintptr Handles [1]SystemExtendedHandleTableEntryInformation } // CallWithExpandingBuffer https://github.com/hillu/go-ntdll func CallWithExpandingBuffer(fn func() NtStatus, buf *[]byte, resultLength *uint32) NtStatus { for { 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 } } } func NtQuerySystemInformation( SystemInformationClass uint32, SystemInformation *byte, SystemInformationLength uint32, ReturnLength *uint32, ) NtStatus { r0, _, _ := ProcNtQuerySystemInformation.Call( uintptr(SystemInformationClass), uintptr(unsafe.Pointer(SystemInformation)), uintptr(SystemInformationLength), uintptr(unsafe.Pointer(ReturnLength))) return NtStatus(r0) } gopsutil-3.24.1/internal/common/endian.go000066400000000000000000000004551455407747200203630ustar00rootroot00000000000000package common import "unsafe" // IsLittleEndian checks if the current platform uses little-endian. // copied from https://github.com/ntrrg/ntgo/blob/v0.8.0/runtime/infrastructure.go#L16 (MIT License) func IsLittleEndian() bool { var x int16 = 0x0011 return *(*byte)(unsafe.Pointer(&x)) == 0x11 } gopsutil-3.24.1/internal/common/sleep.go000066400000000000000000000005401455407747200202300ustar00rootroot00000000000000package common import ( "context" "time" ) // Sleep awaits for provided interval. // Can be interrupted by context cancelation. func Sleep(ctx context.Context, interval time.Duration) error { timer := time.NewTimer(interval) select { case <-ctx.Done(): if !timer.Stop() { <-timer.C } return ctx.Err() case <-timer.C: return nil } } gopsutil-3.24.1/internal/common/sleep_test.go000066400000000000000000000011321455407747200212650ustar00rootroot00000000000000package common_test import ( "context" "errors" "testing" "time" "github.com/shirou/gopsutil/v3/internal/common" ) func TestSleep(test *testing.T) { const dt = 50 * time.Millisecond t := func(name string, ctx context.Context, expected error) { test.Run(name, func(test *testing.T) { err := common.Sleep(ctx, dt) if !errors.Is(err, expected) { test.Errorf("expected %v, got %v", expected, err) } }) } ctx := context.Background() canceled, cancel := context.WithCancel(ctx) cancel() t("background context", ctx, nil) t("canceled context", canceled, context.Canceled) } gopsutil-3.24.1/internal/common/warnings.go000066400000000000000000000007341455407747200207550ustar00rootroot00000000000000package common import "fmt" type Warnings struct { List []error Verbose bool } func (w *Warnings) Add(err error) { w.List = append(w.List, err) } func (w *Warnings) Reference() error { if len(w.List) > 0 { return w } return nil } func (w *Warnings) Error() string { if w.Verbose { str := "" for i, e := range w.List { str += fmt.Sprintf("\tError %d: %s\n", i, e.Error()) } return str } return fmt.Sprintf("Number of warnings: %v", len(w.List)) } gopsutil-3.24.1/load/000077500000000000000000000000001455407747200144055ustar00rootroot00000000000000gopsutil-3.24.1/load/load.go000066400000000000000000000011731455407747200156550ustar00rootroot00000000000000package load import ( "encoding/json" "github.com/shirou/gopsutil/v3/internal/common" ) var invoke common.Invoker = common.Invoke{} type AvgStat struct { Load1 float64 `json:"load1"` Load5 float64 `json:"load5"` Load15 float64 `json:"load15"` } func (l AvgStat) String() string { s, _ := json.Marshal(l) return string(s) } type MiscStat struct { ProcsTotal int `json:"procsTotal"` ProcsCreated int `json:"procsCreated"` ProcsRunning int `json:"procsRunning"` ProcsBlocked int `json:"procsBlocked"` Ctxt int `json:"ctxt"` } func (m MiscStat) String() string { s, _ := json.Marshal(m) return string(s) } gopsutil-3.24.1/load/load_aix.go000066400000000000000000000006271455407747200165210ustar00rootroot00000000000000//go:build aix // +build aix package load import ( "context" ) func Avg() (*AvgStat, error) { return AvgWithContext(context.Background()) } // Misc returns miscellaneous host-wide statistics. // darwin use ps command to get process running/blocked count. // Almost same as Darwin implementation, but state is different. func Misc() (*MiscStat, error) { return MiscWithContext(context.Background()) } gopsutil-3.24.1/load/load_aix_cgo.go000066400000000000000000000017451455407747200173530ustar00rootroot00000000000000//go:build aix && cgo // +build aix,cgo package load /* #cgo LDFLAGS: -L/usr/lib -lperfstat #include #include */ import "C" import ( "context" "unsafe" "github.com/power-devops/perfstat" ) func AvgWithContext(ctx context.Context) (*AvgStat, error) { c, err := perfstat.CpuTotalStat() if err != nil { return nil, err } ret := &AvgStat{ Load1: float64(c.LoadAvg1), Load5: float64(c.LoadAvg5), Load15: float64(c.LoadAvg15), } return ret, nil } func MiscWithContext(ctx context.Context) (*MiscStat, error) { info := C.struct_procentry64{} cpid := C.pid_t(0) ret := MiscStat{} for { // getprocs first argument is a void* num, err := C.getprocs64(unsafe.Pointer(&info), C.sizeof_struct_procentry64, nil, 0, &cpid, 1) if err != nil { return nil, err } ret.ProcsTotal++ switch info.pi_state { case C.SACTIVE: ret.ProcsRunning++ case C.SSTOP: ret.ProcsBlocked++ } if num == 0 { break } } return &ret, nil } gopsutil-3.24.1/load/load_aix_nocgo.go000066400000000000000000000024521455407747200177040ustar00rootroot00000000000000//go:build aix && !cgo // +build aix,!cgo package load import ( "context" "regexp" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" ) var separator = regexp.MustCompile(`,?\s+`) func AvgWithContext(ctx context.Context) (*AvgStat, error) { line, err := invoke.CommandWithContext(ctx, "uptime") if err != nil { return nil, err } idx := strings.Index(string(line), "load average:") if idx < 0 { return nil, common.ErrNotImplementedError } ret := &AvgStat{} p := separator.Split(string(line[idx:len(line)]), 5) if 4 < len(p) && p[0] == "load" && p[1] == "average:" { if t, err := strconv.ParseFloat(p[2], 64); err == nil { ret.Load1 = t } if t, err := strconv.ParseFloat(p[3], 64); err == nil { ret.Load5 = t } if t, err := strconv.ParseFloat(p[4], 64); err == nil { ret.Load15 = t } return ret, nil } return nil, common.ErrNotImplementedError } func MiscWithContext(ctx context.Context) (*MiscStat, error) { out, err := invoke.CommandWithContext(ctx, "ps", "-Ao", "state") if err != nil { return nil, err } ret := &MiscStat{} for _, line := range strings.Split(string(out), "\n") { ret.ProcsTotal++ switch line { case "R": case "A": ret.ProcsRunning++ case "T": ret.ProcsBlocked++ default: continue } } return ret, nil } gopsutil-3.24.1/load/load_bsd.go000066400000000000000000000031071455407747200165040ustar00rootroot00000000000000//go:build freebsd || openbsd // +build freebsd openbsd package load import ( "context" "strings" "unsafe" "golang.org/x/sys/unix" ) func Avg() (*AvgStat, error) { return AvgWithContext(context.Background()) } func AvgWithContext(ctx context.Context) (*AvgStat, error) { // This SysctlRaw method borrowed from // https://github.com/prometheus/node_exporter/blob/master/collector/loadavg_freebsd.go type loadavg struct { load [3]uint32 scale int } b, err := unix.SysctlRaw("vm.loadavg") if err != nil { return nil, err } load := *(*loadavg)(unsafe.Pointer((&b[0]))) scale := float64(load.scale) ret := &AvgStat{ Load1: float64(load.load[0]) / scale, Load5: float64(load.load[1]) / scale, Load15: float64(load.load[2]) / scale, } return ret, nil } type forkstat struct { forks int vforks int __tforks int } // Misc returns miscellaneous host-wide statistics. // darwin use ps command to get process running/blocked count. // Almost same as Darwin implementation, but state is different. func Misc() (*MiscStat, error) { return MiscWithContext(context.Background()) } func MiscWithContext(ctx context.Context) (*MiscStat, error) { out, err := invoke.CommandWithContext(ctx, "ps", "axo", "state") if err != nil { return nil, err } lines := strings.Split(string(out), "\n") ret := MiscStat{} for _, l := range lines { if strings.Contains(l, "R") { ret.ProcsRunning++ } else if strings.Contains(l, "D") { ret.ProcsBlocked++ } } f, err := getForkStat() if err != nil { return nil, err } ret.ProcsCreated = f.forks return &ret, nil } gopsutil-3.24.1/load/load_darwin.go000066400000000000000000000030121455407747200172130ustar00rootroot00000000000000//go:build darwin // +build darwin package load import ( "context" "strings" "unsafe" "golang.org/x/sys/unix" ) func Avg() (*AvgStat, error) { return AvgWithContext(context.Background()) } func AvgWithContext(ctx context.Context) (*AvgStat, error) { // This SysctlRaw method borrowed from // https://github.com/prometheus/node_exporter/blob/master/collector/loadavg_freebsd.go // this implementation is common with BSDs type loadavg struct { load [3]uint32 scale int } b, err := unix.SysctlRaw("vm.loadavg") if err != nil { return nil, err } load := *(*loadavg)(unsafe.Pointer((&b[0]))) scale := float64(load.scale) ret := &AvgStat{ Load1: float64(load.load[0]) / scale, Load5: float64(load.load[1]) / scale, Load15: float64(load.load[2]) / scale, } return ret, nil } // Misc returns miscellaneous host-wide statistics. // darwin use ps command to get process running/blocked count. // Almost same as FreeBSD implementation, but state is different. // U means 'Uninterruptible Sleep'. func Misc() (*MiscStat, error) { return MiscWithContext(context.Background()) } func MiscWithContext(ctx context.Context) (*MiscStat, error) { out, err := invoke.CommandWithContext(ctx, "ps", "axo", "state") if err != nil { return nil, err } lines := strings.Split(string(out), "\n") ret := MiscStat{} for _, l := range lines { if strings.Contains(l, "R") { ret.ProcsRunning++ } else if strings.Contains(l, "U") { // uninterruptible sleep == blocked ret.ProcsBlocked++ } } return &ret, nil } gopsutil-3.24.1/load/load_fallback.go000066400000000000000000000011471455407747200174750ustar00rootroot00000000000000//go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !aix // +build !darwin,!linux,!freebsd,!openbsd,!windows,!solaris,!aix package load import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func Avg() (*AvgStat, error) { return AvgWithContext(context.Background()) } func AvgWithContext(ctx context.Context) (*AvgStat, error) { return nil, common.ErrNotImplementedError } func Misc() (*MiscStat, error) { return MiscWithContext(context.Background()) } func MiscWithContext(ctx context.Context) (*MiscStat, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/load/load_freebsd.go000066400000000000000000000001651455407747200173470ustar00rootroot00000000000000//go:build freebsd // +build freebsd package load func getForkStat() (forkstat, error) { return forkstat{}, nil } gopsutil-3.24.1/load/load_linux.go000066400000000000000000000053351455407747200171000ustar00rootroot00000000000000//go:build linux // +build linux package load import ( "context" "os" "strconv" "strings" "syscall" "github.com/shirou/gopsutil/v3/internal/common" ) func Avg() (*AvgStat, error) { return AvgWithContext(context.Background()) } func AvgWithContext(ctx context.Context) (*AvgStat, error) { stat, err := fileAvgWithContext(ctx) if err != nil { stat, err = sysinfoAvgWithContext() } return stat, err } func sysinfoAvgWithContext() (*AvgStat, error) { var info syscall.Sysinfo_t err := syscall.Sysinfo(&info) if err != nil { return nil, err } const si_load_shift = 16 return &AvgStat{ Load1: float64(info.Loads[0]) / float64(1< 2 { if t, err := strconv.ParseUint(p[1], 10, 64); err == nil { vmem.Total = t * pagesize } if t, err := strconv.ParseUint(p[2], 10, 64); err == nil { vmem.Used = t * pagesize if vmem.Total > 0 { vmem.UsedPercent = 100 * float64(vmem.Used) / float64(vmem.Total) } } if t, err := strconv.ParseUint(p[3], 10, 64); err == nil { vmem.Free = t * pagesize } } } else if strings.HasPrefix(line, "pg space") { p := strings.Fields(line) if len(p) > 3 { if t, err := strconv.ParseUint(p[2], 10, 64); err == nil { swap.Total = t * pagesize } if t, err := strconv.ParseUint(p[3], 10, 64); err == nil { swap.Free = swap.Total - t*pagesize } } break } } return vmem, swap, nil } gopsutil-3.24.1/mem/mem_bsd.go000066400000000000000000000047521455407747200162110ustar00rootroot00000000000000//go:build freebsd || openbsd || netbsd // +build freebsd openbsd netbsd package mem import ( "context" "fmt" "strconv" "strings" ) const swapCommand = "swapctl" // swapctl column indexes const ( nameCol = 0 totalKiBCol = 1 usedKiBCol = 2 ) func SwapDevices() ([]*SwapDevice, error) { return SwapDevicesWithContext(context.Background()) } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { output, err := invoke.CommandWithContext(ctx, swapCommand, "-lk") if err != nil { return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err) } return parseSwapctlOutput(string(output)) } func parseSwapctlOutput(output string) ([]*SwapDevice, error) { lines := strings.Split(output, "\n") if len(lines) == 0 { return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output) } // Check header headerFields are as expected. header := lines[0] header = strings.ToLower(header) header = strings.ReplaceAll(header, ":", "") headerFields := strings.Fields(header) if len(headerFields) < usedKiBCol { return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, header) } if headerFields[nameCol] != "device" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "device") } if headerFields[totalKiBCol] != "1kb-blocks" && headerFields[totalKiBCol] != "1k-blocks" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalKiBCol], "1kb-blocks") } if headerFields[usedKiBCol] != "used" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[usedKiBCol], "used") } var swapDevices []*SwapDevice for _, line := range lines[1:] { if line == "" { continue // the terminal line is typically empty } fields := strings.Fields(line) if len(fields) < usedKiBCol { return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand) } totalKiB, err := strconv.ParseUint(fields[totalKiBCol], 10, 64) if err != nil { return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err) } usedKiB, err := strconv.ParseUint(fields[usedKiBCol], 10, 64) if err != nil { return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err) } swapDevices = append(swapDevices, &SwapDevice{ Name: fields[nameCol], UsedBytes: usedKiB * 1024, FreeBytes: (totalKiB - usedKiB) * 1024, }) } return swapDevices, nil } gopsutil-3.24.1/mem/mem_bsd_test.go000066400000000000000000000026051455407747200172430ustar00rootroot00000000000000//go:build freebsd || openbsd // +build freebsd openbsd package mem import ( "testing" "github.com/stretchr/testify/assert" ) const validFreeBSD = `Device: 1kB-blocks Used: /dev/gpt/swapfs 1048576 1234 /dev/md0 1048576 666 ` const validOpenBSD = `Device 1K-blocks Used Avail Capacity Priority /dev/wd0b 655025 1234 653791 1% 0 ` const invalid = `Device: 512-blocks Used: /dev/gpt/swapfs 1048576 1234 /dev/md0 1048576 666 ` func TestParseSwapctlOutput_FreeBSD(t *testing.T) { assert := assert.New(t) stats, err := parseSwapctlOutput(validFreeBSD) assert.NoError(err) assert.Equal(*stats[0], SwapDevice{ Name: "/dev/gpt/swapfs", UsedBytes: 1263616, FreeBytes: 1072478208, }) assert.Equal(*stats[1], SwapDevice{ Name: "/dev/md0", UsedBytes: 681984, FreeBytes: 1073059840, }) } func TestParseSwapctlOutput_OpenBSD(t *testing.T) { assert := assert.New(t) stats, err := parseSwapctlOutput(validOpenBSD) assert.NoError(err) assert.Equal(*stats[0], SwapDevice{ Name: "/dev/wd0b", UsedBytes: 1234 * 1024, FreeBytes: 653791 * 1024, }) } func TestParseSwapctlOutput_Invalid(t *testing.T) { _, err := parseSwapctlOutput(invalid) assert.Error(t, err) } func TestParseSwapctlOutput_Empty(t *testing.T) { _, err := parseSwapctlOutput("") assert.Error(t, err) } gopsutil-3.24.1/mem/mem_darwin.go000066400000000000000000000030161455407747200167150ustar00rootroot00000000000000//go:build darwin // +build darwin package mem import ( "context" "fmt" "unsafe" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/internal/common" ) func getHwMemsize() (uint64, error) { total, err := unix.SysctlUint64("hw.memsize") if err != nil { return 0, err } return total, nil } // xsw_usage in sys/sysctl.h type swapUsage struct { Total uint64 Avail uint64 Used uint64 Pagesize int32 Encrypted bool } // SwapMemory returns swapinfo. func SwapMemory() (*SwapMemoryStat, error) { return SwapMemoryWithContext(context.Background()) } func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { // https://github.com/yanllearnn/go-osstat/blob/ae8a279d26f52ec946a03698c7f50a26cfb427e3/memory/memory_darwin.go var ret *SwapMemoryStat value, err := unix.SysctlRaw("vm.swapusage") if err != nil { return ret, err } if len(value) != 32 { return ret, fmt.Errorf("unexpected output of sysctl vm.swapusage: %v (len: %d)", value, len(value)) } swap := (*swapUsage)(unsafe.Pointer(&value[0])) u := float64(0) if swap.Total != 0 { u = ((float64(swap.Total) - float64(swap.Avail)) / float64(swap.Total)) * 100.0 } ret = &SwapMemoryStat{ Total: swap.Total, Used: swap.Used, Free: swap.Avail, UsedPercent: u, } return ret, nil } func SwapDevices() ([]*SwapDevice, error) { return SwapDevicesWithContext(context.Background()) } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/mem/mem_darwin_cgo.go000066400000000000000000000027001455407747200175440ustar00rootroot00000000000000//go:build darwin && cgo // +build darwin,cgo package mem /* #include #include */ import "C" import ( "context" "fmt" "unsafe" ) // VirtualMemory returns VirtualmemoryStat. func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { count := C.mach_msg_type_number_t(C.HOST_VM_INFO_COUNT) var vmstat C.vm_statistics_data_t status := C.host_statistics(C.host_t(C.mach_host_self()), C.HOST_VM_INFO, C.host_info_t(unsafe.Pointer(&vmstat)), &count) if status != C.KERN_SUCCESS { return nil, fmt.Errorf("host_statistics error=%d", status) } pageSize := uint64(C.vm_kernel_page_size) total, err := getHwMemsize() if err != nil { return nil, err } totalCount := C.natural_t(total / pageSize) availableCount := vmstat.inactive_count + vmstat.free_count usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount) usedCount := totalCount - availableCount return &VirtualMemoryStat{ Total: total, Available: pageSize * uint64(availableCount), Used: pageSize * uint64(usedCount), UsedPercent: usedPercent, Free: pageSize * uint64(vmstat.free_count), Active: pageSize * uint64(vmstat.active_count), Inactive: pageSize * uint64(vmstat.inactive_count), Wired: pageSize * uint64(vmstat.wire_count), }, nil } gopsutil-3.24.1/mem/mem_darwin_nocgo.go000066400000000000000000000035001455407747200201000ustar00rootroot00000000000000//go:build darwin && !cgo // +build darwin,!cgo package mem import ( "context" "strconv" "strings" "golang.org/x/sys/unix" ) // Runs vm_stat and returns Free and inactive pages func getVMStat(vms *VirtualMemoryStat) error { out, err := invoke.Command("vm_stat") if err != nil { return err } return parseVMStat(string(out), vms) } func parseVMStat(out string, vms *VirtualMemoryStat) error { var err error lines := strings.Split(out, "\n") pagesize := uint64(unix.Getpagesize()) for _, line := range lines { fields := strings.Split(line, ":") if len(fields) < 2 { continue } key := strings.TrimSpace(fields[0]) value := strings.Trim(fields[1], " .") switch key { case "Pages free": free, e := strconv.ParseUint(value, 10, 64) if e != nil { err = e } vms.Free = free * pagesize case "Pages inactive": inactive, e := strconv.ParseUint(value, 10, 64) if e != nil { err = e } vms.Inactive = inactive * pagesize case "Pages active": active, e := strconv.ParseUint(value, 10, 64) if e != nil { err = e } vms.Active = active * pagesize case "Pages wired down": wired, e := strconv.ParseUint(value, 10, 64) if e != nil { err = e } vms.Wired = wired * pagesize } } return err } // VirtualMemory returns VirtualmemoryStat. func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { ret := &VirtualMemoryStat{} total, err := getHwMemsize() if err != nil { return nil, err } err = getVMStat(ret) if err != nil { return nil, err } ret.Available = ret.Free + ret.Inactive ret.Total = total ret.Used = ret.Total - ret.Available ret.UsedPercent = 100 * float64(ret.Used) / float64(ret.Total) return ret, nil } gopsutil-3.24.1/mem/mem_darwin_test.go000066400000000000000000000020371455407747200177560ustar00rootroot00000000000000//go:build darwin // +build darwin package mem import ( "strconv" "strings" "testing" "github.com/stretchr/testify/assert" ) func TestVirtualMemoryDarwin(t *testing.T) { v, err := VirtualMemory() assert.Nil(t, err) outBytes, err := invoke.Command("/usr/sbin/sysctl", "hw.memsize") assert.Nil(t, err) outString := string(outBytes) outString = strings.TrimSpace(outString) outParts := strings.Split(outString, " ") actualTotal, err := strconv.ParseInt(outParts[1], 10, 64) assert.Nil(t, err) assert.Equal(t, uint64(actualTotal), v.Total) assert.True(t, v.Available > 0) assert.Equal(t, v.Available, v.Free+v.Inactive, "%v", v) assert.True(t, v.Used > 0) assert.True(t, v.Used < v.Total) assert.True(t, v.UsedPercent > 0) assert.True(t, v.UsedPercent < 100) assert.True(t, v.Free > 0) assert.True(t, v.Free < v.Available) assert.True(t, v.Active > 0) assert.True(t, v.Active < v.Total) assert.True(t, v.Inactive > 0) assert.True(t, v.Inactive < v.Total) assert.True(t, v.Wired > 0) assert.True(t, v.Wired < v.Total) } gopsutil-3.24.1/mem/mem_fallback.go000066400000000000000000000016661455407747200172010ustar00rootroot00000000000000//go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !plan9 && !aix && !netbsd // +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows,!plan9,!aix,!netbsd package mem import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { return nil, common.ErrNotImplementedError } func SwapMemory() (*SwapMemoryStat, error) { return SwapMemoryWithContext(context.Background()) } func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { return nil, common.ErrNotImplementedError } func SwapDevices() ([]*SwapDevice, error) { return SwapDevicesWithContext(context.Background()) } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/mem/mem_freebsd.go000066400000000000000000000076351455407747200170560ustar00rootroot00000000000000//go:build freebsd // +build freebsd package mem import ( "context" "errors" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/unix" ) func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { pageSize, err := common.SysctlUint("vm.stats.vm.v_page_size") if err != nil { return nil, err } physmem, err := common.SysctlUint("hw.physmem") if err != nil { return nil, err } free, err := common.SysctlUint("vm.stats.vm.v_free_count") if err != nil { return nil, err } active, err := common.SysctlUint("vm.stats.vm.v_active_count") if err != nil { return nil, err } inactive, err := common.SysctlUint("vm.stats.vm.v_inactive_count") if err != nil { return nil, err } buffers, err := common.SysctlUint("vfs.bufspace") if err != nil { return nil, err } wired, err := common.SysctlUint("vm.stats.vm.v_wire_count") if err != nil { return nil, err } var cached, laundry uint64 osreldate, _ := common.SysctlUint("kern.osreldate") if osreldate < 1102000 { cached, err = common.SysctlUint("vm.stats.vm.v_cache_count") if err != nil { return nil, err } } else { laundry, err = common.SysctlUint("vm.stats.vm.v_laundry_count") if err != nil { return nil, err } } p := pageSize ret := &VirtualMemoryStat{ Total: physmem, Free: free * p, Active: active * p, Inactive: inactive * p, Cached: cached * p, Buffers: buffers, Wired: wired * p, Laundry: laundry * p, } ret.Available = ret.Inactive + ret.Cached + ret.Free + ret.Laundry ret.Used = ret.Total - ret.Available ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0 return ret, nil } // Return swapinfo func SwapMemory() (*SwapMemoryStat, error) { return SwapMemoryWithContext(context.Background()) } // Constants from vm/vm_param.h // nolint: golint const ( XSWDEV_VERSION11 = 1 XSWDEV_VERSION = 2 ) // Types from vm/vm_param.h type xswdev struct { Version uint32 // Version is the version Dev uint64 // Dev is the device identifier Flags int32 // Flags is the swap flags applied to the device NBlks int32 // NBlks is the total number of blocks Used int32 // Used is the number of blocks used } // xswdev11 is a compatibility for under FreeBSD 11 // sys/vm/swap_pager.c type xswdev11 struct { Version uint32 // Version is the version Dev uint32 // Dev is the device identifier Flags int32 // Flags is the swap flags applied to the device NBlks int32 // NBlks is the total number of blocks Used int32 // Used is the number of blocks used } func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { // FreeBSD can have multiple swap devices so we total them up i, err := common.SysctlUint("vm.nswapdev") if err != nil { return nil, err } if i == 0 { return nil, errors.New("no swap devices found") } c := int(i) i, err = common.SysctlUint("vm.stats.vm.v_page_size") if err != nil { return nil, err } pageSize := i var buf []byte s := &SwapMemoryStat{} for n := 0; n < c; n++ { buf, err = unix.SysctlRaw("vm.swap_info", n) if err != nil { return nil, err } // first, try to parse with version 2 xsw := (*xswdev)(unsafe.Pointer(&buf[0])) if xsw.Version == XSWDEV_VERSION11 { // this is version 1, so try to parse again xsw := (*xswdev11)(unsafe.Pointer(&buf[0])) if xsw.Version != XSWDEV_VERSION11 { return nil, errors.New("xswdev version mismatch(11)") } s.Total += uint64(xsw.NBlks) s.Used += uint64(xsw.Used) } else if xsw.Version != XSWDEV_VERSION { return nil, errors.New("xswdev version mismatch") } else { s.Total += uint64(xsw.NBlks) s.Used += uint64(xsw.Used) } } if s.Total != 0 { s.UsedPercent = float64(s.Used) / float64(s.Total) * 100 } s.Total *= pageSize s.Used *= pageSize s.Free = s.Total - s.Used return s, nil } gopsutil-3.24.1/mem/mem_linux.go000066400000000000000000000322771455407747200166030ustar00rootroot00000000000000//go:build linux // +build linux package mem import ( "bufio" "context" "encoding/json" "fmt" "io" "math" "os" "strconv" "strings" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/internal/common" ) type VirtualMemoryExStat struct { ActiveFile uint64 `json:"activefile"` InactiveFile uint64 `json:"inactivefile"` ActiveAnon uint64 `json:"activeanon"` InactiveAnon uint64 `json:"inactiveanon"` Unevictable uint64 `json:"unevictable"` } func (v VirtualMemoryExStat) String() string { s, _ := json.Marshal(v) return string(s) } func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { vm, _, err := fillFromMeminfoWithContext(ctx) if err != nil { return nil, err } return vm, nil } func VirtualMemoryEx() (*VirtualMemoryExStat, error) { return VirtualMemoryExWithContext(context.Background()) } func VirtualMemoryExWithContext(ctx context.Context) (*VirtualMemoryExStat, error) { _, vmEx, err := fillFromMeminfoWithContext(ctx) if err != nil { return nil, err } return vmEx, nil } func fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *VirtualMemoryExStat, error) { filename := common.HostProcWithContext(ctx, "meminfo") lines, _ := common.ReadLines(filename) // flag if MemAvailable is in /proc/meminfo (kernel 3.14+) memavail := false activeFile := false // "Active(file)" not available: 2.6.28 / Dec 2008 inactiveFile := false // "Inactive(file)" not available: 2.6.28 / Dec 2008 sReclaimable := false // "Sreclaimable:" not available: 2.6.19 / Nov 2006 ret := &VirtualMemoryStat{} retEx := &VirtualMemoryExStat{} for _, line := range lines { fields := strings.Split(line, ":") if len(fields) != 2 { continue } key := strings.TrimSpace(fields[0]) value := strings.TrimSpace(fields[1]) value = strings.Replace(value, " kB", "", -1) switch key { case "MemTotal": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Total = t * 1024 case "MemFree": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Free = t * 1024 case "MemAvailable": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } memavail = true ret.Available = t * 1024 case "Buffers": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Buffers = t * 1024 case "Cached": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Cached = t * 1024 case "Active": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Active = t * 1024 case "Inactive": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Inactive = t * 1024 case "Active(anon)": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } retEx.ActiveAnon = t * 1024 case "Inactive(anon)": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } retEx.InactiveAnon = t * 1024 case "Active(file)": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } activeFile = true retEx.ActiveFile = t * 1024 case "Inactive(file)": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } inactiveFile = true retEx.InactiveFile = t * 1024 case "Unevictable": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } retEx.Unevictable = t * 1024 case "Writeback": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.WriteBack = t * 1024 case "WritebackTmp": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.WriteBackTmp = t * 1024 case "Dirty": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Dirty = t * 1024 case "Shmem": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Shared = t * 1024 case "Slab": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Slab = t * 1024 case "SReclaimable": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } sReclaimable = true ret.Sreclaimable = t * 1024 case "SUnreclaim": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Sunreclaim = t * 1024 case "PageTables": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.PageTables = t * 1024 case "SwapCached": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.SwapCached = t * 1024 case "CommitLimit": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.CommitLimit = t * 1024 case "Committed_AS": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.CommittedAS = t * 1024 case "HighTotal": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.HighTotal = t * 1024 case "HighFree": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.HighFree = t * 1024 case "LowTotal": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.LowTotal = t * 1024 case "LowFree": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.LowFree = t * 1024 case "SwapTotal": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.SwapTotal = t * 1024 case "SwapFree": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.SwapFree = t * 1024 case "Mapped": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.Mapped = t * 1024 case "VmallocTotal": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.VmallocTotal = t * 1024 case "VmallocUsed": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.VmallocUsed = t * 1024 case "VmallocChunk": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.VmallocChunk = t * 1024 case "HugePages_Total": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.HugePagesTotal = t case "HugePages_Free": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.HugePagesFree = t case "HugePages_Rsvd": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.HugePagesRsvd = t case "HugePages_Surp": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.HugePagesSurp = t case "Hugepagesize": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.HugePageSize = t * 1024 case "AnonHugePages": t, err := strconv.ParseUint(value, 10, 64) if err != nil { return ret, retEx, err } ret.AnonHugePages = t * 1024 } } ret.Cached += ret.Sreclaimable if !memavail { if activeFile && inactiveFile && sReclaimable { ret.Available = calculateAvailVmem(ctx, ret, retEx) } else { ret.Available = ret.Cached + ret.Free } } ret.Used = ret.Total - ret.Free - ret.Buffers - ret.Cached ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0 return ret, retEx, nil } func SwapMemory() (*SwapMemoryStat, error) { return SwapMemoryWithContext(context.Background()) } func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { sysinfo := &unix.Sysinfo_t{} if err := unix.Sysinfo(sysinfo); err != nil { return nil, err } ret := &SwapMemoryStat{ Total: uint64(sysinfo.Totalswap) * uint64(sysinfo.Unit), Free: uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit), } ret.Used = ret.Total - ret.Free // check Infinity if ret.Total != 0 { ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0 } else { ret.UsedPercent = 0 } filename := common.HostProcWithContext(ctx, "vmstat") lines, _ := common.ReadLines(filename) for _, l := range lines { fields := strings.Fields(l) if len(fields) < 2 { continue } switch fields[0] { case "pswpin": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.Sin = value * 4 * 1024 case "pswpout": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.Sout = value * 4 * 1024 case "pgpgin": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.PgIn = value * 4 * 1024 case "pgpgout": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.PgOut = value * 4 * 1024 case "pgfault": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.PgFault = value * 4 * 1024 case "pgmajfault": value, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { continue } ret.PgMajFault = value * 4 * 1024 } } return ret, nil } // calculateAvailVmem is a fallback under kernel 3.14 where /proc/meminfo does not provide // "MemAvailable:" column. It reimplements an algorithm from the link below // https://github.com/giampaolo/psutil/pull/890 func calculateAvailVmem(ctx context.Context, ret *VirtualMemoryStat, retEx *VirtualMemoryExStat) uint64 { var watermarkLow uint64 fn := common.HostProcWithContext(ctx, "zoneinfo") lines, err := common.ReadLines(fn) if err != nil { return ret.Free + ret.Cached // fallback under kernel 2.6.13 } pagesize := uint64(os.Getpagesize()) watermarkLow = 0 for _, line := range lines { fields := strings.Fields(line) if strings.HasPrefix(fields[0], "low") { lowValue, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { lowValue = 0 } watermarkLow += lowValue } } watermarkLow *= pagesize availMemory := ret.Free - watermarkLow pageCache := retEx.ActiveFile + retEx.InactiveFile pageCache -= uint64(math.Min(float64(pageCache/2), float64(watermarkLow))) availMemory += pageCache availMemory += ret.Sreclaimable - uint64(math.Min(float64(ret.Sreclaimable/2.0), float64(watermarkLow))) if availMemory < 0 { availMemory = 0 } return availMemory } const swapsFilename = "swaps" // swaps file column indexes const ( nameCol = 0 // typeCol = 1 totalCol = 2 usedCol = 3 // priorityCol = 4 ) func SwapDevices() ([]*SwapDevice, error) { return SwapDevicesWithContext(context.Background()) } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { swapsFilePath := common.HostProcWithContext(ctx, swapsFilename) f, err := os.Open(swapsFilePath) if err != nil { return nil, err } defer f.Close() return parseSwapsFile(ctx, f) } func parseSwapsFile(ctx context.Context, r io.Reader) ([]*SwapDevice, error) { swapsFilePath := common.HostProcWithContext(ctx, swapsFilename) scanner := bufio.NewScanner(r) if !scanner.Scan() { if err := scanner.Err(); err != nil { return nil, fmt.Errorf("couldn't read file %q: %w", swapsFilePath, err) } return nil, fmt.Errorf("unexpected end-of-file in %q", swapsFilePath) } // Check header headerFields are as expected headerFields := strings.Fields(scanner.Text()) if len(headerFields) < usedCol { return nil, fmt.Errorf("couldn't parse %q: too few fields in header", swapsFilePath) } if headerFields[nameCol] != "Filename" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[nameCol], "Filename") } if headerFields[totalCol] != "Size" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[totalCol], "Size") } if headerFields[usedCol] != "Used" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[usedCol], "Used") } var swapDevices []*SwapDevice for scanner.Scan() { fields := strings.Fields(scanner.Text()) if len(fields) < usedCol { return nil, fmt.Errorf("couldn't parse %q: too few fields", swapsFilePath) } totalKiB, err := strconv.ParseUint(fields[totalCol], 10, 64) if err != nil { return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapsFilePath, err) } usedKiB, err := strconv.ParseUint(fields[usedCol], 10, 64) if err != nil { return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapsFilePath, err) } swapDevices = append(swapDevices, &SwapDevice{ Name: fields[nameCol], UsedBytes: usedKiB * 1024, FreeBytes: (totalKiB - usedKiB) * 1024, }) } if err := scanner.Err(); err != nil { return nil, fmt.Errorf("couldn't read file %q: %w", swapsFilePath, err) } return swapDevices, nil } gopsutil-3.24.1/mem/mem_linux_test.go000066400000000000000000000102511455407747200176260ustar00rootroot00000000000000//go:build linux // +build linux package mem import ( "context" "path/filepath" "reflect" "strings" "testing" "github.com/stretchr/testify/assert" ) func TestVirtualMemoryEx(t *testing.T) { v, err := VirtualMemoryEx() if err != nil { t.Error(err) } t.Log(v) } var virtualMemoryTests = []struct { mockedRootFS string stat *VirtualMemoryStat }{ { "intelcorei5", &VirtualMemoryStat{ Total: 16502300672, Available: 11495358464, Used: 3437277184, UsedPercent: 20.82907863769651, Free: 8783491072, Active: 4347392000, Inactive: 2938834944, Wired: 0, Laundry: 0, Buffers: 212496384, Cached: 4069036032, WriteBack: 0, Dirty: 176128, WriteBackTmp: 0, Shared: 1222402048, Slab: 253771776, Sreclaimable: 186470400, Sunreclaim: 67301376, PageTables: 65241088, SwapCached: 0, CommitLimit: 16509730816, CommittedAS: 12360818688, HighTotal: 0, HighFree: 0, LowTotal: 0, LowFree: 0, SwapTotal: 8258580480, SwapFree: 8258580480, Mapped: 1172627456, VmallocTotal: 35184372087808, VmallocUsed: 0, VmallocChunk: 0, HugePagesTotal: 0, HugePagesFree: 0, HugePagesRsvd: 0, HugePagesSurp: 0, HugePageSize: 2097152, }, }, { "issue1002", &VirtualMemoryStat{ Total: 260579328, Available: 215199744, Used: 34328576, UsedPercent: 13.173944481121694, Free: 124506112, Active: 108785664, Inactive: 8581120, Wired: 0, Laundry: 0, Buffers: 4915200, Cached: 96829440, WriteBack: 0, Dirty: 0, WriteBackTmp: 0, Shared: 0, Slab: 9293824, Sreclaimable: 2764800, Sunreclaim: 6529024, PageTables: 405504, SwapCached: 0, CommitLimit: 130289664, CommittedAS: 25567232, HighTotal: 134217728, HighFree: 67784704, LowTotal: 126361600, LowFree: 56721408, SwapTotal: 0, SwapFree: 0, Mapped: 38793216, VmallocTotal: 1996488704, VmallocUsed: 0, VmallocChunk: 0, HugePagesTotal: 0, HugePagesFree: 0, HugePagesRsvd: 0, HugePagesSurp: 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) { for _, tt := range virtualMemoryTests { t.Run(tt.mockedRootFS, func(t *testing.T) { t.Setenv("HOST_PROC", filepath.Join("testdata/linux/virtualmemory/", tt.mockedRootFS, "proc")) stat, err := VirtualMemory() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if !reflect.DeepEqual(stat, tt.stat) { t.Errorf("got: %+v\nwant: %+v", stat, tt.stat) } }) } } const validFile = `Filename Type Size Used Priority /dev/dm-2 partition 67022844 490788 -2 /swapfile file 2 1 -3 ` const invalidFile = `INVALID Type Size Used Priority /dev/dm-2 partition 67022844 490788 -2 /swapfile file 1048572 0 -3 ` func TestParseSwapsFile_ValidFile(t *testing.T) { assert := assert.New(t) stats, err := parseSwapsFile(context.Background(), strings.NewReader(validFile)) assert.NoError(err) assert.Equal(*stats[0], SwapDevice{ Name: "/dev/dm-2", UsedBytes: 502566912, FreeBytes: 68128825344, }) assert.Equal(*stats[1], SwapDevice{ Name: "/swapfile", UsedBytes: 1024, FreeBytes: 1024, }) } func TestParseSwapsFile_InvalidFile(t *testing.T) { _, err := parseSwapsFile(context.Background(), strings.NewReader(invalidFile)) assert.Error(t, err) } func TestParseSwapsFile_EmptyFile(t *testing.T) { _, err := parseSwapsFile(context.Background(), strings.NewReader("")) assert.Error(t, err) } gopsutil-3.24.1/mem/mem_netbsd.go000066400000000000000000000037521455407747200167170ustar00rootroot00000000000000//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 } gopsutil-3.24.1/mem/mem_openbsd.go000066400000000000000000000045251455407747200170710ustar00rootroot00000000000000//go:build openbsd // +build openbsd package mem import ( "bytes" "context" "encoding/binary" "errors" "fmt" "github.com/shirou/gopsutil/v3/internal/common" "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.uvmexp") 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.uvmexp") 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 mib := []int32{CTLVfs, VfsGeneric, VfsBcacheStat} buf, length, err := common.CallSyscall(mib) if err != nil { return nil, err } if length < sizeOfBcachestats { return nil, fmt.Errorf("short syscall ret %d bytes", length) } var bcs Bcachestats br := bytes.NewReader(buf) err = common.Read(br, binary.LittleEndian, &bcs) if err != nil { return nil, err } ret.Buffers = uint64(bcs.Numbufpages) * p 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 } gopsutil-3.24.1/mem/mem_openbsd_386.go000066400000000000000000000012261455407747200174640ustar00rootroot00000000000000//go:build openbsd && 386 // +build openbsd,386 // 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 } gopsutil-3.24.1/mem/mem_openbsd_amd64.go000066400000000000000000000010271455407747200200560ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_openbsd.go package mem const ( CTLVfs = 10 VfsGeneric = 0 VfsBcacheStat = 3 ) const ( sizeOfBcachestats = 0x78 ) 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 } gopsutil-3.24.1/mem/mem_openbsd_arm.go000066400000000000000000000012261455407747200177230ustar00rootroot00000000000000//go:build openbsd && arm // +build openbsd,arm // 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 } gopsutil-3.24.1/mem/mem_openbsd_arm64.go000066400000000000000000000012321455407747200200720ustar00rootroot00000000000000//go:build openbsd && arm64 // +build openbsd,arm64 // 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 } gopsutil-3.24.1/mem/mem_plan9.go000066400000000000000000000034231455407747200164560ustar00rootroot00000000000000//go:build plan9 // +build plan9 package mem import ( "context" "os" stats "github.com/lufia/plan9stats" "github.com/shirou/gopsutil/v3/internal/common" ) func SwapMemory() (*SwapMemoryStat, error) { return SwapMemoryWithContext(context.Background()) } func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { root := os.Getenv("HOST_ROOT") m, err := stats.ReadMemStats(ctx, stats.WithRootDir(root)) if err != nil { return nil, err } u := 0.0 if m.SwapPages.Avail != 0 { u = float64(m.SwapPages.Used) / float64(m.SwapPages.Avail) * 100.0 } return &SwapMemoryStat{ Total: uint64(m.SwapPages.Avail * m.PageSize), Used: uint64(m.SwapPages.Used * m.PageSize), Free: uint64(m.SwapPages.Free() * m.PageSize), UsedPercent: u, }, nil } func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { root := os.Getenv("HOST_ROOT") m, err := stats.ReadMemStats(ctx, stats.WithRootDir(root)) if err != nil { return nil, err } u := 0.0 if m.UserPages.Avail != 0 { u = float64(m.UserPages.Used) / float64(m.UserPages.Avail) * 100.0 } return &VirtualMemoryStat{ Total: uint64(m.Total), Available: uint64(m.UserPages.Free() * m.PageSize), Used: uint64(m.UserPages.Used * m.PageSize), UsedPercent: u, Free: uint64(m.UserPages.Free() * m.PageSize), SwapTotal: uint64(m.SwapPages.Avail * m.PageSize), SwapFree: uint64(m.SwapPages.Free() * m.PageSize), }, nil } func SwapDevices() ([]*SwapDevice, error) { return SwapDevicesWithContext(context.Background()) } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/mem/mem_plan9_test.go000066400000000000000000000026271455407747200175220ustar00rootroot00000000000000//go:build plan9 // +build plan9 package mem import ( "reflect" "testing" ) var virtualMemoryTests = []struct { mockedRootFS string stat *VirtualMemoryStat }{ { "swap", &VirtualMemoryStat{ Total: 1071185920, Available: 808370176, Used: 11436032, UsedPercent: 1.3949677238843257, Free: 808370176, SwapTotal: 655360000, SwapFree: 655360000, }, }, } func TestVirtualMemoryPlan9(t *testing.T) { for _, tt := range virtualMemoryTests { t.Run(tt.mockedRootFS, func(t *testing.T) { t.Setenv("HOST_ROOT", "testdata/plan9/virtualmemory/") stat, err := VirtualMemory() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if !reflect.DeepEqual(stat, tt.stat) { t.Errorf("got: %+v\nwant: %+v", stat, tt.stat) } }) } } var swapMemoryTests = []struct { mockedRootFS string swap *SwapMemoryStat }{ { "swap", &SwapMemoryStat{ Total: 655360000, Used: 0, Free: 655360000, }, }, } func TestSwapMemoryPlan9(t *testing.T) { for _, tt := range swapMemoryTests { t.Run(tt.mockedRootFS, func(t *testing.T) { t.Setenv("HOST_ROOT", "testdata/plan9/virtualmemory/") swap, err := SwapMemory() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if !reflect.DeepEqual(swap, tt.swap) { t.Errorf("got: %+v\nwant: %+v", swap, tt.swap) } }) } } gopsutil-3.24.1/mem/mem_solaris.go000066400000000000000000000126621455407747200171140ustar00rootroot00000000000000//go:build solaris // +build solaris package mem import ( "context" "errors" "fmt" "regexp" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" "github.com/tklauser/go-sysconf" ) // VirtualMemory for Solaris is a minimal implementation which only returns // what Nomad needs. It does take into account global vs zone, however. func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { result := &VirtualMemoryStat{} zoneName, err := zoneName() if err != nil { return nil, err } if zoneName == "global" { cap, err := globalZoneMemoryCapacity() if err != nil { return nil, err } result.Total = cap freemem, err := globalZoneFreeMemory(ctx) if err != nil { return nil, err } result.Available = freemem result.Free = freemem result.Used = result.Total - result.Free } else { cap, err := nonGlobalZoneMemoryCapacity() if err != nil { return nil, err } result.Total = cap } return result, nil } func SwapMemory() (*SwapMemoryStat, error) { return SwapMemoryWithContext(context.Background()) } func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { return nil, common.ErrNotImplementedError } func zoneName() (string, error) { ctx := context.Background() out, err := invoke.CommandWithContext(ctx, "zonename") if err != nil { return "", err } return strings.TrimSpace(string(out)), nil } var globalZoneMemoryCapacityMatch = regexp.MustCompile(`[Mm]emory size: (\d+) Megabytes`) func globalZoneMemoryCapacity() (uint64, error) { ctx := context.Background() out, err := invoke.CommandWithContext(ctx, "prtconf") if err != nil { return 0, err } match := globalZoneMemoryCapacityMatch.FindAllStringSubmatch(string(out), -1) if len(match) != 1 { return 0, errors.New("memory size not contained in output of prtconf") } totalMB, err := strconv.ParseUint(match[0][1], 10, 64) if err != nil { return 0, err } return totalMB * 1024 * 1024, nil } func globalZoneFreeMemory(ctx context.Context) (uint64, error) { output, err := invoke.CommandWithContext(ctx, "pagesize") if err != nil { return 0, err } pagesize, err := strconv.ParseUint(strings.TrimSpace(string(output)), 10, 64) if err != nil { return 0, err } free, err := sysconf.Sysconf(sysconf.SC_AVPHYS_PAGES) if err != nil { return 0, err } return uint64(free) * pagesize, nil } var kstatMatch = regexp.MustCompile(`(\S+)\s+(\S*)`) func nonGlobalZoneMemoryCapacity() (uint64, error) { ctx := context.Background() out, err := invoke.CommandWithContext(ctx, "kstat", "-p", "-c", "zone_memory_cap", "memory_cap:*:*:physcap") if err != nil { return 0, err } kstats := kstatMatch.FindAllStringSubmatch(string(out), -1) if len(kstats) != 1 { return 0, fmt.Errorf("expected 1 kstat, found %d", len(kstats)) } memSizeBytes, err := strconv.ParseUint(kstats[0][2], 10, 64) if err != nil { return 0, err } return memSizeBytes, nil } const swapCommand = "swap" // The blockSize as reported by `swap -l`. See https://docs.oracle.com/cd/E23824_01/html/821-1459/fsswap-52195.html const blockSize = 512 // swapctl column indexes const ( nameCol = 0 // devCol = 1 // swaploCol = 2 totalBlocksCol = 3 freeBlocksCol = 4 ) func SwapDevices() ([]*SwapDevice, error) { return SwapDevicesWithContext(context.Background()) } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { output, err := invoke.CommandWithContext(ctx, swapCommand, "-l") if err != nil { return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err) } return parseSwapsCommandOutput(string(output)) } func parseSwapsCommandOutput(output string) ([]*SwapDevice, error) { lines := strings.Split(output, "\n") if len(lines) == 0 { return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output) } // Check header headerFields are as expected. headerFields := strings.Fields(lines[0]) if len(headerFields) < freeBlocksCol { return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, lines[0]) } if headerFields[nameCol] != "swapfile" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "swapfile") } if headerFields[totalBlocksCol] != "blocks" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalBlocksCol], "blocks") } if headerFields[freeBlocksCol] != "free" { return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[freeBlocksCol], "free") } var swapDevices []*SwapDevice for _, line := range lines[1:] { if line == "" { continue // the terminal line is typically empty } fields := strings.Fields(line) if len(fields) < freeBlocksCol { return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand) } totalBlocks, err := strconv.ParseUint(fields[totalBlocksCol], 10, 64) if err != nil { return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err) } freeBlocks, err := strconv.ParseUint(fields[freeBlocksCol], 10, 64) if err != nil { return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err) } swapDevices = append(swapDevices, &SwapDevice{ Name: fields[nameCol], UsedBytes: (totalBlocks - freeBlocks) * blockSize, FreeBytes: freeBlocks * blockSize, }) } return swapDevices, nil } gopsutil-3.24.1/mem/mem_solaris_test.go000066400000000000000000000021531455407747200201450ustar00rootroot00000000000000//go:build solaris // +build solaris package mem import ( "testing" "github.com/stretchr/testify/assert" ) const validFile = `swapfile dev swaplo blocks free /dev/zvol/dsk/rpool/swap 256,1 16 1058800 1058800 /dev/dsk/c0t0d0s1 136,1 16 1638608 1600528` const invalidFile = `swapfile dev swaplo INVALID free /dev/zvol/dsk/rpool/swap 256,1 16 1058800 1058800 /dev/dsk/c0t0d0s1 136,1 16 1638608 1600528` func TestParseSwapsCommandOutput_Valid(t *testing.T) { assert := assert.New(t) stats, err := parseSwapsCommandOutput(validFile) assert.NoError(err) assert.Equal(*stats[0], SwapDevice{ Name: "/dev/zvol/dsk/rpool/swap", UsedBytes: 0, FreeBytes: 1058800 * 512, }) assert.Equal(*stats[1], SwapDevice{ Name: "/dev/dsk/c0t0d0s1", UsedBytes: 38080 * 512, FreeBytes: 1600528 * 512, }) } func TestParseSwapsCommandOutput_Invalid(t *testing.T) { _, err := parseSwapsCommandOutput(invalidFile) assert.Error(t, err) } func TestParseSwapsCommandOutput_Empty(t *testing.T) { _, err := parseSwapsCommandOutput("") assert.Error(t, err) } gopsutil-3.24.1/mem/mem_test.go000066400000000000000000000074621455407747200164210ustar00rootroot00000000000000package mem import ( "errors" "fmt" "runtime" "testing" "github.com/stretchr/testify/assert" "github.com/shirou/gopsutil/v3/internal/common" ) func skipIfNotImplementedErr(t *testing.T, err error) { if errors.Is(err, common.ErrNotImplementedError) { t.Skip("not implemented") } } func TestVirtual_memory(t *testing.T) { if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" { t.Skip("Only .Total .Available are supported on Solaris/illumos") } v, err := VirtualMemory() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } empty := &VirtualMemoryStat{} if v == empty { t.Errorf("error %v", v) } t.Log(v) assert.True(t, v.Total > 0) assert.True(t, v.Available > 0) assert.True(t, v.Used > 0) total := v.Used + v.Free + v.Buffers + v.Cached totalStr := "used + free + buffers + cached" switch runtime.GOOS { case "windows": total = v.Used + v.Available totalStr = "used + available" case "darwin", "openbsd": total = v.Used + v.Free + v.Cached + v.Inactive totalStr = "used + free + cached + inactive" case "freebsd": total = v.Used + v.Free + v.Cached + v.Inactive + v.Laundry totalStr = "used + free + cached + inactive + laundry" } assert.Equal(t, v.Total, total, "Total should be computable (%v): %v", totalStr, v) assert.True(t, runtime.GOOS == "windows" || v.Free > 0) assert.True(t, runtime.GOOS == "windows" || v.Available > v.Free, "Free should be a subset of Available: %v", v) inDelta := assert.InDelta if runtime.GOOS == "windows" { inDelta = assert.InEpsilon } inDelta(t, v.UsedPercent, 100*float64(v.Used)/float64(v.Total), 0.1, "UsedPercent should be how many percent of Total is Used: %v", v) } func TestSwap_memory(t *testing.T) { v, err := SwapMemory() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } empty := &SwapMemoryStat{} if v == empty { t.Errorf("error %v", v) } t.Log(v) } func TestVirtualMemoryStat_String(t *testing.T) { v := VirtualMemoryStat{ Total: 10, Available: 20, Used: 30, UsedPercent: 30.1, Free: 40, } 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,"anonHugePages":0}` if e != fmt.Sprintf("%v", v) { t.Errorf("VirtualMemoryStat string is invalid: %v", v) } } func TestSwapMemoryStat_String(t *testing.T) { v := SwapMemoryStat{ Total: 10, Used: 30, Free: 40, UsedPercent: 30.1, Sin: 1, Sout: 2, PgIn: 3, PgOut: 4, PgFault: 5, PgMajFault: 6, } e := `{"total":10,"used":30,"free":40,"usedPercent":30.1,"sin":1,"sout":2,"pgIn":3,"pgOut":4,"pgFault":5,"pgMajFault":6}` if e != fmt.Sprintf("%v", v) { t.Errorf("SwapMemoryStat string is invalid: %v", v) } } func TestSwapDevices(t *testing.T) { v, err := SwapDevices() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("error calling SwapDevices: %v", err) } t.Logf("SwapDevices() -> %+v", v) if len(v) == 0 { t.Fatalf("no swap devices found. [this is expected if the host has swap disabled]") } for _, device := range v { if device.Name == "" { t.Fatalf("deviceName not set in %+v", device) } if device.FreeBytes == 0 { t.Logf("[WARNING] free-bytes is zero in %+v. This might be expected", device) } if device.UsedBytes == 0 { t.Logf("[WARNING] used-bytes is zero in %+v. This might be expected", device) } } } gopsutil-3.24.1/mem/mem_windows.go000066400000000000000000000112711455407747200171250ustar00rootroot00000000000000//go:build windows // +build windows package mem import ( "context" "sync" "syscall" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/windows" ) var ( procEnumPageFilesW = common.ModPsapi.NewProc("EnumPageFilesW") procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo") procGetPerformanceInfo = common.ModPsapi.NewProc("GetPerformanceInfo") procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx") ) type memoryStatusEx struct { cbSize uint32 dwMemoryLoad uint32 ullTotalPhys uint64 // in bytes ullAvailPhys uint64 ullTotalPageFile uint64 ullAvailPageFile uint64 ullTotalVirtual uint64 ullAvailVirtual uint64 ullAvailExtendedVirtual uint64 } func VirtualMemory() (*VirtualMemoryStat, error) { return VirtualMemoryWithContext(context.Background()) } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { var memInfo memoryStatusEx memInfo.cbSize = uint32(unsafe.Sizeof(memInfo)) mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo))) if mem == 0 { return nil, windows.GetLastError() } ret := &VirtualMemoryStat{ Total: memInfo.ullTotalPhys, Available: memInfo.ullAvailPhys, Free: memInfo.ullAvailPhys, UsedPercent: float64(memInfo.dwMemoryLoad), } ret.Used = ret.Total - ret.Available return ret, nil } type performanceInformation struct { cb uint32 commitTotal uint64 commitLimit uint64 commitPeak uint64 physicalTotal uint64 physicalAvailable uint64 systemCache uint64 kernelTotal uint64 kernelPaged uint64 kernelNonpaged uint64 pageSize uint64 handleCount uint32 processCount uint32 threadCount uint32 } func SwapMemory() (*SwapMemoryStat, error) { return SwapMemoryWithContext(context.Background()) } func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { var perfInfo performanceInformation perfInfo.cb = uint32(unsafe.Sizeof(perfInfo)) mem, _, _ := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb)) if mem == 0 { return nil, windows.GetLastError() } tot := perfInfo.commitLimit * perfInfo.pageSize used := perfInfo.commitTotal * perfInfo.pageSize free := tot - used var usedPercent float64 if tot == 0 { usedPercent = 0 } else { usedPercent = float64(used) / float64(tot) * 100 } ret := &SwapMemoryStat{ Total: tot, Used: used, Free: free, UsedPercent: usedPercent, } return ret, nil } var ( pageSize uint64 pageSizeOnce sync.Once ) type systemInfo struct { wProcessorArchitecture uint16 wReserved uint16 dwPageSize uint32 lpMinimumApplicationAddress uintptr lpMaximumApplicationAddress uintptr dwActiveProcessorMask uintptr dwNumberOfProcessors uint32 dwProcessorType uint32 dwAllocationGranularity uint32 wProcessorLevel uint16 wProcessorRevision uint16 } // system type as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-enum_page_file_information type enumPageFileInformation struct { cb uint32 reserved uint32 totalSize uint64 totalInUse uint64 peakUsage uint64 } func SwapDevices() ([]*SwapDevice, error) { return SwapDevicesWithContext(context.Background()) } func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) { pageSizeOnce.Do(func() { var sysInfo systemInfo procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sysInfo))) pageSize = uint64(sysInfo.dwPageSize) }) // the following system call invokes the supplied callback function once for each page file before returning // see https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumpagefilesw var swapDevices []*SwapDevice result, _, _ := procEnumPageFilesW.Call(windows.NewCallback(pEnumPageFileCallbackW), uintptr(unsafe.Pointer(&swapDevices))) if result == 0 { return nil, windows.GetLastError() } return swapDevices, nil } // system callback as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/nc-psapi-penum_page_file_callbackw func pEnumPageFileCallbackW(swapDevices *[]*SwapDevice, enumPageFileInfo *enumPageFileInformation, lpFilenamePtr *[syscall.MAX_LONG_PATH]uint16) *bool { *swapDevices = append(*swapDevices, &SwapDevice{ Name: syscall.UTF16ToString((*lpFilenamePtr)[:]), UsedBytes: enumPageFileInfo.totalInUse * pageSize, FreeBytes: (enumPageFileInfo.totalSize - enumPageFileInfo.totalInUse) * pageSize, }) // return true to continue enumerating page files ret := true return &ret } gopsutil-3.24.1/mem/testdata/000077500000000000000000000000001455407747200160555ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/000077500000000000000000000000001455407747200172145ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/virtualmemory/000077500000000000000000000000001455407747200221335ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/virtualmemory/anonhugepages/000077500000000000000000000000001455407747200247575ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/virtualmemory/anonhugepages/proc/000077500000000000000000000000001455407747200257225ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/virtualmemory/anonhugepages/proc/meminfo000066400000000000000000000001621455407747200272760ustar00rootroot00000000000000MemTotal: 260799420 kB MemFree: 119443248 kB MemAvailable: 127880216 kB AnonHugePages: 50409472 kBgopsutil-3.24.1/mem/testdata/linux/virtualmemory/intelcorei5/000077500000000000000000000000001455407747200243555ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/virtualmemory/intelcorei5/proc/000077500000000000000000000000001455407747200253205ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/virtualmemory/intelcorei5/proc/meminfo000066400000000000000000000023771455407747200267060ustar00rootroot00000000000000MemTotal: 16115528 kB MemFree: 8577628 kB MemAvailable: 11225936 kB Buffers: 207516 kB Cached: 3791568 kB SwapCached: 0 kB Active: 4245500 kB Inactive: 2869956 kB Active(anon): 3123508 kB Inactive(anon): 1186612 kB Active(file): 1121992 kB Inactive(file): 1683344 kB Unevictable: 32 kB Mlocked: 32 kB SwapTotal: 8065020 kB SwapFree: 8065020 kB Dirty: 172 kB Writeback: 0 kB AnonPages: 3116472 kB Mapped: 1145144 kB Shmem: 1193752 kB Slab: 247824 kB SReclaimable: 182100 kB SUnreclaim: 65724 kB KernelStack: 14224 kB PageTables: 63712 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 16122784 kB Committed_AS: 12071112 kB VmallocTotal: 34359738367 kB VmallocUsed: 0 kB VmallocChunk: 0 kB HardwareCorrupted: 0 kB AnonHugePages: 0 kB ShmemHugePages: 0 kB ShmemPmdMapped: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 143564 kB DirectMap2M: 6871040 kB DirectMap1G: 10485760 kB gopsutil-3.24.1/mem/testdata/linux/virtualmemory/issue1002/000077500000000000000000000000001455407747200235665ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/virtualmemory/issue1002/proc/000077500000000000000000000000001455407747200245315ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/linux/virtualmemory/issue1002/proc/meminfo000066400000000000000000000023401455407747200261050ustar00rootroot00000000000000 total: used: free: shared: buffers: cached: Mem: 260579328 136073216 124506112 0 4915200 94064640 Swap: 0 0 0 MemTotal: 254472 kB MemFree: 121588 kB MemShared: 0 kB Buffers: 4800 kB Cached: 91860 kB SwapCached: 0 kB Active: 106236 kB Inactive: 8380 kB MemAvailable: 210156 kB Active(anon): 17956 kB Inactive(anon): 0 kB Active(file): 88280 kB Inactive(file): 8380 kB Unevictable: 0 kB Mlocked: 0 kB HighTotal: 131072 kB HighFree: 66196 kB LowTotal: 123400 kB LowFree: 55392 kB SwapTotal: 0 kB SwapFree: 0 kB Dirty: 0 kB Writeback: 0 kB AnonPages: 17992 kB Mapped: 37884 kB Shmem: 0 kB Slab: 9076 kB SReclaimable: 2700 kB SUnreclaim: 6376 kB KernelStack: 624 kB PageTables: 396 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 127236 kB Committed_AS: 24968 kB VmallocTotal: 1949696 kB VmallocUsed: 0 kB VmallocChunk: 0 kB gopsutil-3.24.1/mem/testdata/plan9/000077500000000000000000000000001455407747200171005ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/plan9/virtualmemory/000077500000000000000000000000001455407747200220175ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/plan9/virtualmemory/dev/000077500000000000000000000000001455407747200225755ustar00rootroot00000000000000gopsutil-3.24.1/mem/testdata/plan9/virtualmemory/dev/swap000066400000000000000000000002031455407747200234650ustar00rootroot000000000000001071185920 memory 4096 pagesize 61372 kernel 2792/200148 user 0/160000 swap 9046176/219352384 kernel malloc 0/16777216 kernel draw gopsutil-3.24.1/mem/types_openbsd.go000066400000000000000000000005741455407747200174570ustar00rootroot00000000000000//go:build ignore // +build ignore /* Input to cgo -godefs. */ package mem /* #include #include #include */ import "C" // Machine characteristics; for internal use. const ( CTLVfs = 10 VfsGeneric = 0 VfsBcacheStat = 3 ) const ( sizeOfBcachestats = C.sizeof_struct_bcachestats ) type Bcachestats C.struct_bcachestats gopsutil-3.24.1/mktypes.sh000066400000000000000000000010131455407747200155110ustar00rootroot00000000000000#!/bin/sh PKGS="cpu disk docker host load mem net process" GOOS=$(go env GOOS) GOARCH=$(go env GOARCH) GOARCH=$(go env GOARCH) for DIR in . v3 do (cd "$DIR" || exit for PKG in $PKGS do if [ -e "${PKG}/types_${GOOS}.go" ]; then (echo "// +build $GOOS" echo "// +build $GOARCH" go tool cgo -godefs "${PKG}/types_${GOOS}.go") | gofmt > "${PKG}/${PKG}_${GOOS}_${GOARCH}.go" fi done) done gopsutil-3.24.1/net/000077500000000000000000000000001455407747200142545ustar00rootroot00000000000000gopsutil-3.24.1/net/net.go000066400000000000000000000204271455407747200153760ustar00rootroot00000000000000package net import ( "context" "encoding/json" "net" "github.com/shirou/gopsutil/v3/internal/common" ) var invoke common.Invoker = common.Invoke{} type IOCountersStat struct { Name string `json:"name"` // interface name BytesSent uint64 `json:"bytesSent"` // number of bytes sent BytesRecv uint64 `json:"bytesRecv"` // number of bytes received PacketsSent uint64 `json:"packetsSent"` // number of packets sent PacketsRecv uint64 `json:"packetsRecv"` // number of packets received Errin uint64 `json:"errin"` // total number of errors while receiving Errout uint64 `json:"errout"` // total number of errors while sending Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD) Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending } // Addr is implemented compatibility to psutil type Addr struct { IP string `json:"ip"` Port uint32 `json:"port"` } type ConnectionStat struct { Fd uint32 `json:"fd"` Family uint32 `json:"family"` Type uint32 `json:"type"` Laddr Addr `json:"localaddr"` Raddr Addr `json:"remoteaddr"` Status string `json:"status"` Uids []int32 `json:"uids"` Pid int32 `json:"pid"` } // System wide stats about different network protocols type ProtoCountersStat struct { Protocol string `json:"protocol"` Stats map[string]int64 `json:"stats"` } // NetInterfaceAddr is designed for represent interface addresses type InterfaceAddr struct { Addr string `json:"addr"` } // InterfaceAddrList is a list of InterfaceAddr type InterfaceAddrList []InterfaceAddr type InterfaceStat struct { Index int `json:"index"` MTU int `json:"mtu"` // maximum transmission unit Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100" HardwareAddr string `json:"hardwareAddr"` // IEEE MAC-48, EUI-48 and EUI-64 form Flags []string `json:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast Addrs InterfaceAddrList `json:"addrs"` } // InterfaceStatList is a list of InterfaceStat type InterfaceStatList []InterfaceStat type FilterStat struct { ConnTrackCount int64 `json:"connTrackCount"` ConnTrackMax int64 `json:"connTrackMax"` } // ConntrackStat has conntrack summary info type ConntrackStat struct { Entries uint32 `json:"entries"` // Number of entries in the conntrack table Searched uint32 `json:"searched"` // Number of conntrack table lookups performed Found uint32 `json:"found"` // Number of searched entries which were successful New uint32 `json:"new"` // Number of entries added which were not expected before Invalid uint32 `json:"invalid"` // Number of packets seen which can not be tracked Ignore uint32 `json:"ignore"` // Packets seen which are already connected to an entry Delete uint32 `json:"delete"` // Number of entries which were removed DeleteList uint32 `json:"deleteList"` // Number of entries which were put to dying list Insert uint32 `json:"insert"` // Number of entries inserted into the list InsertFailed uint32 `json:"insertFailed"` // # insertion attempted but failed (same entry exists) Drop uint32 `json:"drop"` // Number of packets dropped due to conntrack failure. EarlyDrop uint32 `json:"earlyDrop"` // Dropped entries to make room for new ones, if maxsize reached IcmpError uint32 `json:"icmpError"` // Subset of invalid. Packets that can't be tracked d/t error ExpectNew uint32 `json:"expectNew"` // Entries added after an expectation was already present ExpectCreate uint32 `json:"expectCreate"` // Expectations added ExpectDelete uint32 `json:"expectDelete"` // Expectations deleted SearchRestart uint32 `json:"searchRestart"` // Conntrack table lookups restarted due to hashtable resizes } func NewConntrackStat(e uint32, s uint32, f uint32, n uint32, inv uint32, ign uint32, del uint32, dlst uint32, ins uint32, insfail uint32, drop uint32, edrop uint32, ie uint32, en uint32, ec uint32, ed uint32, sr uint32) *ConntrackStat { return &ConntrackStat{ Entries: e, Searched: s, Found: f, New: n, Invalid: inv, Ignore: ign, Delete: del, DeleteList: dlst, Insert: ins, InsertFailed: insfail, Drop: drop, EarlyDrop: edrop, IcmpError: ie, ExpectNew: en, ExpectCreate: ec, ExpectDelete: ed, SearchRestart: sr, } } type ConntrackStatList struct { items []*ConntrackStat } func NewConntrackStatList() *ConntrackStatList { return &ConntrackStatList{ items: []*ConntrackStat{}, } } func (l *ConntrackStatList) Append(c *ConntrackStat) { l.items = append(l.items, c) } func (l *ConntrackStatList) Items() []ConntrackStat { items := make([]ConntrackStat, len(l.items)) for i, el := range l.items { items[i] = *el } return items } // Summary returns a single-element list with totals from all list items. func (l *ConntrackStatList) Summary() []ConntrackStat { summary := NewConntrackStat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) for _, cs := range l.items { summary.Entries += cs.Entries summary.Searched += cs.Searched summary.Found += cs.Found summary.New += cs.New summary.Invalid += cs.Invalid summary.Ignore += cs.Ignore summary.Delete += cs.Delete summary.DeleteList += cs.DeleteList summary.Insert += cs.Insert summary.InsertFailed += cs.InsertFailed summary.Drop += cs.Drop summary.EarlyDrop += cs.EarlyDrop summary.IcmpError += cs.IcmpError summary.ExpectNew += cs.ExpectNew summary.ExpectCreate += cs.ExpectCreate summary.ExpectDelete += cs.ExpectDelete summary.SearchRestart += cs.SearchRestart } return []ConntrackStat{*summary} } func (n IOCountersStat) String() string { s, _ := json.Marshal(n) return string(s) } func (n ConnectionStat) String() string { s, _ := json.Marshal(n) return string(s) } func (n ProtoCountersStat) String() string { s, _ := json.Marshal(n) return string(s) } func (a Addr) String() string { s, _ := json.Marshal(a) return string(s) } func (n InterfaceStat) String() string { s, _ := json.Marshal(n) return string(s) } func (l InterfaceStatList) String() string { s, _ := json.Marshal(l) return string(s) } func (n InterfaceAddr) String() string { s, _ := json.Marshal(n) return string(s) } func (n ConntrackStat) String() string { s, _ := json.Marshal(n) return string(s) } func Interfaces() (InterfaceStatList, error) { return InterfacesWithContext(context.Background()) } func InterfacesWithContext(ctx context.Context) (InterfaceStatList, error) { is, err := net.Interfaces() if err != nil { return nil, err } ret := make(InterfaceStatList, 0, len(is)) for _, ifi := range is { var flags []string if ifi.Flags&net.FlagUp != 0 { flags = append(flags, "up") } if ifi.Flags&net.FlagBroadcast != 0 { flags = append(flags, "broadcast") } if ifi.Flags&net.FlagLoopback != 0 { flags = append(flags, "loopback") } if ifi.Flags&net.FlagPointToPoint != 0 { flags = append(flags, "pointtopoint") } if ifi.Flags&net.FlagMulticast != 0 { flags = append(flags, "multicast") } r := InterfaceStat{ Index: ifi.Index, Name: ifi.Name, MTU: ifi.MTU, HardwareAddr: ifi.HardwareAddr.String(), Flags: flags, } addrs, err := ifi.Addrs() if err == nil { r.Addrs = make(InterfaceAddrList, 0, len(addrs)) for _, addr := range addrs { r.Addrs = append(r.Addrs, InterfaceAddr{ Addr: addr.String(), }) } } ret = append(ret, r) } return ret, nil } func getIOCountersAll(n []IOCountersStat) ([]IOCountersStat, error) { r := IOCountersStat{ Name: "all", } for _, nic := range n { r.BytesRecv += nic.BytesRecv r.PacketsRecv += nic.PacketsRecv r.Errin += nic.Errin r.Dropin += nic.Dropin r.BytesSent += nic.BytesSent r.PacketsSent += nic.PacketsSent r.Errout += nic.Errout r.Dropout += nic.Dropout } return []IOCountersStat{r}, nil } gopsutil-3.24.1/net/net_aix.go000066400000000000000000000210651455407747200162360ustar00rootroot00000000000000//go:build aix // +build aix package net import ( "context" "fmt" "regexp" "strconv" "strings" "syscall" "github.com/shirou/gopsutil/v3/internal/common" ) func IOCounters(pernic bool) ([]IOCountersStat, error) { return IOCountersWithContext(context.Background(), pernic) } // IOCountersByFile exists just for compatibility with Linux. func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { return IOCountersByFileWithContext(context.Background(), pernic, filename) } func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) { return IOCounters(pernic) } func FilterCounters() ([]FilterStat, error) { return FilterCountersWithContext(context.Background()) } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { return nil, common.ErrNotImplementedError } func ConntrackStats(percpu bool) ([]ConntrackStat, error) { return ConntrackStatsWithContext(context.Background(), percpu) } func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { return nil, common.ErrNotImplementedError } func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { return ProtoCountersWithContext(context.Background(), protocols) } func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { return nil, common.ErrNotImplementedError } func parseNetstatNetLine(line string) (ConnectionStat, error) { f := strings.Fields(line) if len(f) < 5 { return ConnectionStat{}, fmt.Errorf("wrong line,%s", line) } var netType, netFamily uint32 switch f[0] { case "tcp", "tcp4": netType = syscall.SOCK_STREAM netFamily = syscall.AF_INET case "udp", "udp4": netType = syscall.SOCK_DGRAM netFamily = syscall.AF_INET case "tcp6": netType = syscall.SOCK_STREAM netFamily = syscall.AF_INET6 case "udp6": netType = syscall.SOCK_DGRAM netFamily = syscall.AF_INET6 default: return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0]) } laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily) if err != nil { return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4]) } n := ConnectionStat{ Fd: uint32(0), // not supported Family: uint32(netFamily), Type: uint32(netType), Laddr: laddr, Raddr: raddr, Pid: int32(0), // not supported } if len(f) == 6 { n.Status = f[5] } return n, nil } var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`) // This function only works for netstat returning addresses with a "." // before the port (0.0.0.0.22 instead of 0.0.0.0:22). func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) { parse := func(l string) (Addr, error) { matches := portMatch.FindStringSubmatch(l) if matches == nil { return Addr{}, fmt.Errorf("wrong addr, %s", l) } host := matches[1] port := matches[2] if host == "*" { switch family { case syscall.AF_INET: host = "0.0.0.0" case syscall.AF_INET6: host = "::" default: return Addr{}, fmt.Errorf("unknown family, %d", family) } } lport, err := strconv.Atoi(port) if err != nil { return Addr{}, err } return Addr{IP: host, Port: uint32(lport)}, nil } laddr, err = parse(local) if remote != "*.*" { // remote addr exists raddr, err = parse(remote) if err != nil { return laddr, raddr, err } } return laddr, raddr, err } func parseNetstatUnixLine(f []string) (ConnectionStat, error) { if len(f) < 8 { return ConnectionStat{}, fmt.Errorf("wrong number of fields: expected >=8 got %d", len(f)) } var netType uint32 switch f[1] { case "dgram": netType = syscall.SOCK_DGRAM case "stream": netType = syscall.SOCK_STREAM default: return ConnectionStat{}, fmt.Errorf("unknown type: %s", f[1]) } // Some Unix Socket don't have any address associated addr := "" if len(f) == 9 { addr = f[8] } c := ConnectionStat{ Fd: uint32(0), // not supported Family: uint32(syscall.AF_UNIX), Type: uint32(netType), Laddr: Addr{ IP: addr, }, Status: "NONE", Pid: int32(0), // not supported } return c, nil } // Return true if proto is the corresponding to the kind parameter // Only for Inet lines func hasCorrectInetProto(kind, proto string) bool { switch kind { case "all", "inet": return true case "unix": return false case "inet4": return !strings.HasSuffix(proto, "6") case "inet6": return strings.HasSuffix(proto, "6") case "tcp": return proto == "tcp" || proto == "tcp4" || proto == "tcp6" case "tcp4": return proto == "tcp" || proto == "tcp4" case "tcp6": return proto == "tcp6" case "udp": return proto == "udp" || proto == "udp4" || proto == "udp6" case "udp4": return proto == "udp" || proto == "udp4" case "udp6": return proto == "udp6" } return false } func parseNetstatA(output string, kind string) ([]ConnectionStat, error) { var ret []ConnectionStat lines := strings.Split(string(output), "\n") for _, line := range lines { fields := strings.Fields(line) if len(fields) < 1 { continue } if strings.HasPrefix(fields[0], "f1") { // Unix lines if len(fields) < 2 { // every unix connections have two lines continue } c, err := parseNetstatUnixLine(fields) if err != nil { return nil, fmt.Errorf("failed to parse Unix Address (%s): %s", line, err) } ret = append(ret, c) } else if strings.HasPrefix(fields[0], "tcp") || strings.HasPrefix(fields[0], "udp") { // Inet lines if !hasCorrectInetProto(kind, fields[0]) { continue } // On AIX, netstat display some connections with "*.*" as local addresses // Skip them as they aren't real connections. if fields[3] == "*.*" { continue } c, err := parseNetstatNetLine(line) if err != nil { return nil, fmt.Errorf("failed to parse Inet Address (%s): %s", line, err) } ret = append(ret, c) } else { // Header lines continue } } return ret, nil } func Connections(kind string) ([]ConnectionStat, error) { return ConnectionsWithContext(context.Background(), kind) } func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { args := []string{"-na"} switch strings.ToLower(kind) { default: fallthrough case "": kind = "all" case "all": // nothing to add case "inet", "inet4", "inet6": args = append(args, "-finet") case "tcp", "tcp4", "tcp6": args = append(args, "-finet") case "udp", "udp4", "udp6": args = append(args, "-finet") case "unix": args = append(args, "-funix") } out, err := invoke.CommandWithContext(ctx, "netstat", args...) if err != nil { return nil, err } ret, err := parseNetstatA(string(out), kind) if err != nil { return nil, err } return ret, nil } func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) { return ConnectionsMaxWithContext(context.Background(), kind, max) } func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } // Return a list of network connections opened, omitting `Uids`. // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be // removed from the API in the future. func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) { return ConnectionsWithoutUidsWithContext(context.Background(), kind) } func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0) } func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max) } func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid) } func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0) } func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max) } func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max) } func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } gopsutil-3.24.1/net/net_aix_cgo.go000066400000000000000000000014621455407747200170650ustar00rootroot00000000000000//go:build aix && cgo // +build aix,cgo package net import ( "context" "github.com/power-devops/perfstat" ) func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { ifs, err := perfstat.NetIfaceStat() if err != nil { return nil, err } iocounters := make([]IOCountersStat, 0, len(ifs)) for _, netif := range ifs { n := IOCountersStat{ Name: netif.Name, BytesSent: uint64(netif.OBytes), BytesRecv: uint64(netif.IBytes), PacketsSent: uint64(netif.OPackets), PacketsRecv: uint64(netif.IPackets), Errin: uint64(netif.OErrors), Errout: uint64(netif.IErrors), Dropout: uint64(netif.XmitDrops), } iocounters = append(iocounters, n) } if pernic == false { return getIOCountersAll(iocounters) } return iocounters, nil } gopsutil-3.24.1/net/net_aix_nocgo.go000066400000000000000000000036611455407747200174250ustar00rootroot00000000000000//go:build aix && !cgo // +build aix,!cgo package net import ( "context" "fmt" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" ) func parseNetstatI(output string) ([]IOCountersStat, error) { lines := strings.Split(string(output), "\n") ret := make([]IOCountersStat, 0, len(lines)-1) exists := make([]string, 0, len(ret)) // Check first line is header if len(lines) > 0 && strings.Fields(lines[0])[0] != "Name" { return nil, fmt.Errorf("not a 'netstat -i' output") } for _, line := range lines[1:] { values := strings.Fields(line) if len(values) < 1 || values[0] == "Name" { continue } if common.StringsHas(exists, values[0]) { // skip if already get continue } exists = append(exists, values[0]) if len(values) < 9 { continue } base := 1 // sometimes Address is omitted if len(values) < 10 { base = 0 } parsed := make([]uint64, 0, 5) vv := []string{ values[base+3], // Ipkts == PacketsRecv values[base+4], // Ierrs == Errin values[base+5], // Opkts == PacketsSent values[base+6], // Oerrs == Errout values[base+8], // Drops == Dropout } for _, target := range vv { if target == "-" { parsed = append(parsed, 0) continue } t, err := strconv.ParseUint(target, 10, 64) if err != nil { return nil, err } parsed = append(parsed, t) } n := IOCountersStat{ Name: values[0], PacketsRecv: parsed[0], Errin: parsed[1], PacketsSent: parsed[2], Errout: parsed[3], Dropout: parsed[4], } ret = append(ret, n) } return ret, nil } func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { out, err := invoke.CommandWithContext(ctx, "netstat", "-idn") if err != nil { return nil, err } iocounters, err := parseNetstatI(string(out)) if err != nil { return nil, err } if pernic == false { return getIOCountersAll(iocounters) } return iocounters, nil } gopsutil-3.24.1/net/net_darwin.go000066400000000000000000000172721455407747200167460ustar00rootroot00000000000000//go:build darwin // +build darwin package net import ( "context" "errors" "fmt" "os/exec" "regexp" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" ) var ( errNetstatHeader = errors.New("Can't parse header of netstat output") netstatLinkRegexp = regexp.MustCompile(`^$`) ) const endOfLine = "\n" func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err error) { var ( numericValue uint64 columns = strings.Fields(line) ) if columns[0] == "Name" { err = errNetstatHeader return } // try to extract the numeric value from if subMatch := netstatLinkRegexp.FindStringSubmatch(columns[2]); len(subMatch) == 2 { numericValue, err = strconv.ParseUint(subMatch[1], 10, 64) if err != nil { return } linkIDUint := uint(numericValue) linkID = &linkIDUint } base := 1 numberColumns := len(columns) // sometimes Address is omitted if numberColumns < 12 { base = 0 } if numberColumns < 11 || numberColumns > 13 { err = fmt.Errorf("Line %q do have an invalid number of columns %d", line, numberColumns) return } parsed := make([]uint64, 0, 7) vv := []string{ columns[base+3], // Ipkts == PacketsRecv columns[base+4], // Ierrs == Errin columns[base+5], // Ibytes == BytesRecv columns[base+6], // Opkts == PacketsSent columns[base+7], // Oerrs == Errout columns[base+8], // Obytes == BytesSent } if len(columns) == 12 { vv = append(vv, columns[base+10]) } for _, target := range vv { if target == "-" { parsed = append(parsed, 0) continue } if numericValue, err = strconv.ParseUint(target, 10, 64); err != nil { return } parsed = append(parsed, numericValue) } stat = &IOCountersStat{ Name: strings.Trim(columns[0], "*"), // remove the * that sometimes is on right on interface PacketsRecv: parsed[0], Errin: parsed[1], BytesRecv: parsed[2], PacketsSent: parsed[3], Errout: parsed[4], BytesSent: parsed[5], } if len(parsed) == 7 { stat.Dropout = parsed[6] } return } type netstatInterface struct { linkID *uint stat *IOCountersStat } func parseNetstatOutput(output string) ([]netstatInterface, error) { var ( err error lines = strings.Split(strings.Trim(output, endOfLine), endOfLine) ) // number of interfaces is number of lines less one for the header numberInterfaces := len(lines) - 1 interfaces := make([]netstatInterface, numberInterfaces) // no output beside header if numberInterfaces == 0 { return interfaces, nil } for index := 0; index < numberInterfaces; index++ { nsIface := netstatInterface{} if nsIface.stat, nsIface.linkID, err = parseNetstatLine(lines[index+1]); err != nil { return nil, err } interfaces[index] = nsIface } return interfaces, nil } // map that hold the name of a network interface and the number of usage type mapInterfaceNameUsage map[string]uint func newMapInterfaceNameUsage(ifaces []netstatInterface) mapInterfaceNameUsage { output := make(mapInterfaceNameUsage) for index := range ifaces { if ifaces[index].linkID != nil { ifaceName := ifaces[index].stat.Name usage, ok := output[ifaceName] if ok { output[ifaceName] = usage + 1 } else { output[ifaceName] = 1 } } } return output } func (min mapInterfaceNameUsage) isTruncated() bool { for _, usage := range min { if usage > 1 { return true } } return false } func (min mapInterfaceNameUsage) notTruncated() []string { output := make([]string, 0) for ifaceName, usage := range min { if usage == 1 { output = append(output, ifaceName) } } return output } // example of `netstat -ibdnW` output on yosemite // Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop // lo0 16384 869107 0 169411755 869107 0 169411755 0 0 // lo0 16384 ::1/128 ::1 869107 - 169411755 869107 - 169411755 - - // lo0 16384 127 127.0.0.1 869107 - 169411755 869107 - 169411755 - - func IOCounters(pernic bool) ([]IOCountersStat, error) { return IOCountersWithContext(context.Background(), pernic) } func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { var ( ret []IOCountersStat retIndex int ) netstat, err := exec.LookPath("netstat") if err != nil { return nil, err } // try to get all interface metrics, and hope there won't be any truncated out, err := invoke.CommandWithContext(ctx, netstat, "-ibdnW") if err != nil { return nil, err } nsInterfaces, err := parseNetstatOutput(string(out)) if err != nil { return nil, err } ifaceUsage := newMapInterfaceNameUsage(nsInterfaces) notTruncated := ifaceUsage.notTruncated() ret = make([]IOCountersStat, len(notTruncated)) if !ifaceUsage.isTruncated() { // no truncated interface name, return stats of all interface with for index := range nsInterfaces { if nsInterfaces[index].linkID != nil { ret[retIndex] = *nsInterfaces[index].stat retIndex++ } } } else { // duplicated interface, list all interfaces if out, err = invoke.CommandWithContext(ctx, "ifconfig", "-l"); err != nil { return nil, err } interfaceNames := strings.Fields(strings.TrimRight(string(out), endOfLine)) // for each of the interface name, run netstat if we don't have any stats yet for _, interfaceName := range interfaceNames { truncated := true for index := range nsInterfaces { if nsInterfaces[index].linkID != nil && nsInterfaces[index].stat.Name == interfaceName { // handle the non truncated name to avoid execute netstat for them again ret[retIndex] = *nsInterfaces[index].stat retIndex++ truncated = false break } } if truncated { // run netstat with -I$ifacename if out, err = invoke.CommandWithContext(ctx, netstat, "-ibdnWI"+interfaceName); err != nil { return nil, err } parsedIfaces, err := parseNetstatOutput(string(out)) if err != nil { return nil, err } if len(parsedIfaces) == 0 { // interface had been removed since `ifconfig -l` had been executed continue } for index := range parsedIfaces { if parsedIfaces[index].linkID != nil { ret = append(ret, *parsedIfaces[index].stat) break } } } } } if pernic == false { return getIOCountersAll(ret) } return ret, nil } // IOCountersByFile exists just for compatibility with Linux. func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { return IOCountersByFileWithContext(context.Background(), pernic, filename) } func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) { return IOCountersWithContext(ctx, pernic) } func FilterCounters() ([]FilterStat, error) { return FilterCountersWithContext(context.Background()) } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { return nil, common.ErrNotImplementedError } func ConntrackStats(percpu bool) ([]ConntrackStat, error) { return ConntrackStatsWithContext(context.Background(), percpu) } func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { return nil, common.ErrNotImplementedError } // ProtoCounters returns network statistics for the entire system // If protocols is empty then all protocols are returned, otherwise // just the protocols in the list are returned. // Not Implemented for Darwin func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { return ProtoCountersWithContext(context.Background(), protocols) } func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/net/net_darwin_test.go000066400000000000000000000136051455407747200200010ustar00rootroot00000000000000package net import ( "testing" assert "github.com/stretchr/testify/require" ) const ( netstatTruncated = `Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop lo0 16384 31241 0 3769823 31241 0 3769823 0 0 lo0 16384 ::1/128 ::1 31241 - 3769823 31241 - 3769823 - - lo0 16384 127 127.0.0.1 31241 - 3769823 31241 - 3769823 - - lo0 16384 fe80::1%lo0 fe80:1::1 31241 - 3769823 31241 - 3769823 - - gif0* 1280 0 0 0 0 0 0 0 0 stf0* 1280 0 0 0 0 0 0 0 0 utun8 1500 286 0 27175 0 0 0 0 0 utun8 1500 286 0 29554 0 0 0 0 0 utun8 1500 286 0 29244 0 0 0 0 0 utun8 1500 286 0 28267 0 0 0 0 0 utun8 1500 286 0 28593 0 0 0 0 0` netstatNotTruncated = `Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop lo0 16384 27190978 0 12824763793 27190978 0 12824763793 0 0 lo0 16384 ::1/128 ::1 27190978 - 12824763793 27190978 - 12824763793 - - lo0 16384 127 127.0.0.1 27190978 - 12824763793 27190978 - 12824763793 - - lo0 16384 fe80::1%lo0 fe80:1::1 27190978 - 12824763793 27190978 - 12824763793 - - gif0* 1280 0 0 0 0 0 0 0 0 stf0* 1280 0 0 0 0 0 0 0 0 en0 1500 a8:66:7f:dd:ee:ff 5708989 0 7295722068 3494252 0 379533492 0 230 en0 1500 fe80::aa66: fe80:4::aa66:7fff 5708989 - 7295722068 3494252 - 379533492 - -` ) func TestParseNetstatLineHeader(t *testing.T) { stat, linkIkd, err := parseNetstatLine(`Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop`) assert.Nil(t, linkIkd) assert.Nil(t, stat) assert.Error(t, err) assert.Equal(t, errNetstatHeader, err) } func assertLoopbackStat(t *testing.T, err error, stat *IOCountersStat) { assert.NoError(t, err) assert.Equal(t, uint64(869107), stat.PacketsRecv) assert.Equal(t, uint64(0), stat.Errin) assert.Equal(t, uint64(169411755), stat.BytesRecv) assert.Equal(t, uint64(869108), stat.PacketsSent) assert.Equal(t, uint64(1), stat.Errout) assert.Equal(t, uint64(169411756), stat.BytesSent) } func TestParseNetstatLineLink(t *testing.T) { stat, linkID, err := parseNetstatLine( `lo0 16384 869107 0 169411755 869108 1 169411756 0 0`, ) assertLoopbackStat(t, err, stat) assert.NotNil(t, linkID) assert.Equal(t, uint(1), *linkID) } func TestParseNetstatLineIPv6(t *testing.T) { stat, linkID, err := parseNetstatLine( `lo0 16384 ::1/128 ::1 869107 - 169411755 869108 1 169411756 - -`, ) assertLoopbackStat(t, err, stat) assert.Nil(t, linkID) } func TestParseNetstatLineIPv4(t *testing.T) { stat, linkID, err := parseNetstatLine( `lo0 16384 127 127.0.0.1 869107 - 169411755 869108 1 169411756 - -`, ) assertLoopbackStat(t, err, stat) assert.Nil(t, linkID) } func TestParseNetstatOutput(t *testing.T) { nsInterfaces, err := parseNetstatOutput(netstatNotTruncated) assert.NoError(t, err) assert.Len(t, nsInterfaces, 8) for index := range nsInterfaces { assert.NotNil(t, nsInterfaces[index].stat, "Index %d", index) } assert.NotNil(t, nsInterfaces[0].linkID) assert.Equal(t, uint(1), *nsInterfaces[0].linkID) assert.Nil(t, nsInterfaces[1].linkID) assert.Nil(t, nsInterfaces[2].linkID) assert.Nil(t, nsInterfaces[3].linkID) assert.NotNil(t, nsInterfaces[4].linkID) assert.Equal(t, uint(2), *nsInterfaces[4].linkID) assert.NotNil(t, nsInterfaces[5].linkID) assert.Equal(t, uint(3), *nsInterfaces[5].linkID) assert.NotNil(t, nsInterfaces[6].linkID) assert.Equal(t, uint(4), *nsInterfaces[6].linkID) assert.Nil(t, nsInterfaces[7].linkID) mapUsage := newMapInterfaceNameUsage(nsInterfaces) assert.False(t, mapUsage.isTruncated()) assert.Len(t, mapUsage.notTruncated(), 4) } func TestParseNetstatTruncated(t *testing.T) { nsInterfaces, err := parseNetstatOutput(netstatTruncated) assert.NoError(t, err) assert.Len(t, nsInterfaces, 11) for index := range nsInterfaces { assert.NotNil(t, nsInterfaces[index].stat, "Index %d", index) } const truncatedIface = "utun8" assert.NotNil(t, nsInterfaces[6].linkID) assert.Equal(t, uint(88), *nsInterfaces[6].linkID) assert.Equal(t, truncatedIface, nsInterfaces[6].stat.Name) assert.NotNil(t, nsInterfaces[7].linkID) assert.Equal(t, uint(90), *nsInterfaces[7].linkID) assert.Equal(t, truncatedIface, nsInterfaces[7].stat.Name) assert.NotNil(t, nsInterfaces[8].linkID) assert.Equal(t, uint(92), *nsInterfaces[8].linkID) assert.Equal(t, truncatedIface, nsInterfaces[8].stat.Name) assert.NotNil(t, nsInterfaces[9].linkID) assert.Equal(t, uint(93), *nsInterfaces[9].linkID) assert.Equal(t, truncatedIface, nsInterfaces[9].stat.Name) assert.NotNil(t, nsInterfaces[10].linkID) assert.Equal(t, uint(95), *nsInterfaces[10].linkID) assert.Equal(t, truncatedIface, nsInterfaces[10].stat.Name) mapUsage := newMapInterfaceNameUsage(nsInterfaces) assert.True(t, mapUsage.isTruncated()) assert.Equal(t, 3, len(mapUsage.notTruncated()), "en0, gif0 and stf0") } gopsutil-3.24.1/net/net_fallback.go000066400000000000000000000067021455407747200172150ustar00rootroot00000000000000//go:build !aix && !darwin && !linux && !freebsd && !openbsd && !windows && !solaris // +build !aix,!darwin,!linux,!freebsd,!openbsd,!windows,!solaris package net import ( "context" "github.com/shirou/gopsutil/v3/internal/common" ) func IOCounters(pernic bool) ([]IOCountersStat, error) { return IOCountersWithContext(context.Background(), pernic) } func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { return []IOCountersStat{}, common.ErrNotImplementedError } func FilterCounters() ([]FilterStat, error) { return FilterCountersWithContext(context.Background()) } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { return []FilterStat{}, common.ErrNotImplementedError } func ConntrackStats(percpu bool) ([]ConntrackStat, error) { return ConntrackStatsWithContext(context.Background(), percpu) } func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { return nil, common.ErrNotImplementedError } func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { return ProtoCountersWithContext(context.Background(), protocols) } func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { return []ProtoCountersStat{}, common.ErrNotImplementedError } func Connections(kind string) ([]ConnectionStat, error) { return ConnectionsWithContext(context.Background(), kind) } func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) { return ConnectionsMaxWithContext(context.Background(), kind, max) } func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } // Return a list of network connections opened, omitting `Uids`. // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be // removed from the API in the future. func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) { return ConnectionsWithoutUidsWithContext(context.Background(), kind) } func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0) } func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max) } func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid) } func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0) } func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max) } func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max) } func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } gopsutil-3.24.1/net/net_freebsd.go000066400000000000000000000062411455407747200170660ustar00rootroot00000000000000//go:build freebsd // +build freebsd package net import ( "context" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" ) func IOCounters(pernic bool) ([]IOCountersStat, error) { return IOCountersWithContext(context.Background(), pernic) } func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { out, err := invoke.CommandWithContext(ctx, "netstat", "-ibdnW") if err != nil { return nil, err } lines := strings.Split(string(out), "\n") ret := make([]IOCountersStat, 0, len(lines)-1) exists := make([]string, 0, len(ret)) for _, line := range lines { values := strings.Fields(line) if len(values) < 1 || values[0] == "Name" { continue } if common.StringsHas(exists, values[0]) { // skip if already get continue } exists = append(exists, values[0]) if len(values) < 12 { continue } base := 1 // sometimes Address is omitted if len(values) < 13 { base = 0 } parsed := make([]uint64, 0, 8) vv := []string{ values[base+3], // PacketsRecv values[base+4], // Errin values[base+5], // Dropin values[base+6], // BytesRecvn values[base+7], // PacketSent values[base+8], // Errout values[base+9], // BytesSent values[base+11], // Dropout } for _, target := range vv { if target == "-" { parsed = append(parsed, 0) continue } t, err := strconv.ParseUint(target, 10, 64) if err != nil { return nil, err } parsed = append(parsed, t) } n := IOCountersStat{ Name: values[0], PacketsRecv: parsed[0], Errin: parsed[1], Dropin: parsed[2], BytesRecv: parsed[3], PacketsSent: parsed[4], Errout: parsed[5], BytesSent: parsed[6], Dropout: parsed[7], } ret = append(ret, n) } if pernic == false { return getIOCountersAll(ret) } return ret, nil } // IOCountersByFile exists just for compatibility with Linux. func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { return IOCountersByFileWithContext(context.Background(), pernic, filename) } func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) { return IOCounters(pernic) } func FilterCounters() ([]FilterStat, error) { return FilterCountersWithContext(context.Background()) } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { return nil, common.ErrNotImplementedError } func ConntrackStats(percpu bool) ([]ConntrackStat, error) { return ConntrackStatsWithContext(context.Background(), percpu) } func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { return nil, common.ErrNotImplementedError } // ProtoCounters returns network statistics for the entire system // If protocols is empty then all protocols are returned, otherwise // just the protocols in the list are returned. // Not Implemented for FreeBSD func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { return ProtoCountersWithContext(context.Background(), protocols) } func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/net/net_linux.go000066400000000000000000000563341455407747200166230ustar00rootroot00000000000000//go:build linux // +build linux package net import ( "bytes" "context" "encoding/hex" "errors" "fmt" "io" "net" "os" "strconv" "strings" "syscall" "github.com/shirou/gopsutil/v3/internal/common" ) const ( // Conntrack Column numbers ctENTRIES = iota ctSEARCHED ctFOUND ctNEW ctINVALID ctIGNORE ctDELETE ctDELETE_LIST ctINSERT ctINSERT_FAILED ctDROP ctEARLY_DROP ctICMP_ERROR CT_EXPEctNEW ctEXPECT_CREATE CT_EXPEctDELETE ctSEARCH_RESTART ) // NetIOCounters returns network I/O statistics for every network // interface installed on the system. If pernic argument is false, // return only sum of all information (which name is 'all'). If true, // every network interface installed on the system is returned // separately. func IOCounters(pernic bool) ([]IOCountersStat, error) { return IOCountersWithContext(context.Background(), pernic) } func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { filename := common.HostProcWithContext(ctx, "net/dev") return IOCountersByFileWithContext(ctx, pernic, filename) } func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { return IOCountersByFileWithContext(context.Background(), pernic, filename) } func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) { lines, err := common.ReadLines(filename) if err != nil { return nil, err } parts := make([]string, 2) statlen := len(lines) - 1 ret := make([]IOCountersStat, 0, statlen) for _, line := range lines[2:] { separatorPos := strings.LastIndex(line, ":") if separatorPos == -1 { continue } parts[0] = line[0:separatorPos] parts[1] = line[separatorPos+1:] interfaceName := strings.TrimSpace(parts[0]) if interfaceName == "" { continue } fields := strings.Fields(strings.TrimSpace(parts[1])) bytesRecv, err := strconv.ParseUint(fields[0], 10, 64) if err != nil { return ret, err } packetsRecv, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { return ret, err } errIn, err := strconv.ParseUint(fields[2], 10, 64) if err != nil { return ret, err } dropIn, err := strconv.ParseUint(fields[3], 10, 64) if err != nil { return ret, err } fifoIn, err := strconv.ParseUint(fields[4], 10, 64) if err != nil { return ret, err } bytesSent, err := strconv.ParseUint(fields[8], 10, 64) if err != nil { return ret, err } packetsSent, err := strconv.ParseUint(fields[9], 10, 64) if err != nil { return ret, err } errOut, err := strconv.ParseUint(fields[10], 10, 64) if err != nil { return ret, err } dropOut, err := strconv.ParseUint(fields[11], 10, 64) if err != nil { return ret, err } fifoOut, err := strconv.ParseUint(fields[12], 10, 64) if err != nil { return ret, err } nic := IOCountersStat{ Name: interfaceName, BytesRecv: bytesRecv, PacketsRecv: packetsRecv, Errin: errIn, Dropin: dropIn, Fifoin: fifoIn, BytesSent: bytesSent, PacketsSent: packetsSent, Errout: errOut, Dropout: dropOut, Fifoout: fifoOut, } ret = append(ret, nic) } if !pernic { return getIOCountersAll(ret) } return ret, nil } var netProtocols = []string{ "ip", "icmp", "icmpmsg", "tcp", "udp", "udplite", } // ProtoCounters returns network statistics for the entire system // If protocols is empty then all protocols are returned, otherwise // just the protocols in the list are returned. // Available protocols: // [ip,icmp,icmpmsg,tcp,udp,udplite] func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { return ProtoCountersWithContext(context.Background(), protocols) } func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { if len(protocols) == 0 { protocols = netProtocols } stats := make([]ProtoCountersStat, 0, len(protocols)) protos := make(map[string]bool, len(protocols)) for _, p := range protocols { protos[p] = true } filename := common.HostProcWithContext(ctx, "net/snmp") lines, err := common.ReadLines(filename) if err != nil { return nil, err } linecount := len(lines) for i := 0; i < linecount; i++ { line := lines[i] r := strings.IndexRune(line, ':') if r == -1 { return nil, errors.New(filename + " is not formatted correctly, expected ':'.") } proto := strings.ToLower(line[:r]) if !protos[proto] { // skip protocol and data line i++ continue } // Read header line statNames := strings.Split(line[r+2:], " ") // Read data line i++ statValues := strings.Split(lines[i][r+2:], " ") if len(statNames) != len(statValues) { return nil, errors.New(filename + " is not formatted correctly, expected same number of columns.") } stat := ProtoCountersStat{ Protocol: proto, Stats: make(map[string]int64, len(statNames)), } for j := range statNames { value, err := strconv.ParseInt(statValues[j], 10, 64) if err != nil { return nil, err } stat.Stats[statNames[j]] = value } stats = append(stats, stat) } return stats, nil } // NetFilterCounters returns iptables conntrack statistics // the currently in use conntrack count and the max. // If the file does not exist or is invalid it will return nil. func FilterCounters() ([]FilterStat, error) { return FilterCountersWithContext(context.Background()) } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { countfile := common.HostProcWithContext(ctx, "sys/net/netfilter/nf_conntrack_count") maxfile := common.HostProcWithContext(ctx, "sys/net/netfilter/nf_conntrack_max") count, err := common.ReadInts(countfile) if err != nil { return nil, err } stats := make([]FilterStat, 0, 1) max, err := common.ReadInts(maxfile) if err != nil { return nil, err } payload := FilterStat{ ConnTrackCount: count[0], ConnTrackMax: max[0], } stats = append(stats, payload) return stats, nil } // ConntrackStats returns more detailed info about the conntrack table func ConntrackStats(percpu bool) ([]ConntrackStat, error) { return ConntrackStatsWithContext(context.Background(), percpu) } // ConntrackStatsWithContext returns more detailed info about the conntrack table func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { return conntrackStatsFromFile(common.HostProcWithContext(ctx, "net/stat/nf_conntrack"), percpu) } // conntrackStatsFromFile returns more detailed info about the conntrack table // from `filename` // If 'percpu' is false, the result will contain exactly one item with totals/summary func conntrackStatsFromFile(filename string, percpu bool) ([]ConntrackStat, error) { lines, err := common.ReadLines(filename) if err != nil { return nil, err } statlist := NewConntrackStatList() for _, line := range lines { fields := strings.Fields(line) if len(fields) == 17 && fields[0] != "entries" { statlist.Append(NewConntrackStat( common.HexToUint32(fields[ctENTRIES]), common.HexToUint32(fields[ctSEARCHED]), common.HexToUint32(fields[ctFOUND]), common.HexToUint32(fields[ctNEW]), common.HexToUint32(fields[ctINVALID]), common.HexToUint32(fields[ctIGNORE]), common.HexToUint32(fields[ctDELETE]), common.HexToUint32(fields[ctDELETE_LIST]), common.HexToUint32(fields[ctINSERT]), common.HexToUint32(fields[ctINSERT_FAILED]), common.HexToUint32(fields[ctDROP]), common.HexToUint32(fields[ctEARLY_DROP]), common.HexToUint32(fields[ctICMP_ERROR]), common.HexToUint32(fields[CT_EXPEctNEW]), common.HexToUint32(fields[ctEXPECT_CREATE]), common.HexToUint32(fields[CT_EXPEctDELETE]), common.HexToUint32(fields[ctSEARCH_RESTART]), )) } } if percpu { return statlist.Items(), nil } return statlist.Summary(), nil } // http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h var tcpStatuses = map[string]string{ "01": "ESTABLISHED", "02": "SYN_SENT", "03": "SYN_RECV", "04": "FIN_WAIT1", "05": "FIN_WAIT2", "06": "TIME_WAIT", "07": "CLOSE", "08": "CLOSE_WAIT", "09": "LAST_ACK", "0A": "LISTEN", "0B": "CLOSING", } type netConnectionKindType struct { family uint32 sockType uint32 filename string } var kindTCP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_STREAM, filename: "tcp", } var kindTCP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_STREAM, filename: "tcp6", } var kindUDP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_DGRAM, filename: "udp", } var kindUDP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_DGRAM, filename: "udp6", } var kindUNIX = netConnectionKindType{ family: syscall.AF_UNIX, filename: "unix", } var netConnectionKindMap = map[string][]netConnectionKindType{ "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX}, "tcp": {kindTCP4, kindTCP6}, "tcp4": {kindTCP4}, "tcp6": {kindTCP6}, "udp": {kindUDP4, kindUDP6}, "udp4": {kindUDP4}, "udp6": {kindUDP6}, "unix": {kindUNIX}, "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6}, "inet4": {kindTCP4, kindUDP4}, "inet6": {kindTCP6, kindUDP6}, } type inodeMap struct { pid int32 fd uint32 } type connTmp struct { fd uint32 family uint32 sockType uint32 laddr Addr raddr Addr status string pid int32 boundPid int32 path string } // Return a list of network connections opened. func Connections(kind string) ([]ConnectionStat, error) { return ConnectionsWithContext(context.Background(), kind) } func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return ConnectionsPidWithContext(ctx, kind, 0) } // Return a list of network connections opened returning at most `max` // connections for each running process. func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) { return ConnectionsMaxWithContext(context.Background(), kind, max) } func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithContext(ctx, kind, 0, max) } // Return a list of network connections opened, omitting `Uids`. // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be // removed from the API in the future. func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) { return ConnectionsWithoutUidsWithContext(context.Background(), kind) } func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0) } func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max) } // Return a list of network connections opened by a process. func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidWithContext(context.Background(), kind, pid) } func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid) } func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidMaxWithContext(ctx, kind, pid, 0) } func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0) } // Return up to `max` network connections opened by a process. func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max) } func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max) } func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max, false) } func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max, true) } func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int, skipUids bool) ([]ConnectionStat, error) { tmap, ok := netConnectionKindMap[kind] if !ok { return nil, fmt.Errorf("invalid kind, %s", kind) } root := common.HostProcWithContext(ctx) var err error var inodes map[string][]inodeMap if pid == 0 { inodes, err = getProcInodesAllWithContext(ctx, root, max) } else { inodes, err = getProcInodes(root, pid, max) if len(inodes) == 0 { // no connection for the pid return []ConnectionStat{}, nil } } if err != nil { return nil, fmt.Errorf("cound not get pid(s), %d: %w", pid, err) } return statsFromInodesWithContext(ctx, root, pid, tmap, inodes, skipUids) } func statsFromInodes(root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap, skipUids bool) ([]ConnectionStat, error) { return statsFromInodesWithContext(context.Background(), root, pid, tmap, inodes, skipUids) } func statsFromInodesWithContext(ctx context.Context, root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap, skipUids bool) ([]ConnectionStat, error) { dupCheckMap := make(map[string]struct{}) var ret []ConnectionStat var err error for _, t := range tmap { var path string var connKey string var ls []connTmp if pid == 0 { path = fmt.Sprintf("%s/net/%s", root, t.filename) } else { path = fmt.Sprintf("%s/%d/net/%s", root, pid, t.filename) } switch t.family { case syscall.AF_INET, syscall.AF_INET6: ls, err = processInetWithContext(ctx, path, t, inodes, pid) case syscall.AF_UNIX: ls, err = processUnix(path, t, inodes, pid) } if err != nil { return nil, err } for _, c := range ls { // Build TCP key to id the connection uniquely // socket type, src ip, src port, dst ip, dst port and state should be enough // to prevent duplications. connKey = fmt.Sprintf("%d-%s:%d-%s:%d-%s", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status) if _, ok := dupCheckMap[connKey]; ok { continue } conn := ConnectionStat{ Fd: c.fd, Family: c.family, Type: c.sockType, Laddr: c.laddr, Raddr: c.raddr, Status: c.status, Pid: c.pid, } if c.pid == 0 { conn.Pid = c.boundPid } else { conn.Pid = c.pid } if !skipUids { // fetch process owner Real, effective, saved set, and filesystem UIDs proc := process{Pid: conn.Pid} conn.Uids, _ = proc.getUids(ctx) } ret = append(ret, conn) dupCheckMap[connKey] = struct{}{} } } return ret, nil } // getProcInodes returns fd of the pid. func getProcInodes(root string, pid int32, max int) (map[string][]inodeMap, error) { ret := make(map[string][]inodeMap) dir := fmt.Sprintf("%s/%d/fd", root, pid) f, err := os.Open(dir) if err != nil { return ret, err } defer f.Close() dirEntries, err := readDir(f, max) if err != nil { return ret, err } for _, dirEntry := range dirEntries { inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, dirEntry.Name()) inode, err := os.Readlink(inodePath) if err != nil { continue } if !strings.HasPrefix(inode, "socket:[") { continue } // the process is using a socket l := len(inode) inode = inode[8 : l-1] _, ok := ret[inode] if !ok { ret[inode] = make([]inodeMap, 0) } fd, err := strconv.Atoi(dirEntry.Name()) if err != nil { continue } i := inodeMap{ pid: pid, fd: uint32(fd), } ret[inode] = append(ret[inode], i) } return ret, nil } // Pids retunres all pids. // Note: this is a copy of process_linux.Pids() // FIXME: Import process occures import cycle. // move to common made other platform breaking. Need consider. func Pids() ([]int32, error) { return PidsWithContext(context.Background()) } func PidsWithContext(ctx context.Context) ([]int32, error) { var ret []int32 d, err := os.Open(common.HostProcWithContext(ctx)) if err != nil { return nil, err } defer d.Close() fnames, err := d.Readdirnames(-1) if err != nil { return nil, err } for _, fname := range fnames { pid, err := strconv.ParseInt(fname, 10, 32) if err != nil { // if not numeric name, just skip continue } ret = append(ret, int32(pid)) } return ret, nil } // Note: the following is based off process_linux structs and methods // we need these to fetch the owner of a process ID // FIXME: Import process occures import cycle. // see remarks on pids() type process struct { Pid int32 `json:"pid"` uids []int32 } // Uids returns user ids of the process as a slice of the int func (p *process) getUids(ctx context.Context) ([]int32, error) { err := p.fillFromStatus(ctx) if err != nil { return []int32{}, err } return p.uids, nil } // Get status from /proc/(pid)/status func (p *process) fillFromStatus(ctx context.Context) error { pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status") contents, err := os.ReadFile(statPath) if err != nil { return err } lines := strings.Split(string(contents), "\n") for _, line := range lines { tabParts := strings.SplitN(line, "\t", 2) if len(tabParts) < 2 { continue } value := tabParts[1] 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) if err != nil { return err } p.uids = append(p.uids, int32(v)) } } } return nil } func getProcInodesAll(root string, max int) (map[string][]inodeMap, error) { return getProcInodesAllWithContext(context.Background(), root, max) } func getProcInodesAllWithContext(ctx context.Context, root string, max int) (map[string][]inodeMap, error) { pids, err := PidsWithContext(ctx) if err != nil { return nil, err } ret := make(map[string][]inodeMap) for _, pid := range pids { t, err := getProcInodes(root, pid, max) if err != nil { // skip if permission error or no longer exists if os.IsPermission(err) || os.IsNotExist(err) || errors.Is(err, io.EOF) { continue } return ret, err } if len(t) == 0 { continue } // TODO: update ret. ret = updateMap(ret, t) } return ret, nil } // decodeAddress decode addresse represents addr in proc/net/* // ex: // "0500000A:0016" -> "10.0.0.5", 22 // "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53 func decodeAddress(family uint32, src string) (Addr, error) { return decodeAddressWithContext(context.Background(), family, src) } func decodeAddressWithContext(ctx context.Context, family uint32, src string) (Addr, error) { t := strings.Split(src, ":") if len(t) != 2 { return Addr{}, fmt.Errorf("does not contain port, %s", src) } addr := t[0] port, err := strconv.ParseUint(t[1], 16, 16) if err != nil { return Addr{}, fmt.Errorf("invalid port, %s", src) } decoded, err := hex.DecodeString(addr) if err != nil { return Addr{}, fmt.Errorf("decode error, %w", err) } var ip net.IP if family == syscall.AF_INET { if common.IsLittleEndian() { ip = net.IP(ReverseWithContext(ctx, decoded)) } else { ip = net.IP(decoded) } } else { // IPv6 ip, err = parseIPv6HexStringWithContext(ctx, decoded) if err != nil { return Addr{}, err } } return Addr{ IP: ip.String(), Port: uint32(port), }, nil } // Reverse reverses array of bytes. func Reverse(s []byte) []byte { return ReverseWithContext(context.Background(), s) } func ReverseWithContext(ctx context.Context, s []byte) []byte { for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { s[i], s[j] = s[j], s[i] } return s } // parseIPv6HexString parse array of bytes to IPv6 string func parseIPv6HexString(src []byte) (net.IP, error) { return parseIPv6HexStringWithContext(context.Background(), src) } func parseIPv6HexStringWithContext(ctx context.Context, src []byte) (net.IP, error) { if len(src) != 16 { return nil, fmt.Errorf("invalid IPv6 string") } buf := make([]byte, 0, 16) for i := 0; i < len(src); i += 4 { r := ReverseWithContext(ctx, src[i:i+4]) buf = append(buf, r...) } return net.IP(buf), nil } func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) { return processInetWithContext(context.Background(), file, kind, inodes, filterPid) } func processInetWithContext(ctx context.Context, file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) { if strings.HasSuffix(file, "6") && !common.PathExists(file) { // IPv6 not supported, return empty. return []connTmp{}, nil } // Read the contents of the /proc file with a single read sys call. // This minimizes duplicates in the returned connections // For more info: // https://github.com/shirou/gopsutil/pull/361 contents, err := os.ReadFile(file) if err != nil { return nil, err } lines := bytes.Split(contents, []byte("\n")) var ret []connTmp // skip first line for _, line := range lines[1:] { l := strings.Fields(string(line)) if len(l) < 10 { continue } laddr := l[1] raddr := l[2] status := l[3] inode := l[9] pid := int32(0) fd := uint32(0) i, exists := inodes[inode] if exists { pid = i[0].pid fd = i[0].fd } if filterPid > 0 && filterPid != pid { continue } if kind.sockType == syscall.SOCK_STREAM { status = tcpStatuses[status] } else { status = "NONE" } la, err := decodeAddressWithContext(ctx, kind.family, laddr) if err != nil { continue } ra, err := decodeAddressWithContext(ctx, kind.family, raddr) if err != nil { continue } ret = append(ret, connTmp{ fd: fd, family: kind.family, sockType: kind.sockType, laddr: la, raddr: ra, status: status, pid: pid, }) } return ret, nil } func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) { // Read the contents of the /proc file with a single read sys call. // This minimizes duplicates in the returned connections // For more info: // https://github.com/shirou/gopsutil/pull/361 contents, err := os.ReadFile(file) if err != nil { return nil, err } lines := bytes.Split(contents, []byte("\n")) var ret []connTmp // skip first line for _, line := range lines[1:] { tokens := strings.Fields(string(line)) if len(tokens) < 6 { continue } st, err := strconv.Atoi(tokens[4]) if err != nil { return nil, err } inode := tokens[6] var pairs []inodeMap pairs, exists := inodes[inode] if !exists { pairs = []inodeMap{ {}, } } for _, pair := range pairs { if filterPid > 0 && filterPid != pair.pid { continue } var path string if len(tokens) == 8 { path = tokens[len(tokens)-1] } ret = append(ret, connTmp{ fd: pair.fd, family: kind.family, sockType: uint32(st), laddr: Addr{ IP: path, }, pid: pair.pid, status: "NONE", path: path, }) } } return ret, nil } func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap { for key, value := range add { a, exists := src[key] if !exists { src[key] = value continue } src[key] = append(a, value...) } return src } gopsutil-3.24.1/net/net_linux_111.go000066400000000000000000000002311455407747200171660ustar00rootroot00000000000000//go:build !go1.16 // +build !go1.16 package net import ( "os" ) func readDir(f *os.File, max int) ([]os.FileInfo, error) { return f.Readdir(max) } gopsutil-3.24.1/net/net_linux_116.go000066400000000000000000000002271455407747200172000ustar00rootroot00000000000000//go:build go1.16 // +build go1.16 package net import ( "os" ) func readDir(f *os.File, max int) ([]os.DirEntry, error) { return f.ReadDir(max) } gopsutil-3.24.1/net/net_linux_netlink_test.go000066400000000000000000000004601455407747200213730ustar00rootroot00000000000000//go:build linux // +build linux package net import "testing" func BenchmarkGetConnectionsInet(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { Connections("inet") } } func BenchmarkGetConnectionsAll(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { Connections("all") } } gopsutil-3.24.1/net/net_linux_test.go000066400000000000000000000250411455407747200176510ustar00rootroot00000000000000package net import ( "context" "fmt" "net" "os" "strings" "syscall" "testing" "github.com/stretchr/testify/assert" "github.com/shirou/gopsutil/v3/internal/common" ) func TestIOCountersByFileParsing(t *testing.T) { // Prpare a temporary file, which will be read during the test tmpfile, err := os.CreateTemp("", "proc_dev_net") defer os.Remove(tmpfile.Name()) // clean up assert.Nil(t, err, "Temporary file creation failed: ", err) cases := [4][2]string{ {"eth0: ", "eth1: "}, {"eth0:0: ", "eth1:0: "}, {"eth0:", "eth1:"}, {"eth0:0:", "eth1:0:"}, } for _, testCase := range cases { err = tmpfile.Truncate(0) assert.Nil(t, err, "Temporary file truncating problem: ", err) // Parse interface name for assertion interface0 := strings.TrimSpace(testCase[0]) interface0 = interface0[:len(interface0)-1] interface1 := strings.TrimSpace(testCase[1]) interface1 = interface1[:len(interface1)-1] // Replace the interfaces from the test case proc := []byte(fmt.Sprintf("Inter-| Receive | Transmit\n face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n %s1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16\n %s100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600\n", testCase[0], testCase[1])) // Write /proc/net/dev sample output _, err = tmpfile.Write(proc) assert.Nil(t, err, "Temporary file writing failed: ", err) counters, err := IOCountersByFile(true, tmpfile.Name()) assert.Nil(t, err) assert.NotEmpty(t, counters) assert.Equal(t, 2, len(counters)) assert.Equal(t, interface0, counters[0].Name) assert.Equal(t, 1, int(counters[0].BytesRecv)) assert.Equal(t, 2, int(counters[0].PacketsRecv)) assert.Equal(t, 3, int(counters[0].Errin)) assert.Equal(t, 4, int(counters[0].Dropin)) assert.Equal(t, 5, int(counters[0].Fifoin)) assert.Equal(t, 9, int(counters[0].BytesSent)) assert.Equal(t, 10, int(counters[0].PacketsSent)) assert.Equal(t, 11, int(counters[0].Errout)) assert.Equal(t, 12, int(counters[0].Dropout)) assert.Equal(t, 13, int(counters[0].Fifoout)) assert.Equal(t, interface1, counters[1].Name) assert.Equal(t, 100, int(counters[1].BytesRecv)) assert.Equal(t, 200, int(counters[1].PacketsRecv)) assert.Equal(t, 300, int(counters[1].Errin)) assert.Equal(t, 400, int(counters[1].Dropin)) assert.Equal(t, 500, int(counters[1].Fifoin)) assert.Equal(t, 900, int(counters[1].BytesSent)) assert.Equal(t, 1000, int(counters[1].PacketsSent)) assert.Equal(t, 1100, int(counters[1].Errout)) assert.Equal(t, 1200, int(counters[1].Dropout)) assert.Equal(t, 1300, int(counters[1].Fifoout)) } err = tmpfile.Close() assert.Nil(t, err, "Temporary file closing failed: ", err) } func TestGetProcInodesAll(t *testing.T) { waitForServer := make(chan bool) go func() { // TCP listening goroutine to have some opened inodes even in CI addr, err := net.ResolveTCPAddr("tcp", "localhost:0") // dynamically get a random open port from OS if err != nil { t.Skipf("unable to resolve localhost: %v", err) } l, err := net.ListenTCP(addr.Network(), addr) if err != nil { t.Skipf("unable to listen on %v: %v", addr, err) } defer l.Close() waitForServer <- true for { conn, err := l.Accept() if err != nil { t.Skipf("unable to accept connection: %v", err) } defer conn.Close() } }() <-waitForServer root := common.HostProcWithContext(context.Background(), "") v, err := getProcInodesAll(root, 0) assert.Nil(t, err) assert.NotEmpty(t, v) } func TestConnectionsMax(t *testing.T) { if os.Getenv("CI") != "" { t.Skip("Skip CI") } max := 10 v, err := ConnectionsMax("tcp", max) assert.Nil(t, err) assert.NotEmpty(t, v) cxByPid := map[int32]int{} for _, cx := range v { if cx.Pid > 0 { cxByPid[cx.Pid]++ } } for _, c := range cxByPid { assert.True(t, c <= max) } } type AddrTest struct { IP string Port int Error bool } func TestDecodeAddress(t *testing.T) { assert := assert.New(t) addr := map[string]AddrTest{ "11111:0035": { Error: true, }, "0100007F:BLAH": { Error: true, }, "0085002452100113070057A13F025401:0035": { IP: "2400:8500:1301:1052:a157:7:154:23f", Port: 53, }, "00855210011307F025401:0035": { Error: true, }, } if common.IsLittleEndian() { addr["0500000A:0016"] = AddrTest{ IP: "10.0.0.5", Port: 22, } addr["0100007F:D1C2"] = AddrTest{ IP: "127.0.0.1", Port: 53698, } } else { addr["0A000005:0016"] = AddrTest{ IP: "10.0.0.5", Port: 22, } addr["7F000001:D1C2"] = AddrTest{ IP: "127.0.0.1", Port: 53698, } } for src, dst := range addr { family := syscall.AF_INET if len(src) > 13 { family = syscall.AF_INET6 } addr, err := decodeAddress(uint32(family), src) if dst.Error { assert.NotNil(err, src) } else { assert.Nil(err, src) assert.Equal(dst.IP, addr.IP, src) assert.Equal(dst.Port, int(addr.Port), src) } } } func TestReverse(t *testing.T) { src := []byte{0x01, 0x02, 0x03} assert.Equal(t, []byte{0x03, 0x02, 0x01}, Reverse(src)) } func TestConntrackStatFileParsing(t *testing.T) { tmpfile, err := os.CreateTemp("", "proc_net_stat_conntrack") defer os.Remove(tmpfile.Name()) assert.Nil(t, err, "Temporary file creation failed: ", err) data := []byte(` entries searched found new invalid ignore delete deleteList insert insertFailed drop earlyDrop icmpError expectNew expectCreate expectDelete searchRestart 0000007b 00000000 00000000 00000000 000b115a 00000084 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000004a 0000007b 00000000 00000000 00000000 0007eee5 00000068 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000035 0000007b 00000000 00000000 00000000 0090346b 00000057 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000025 0000007b 00000000 00000000 00000000 0005920f 00000069 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000064 0000007b 00000000 00000000 00000000 000331ff 00000059 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000003b 0000007b 00000000 00000000 00000000 000314ea 00000066 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000054 0000007b 00000000 00000000 00000000 0002b270 00000055 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000003d 0000007b 00000000 00000000 00000000 0002f67d 00000057 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000042 `) // Expected results slist := NewConntrackStatList() slist.Append(&ConntrackStat{ Entries: 123, Searched: 0, Found: 0, New: 0, Invalid: 725338, Ignore: 132, Delete: 0, DeleteList: 0, Insert: 0, InsertFailed: 0, Drop: 0, EarlyDrop: 0, IcmpError: 0, ExpectNew: 0, ExpectCreate: 0, ExpectDelete: 0, SearchRestart: 74, }) slist.Append(&ConntrackStat{123, 0, 0, 0, 519909, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53}) slist.Append(&ConntrackStat{123, 0, 0, 0, 9450603, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37}) slist.Append(&ConntrackStat{123, 0, 0, 0, 365071, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}) slist.Append(&ConntrackStat{123, 0, 0, 0, 209407, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59}) slist.Append(&ConntrackStat{123, 0, 0, 0, 201962, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84}) slist.Append(&ConntrackStat{123, 0, 0, 0, 176752, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61}) slist.Append(&ConntrackStat{123, 0, 0, 0, 194173, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66}) // Write data to tempfile _, err = tmpfile.Write(data) assert.Nil(t, err, "Temporary file writing failed: ", err) // Function under test stats, err := conntrackStatsFromFile(tmpfile.Name(), true) assert.Nil(t, err) assert.Equal(t, 8, len(stats), "Expected 8 results") summary := &ConntrackStat{} for i, exp := range slist.Items() { st := stats[i] assert.Equal(t, exp.Entries, st.Entries) summary.Entries += st.Entries assert.Equal(t, exp.Searched, st.Searched) summary.Searched += st.Searched assert.Equal(t, exp.Found, st.Found) summary.Found += st.Found assert.Equal(t, exp.New, st.New) summary.New += st.New assert.Equal(t, exp.Invalid, st.Invalid) summary.Invalid += st.Invalid assert.Equal(t, exp.Ignore, st.Ignore) summary.Ignore += st.Ignore assert.Equal(t, exp.Delete, st.Delete) summary.Delete += st.Delete assert.Equal(t, exp.DeleteList, st.DeleteList) summary.DeleteList += st.DeleteList assert.Equal(t, exp.Insert, st.Insert) summary.Insert += st.Insert assert.Equal(t, exp.InsertFailed, st.InsertFailed) summary.InsertFailed += st.InsertFailed assert.Equal(t, exp.Drop, st.Drop) summary.Drop += st.Drop assert.Equal(t, exp.EarlyDrop, st.EarlyDrop) summary.EarlyDrop += st.EarlyDrop assert.Equal(t, exp.IcmpError, st.IcmpError) summary.IcmpError += st.IcmpError assert.Equal(t, exp.ExpectNew, st.ExpectNew) summary.ExpectNew += st.ExpectNew assert.Equal(t, exp.ExpectCreate, st.ExpectCreate) summary.ExpectCreate += st.ExpectCreate assert.Equal(t, exp.ExpectDelete, st.ExpectDelete) summary.ExpectDelete += st.ExpectDelete assert.Equal(t, exp.SearchRestart, st.SearchRestart) summary.SearchRestart += st.SearchRestart } // Test summary grouping totals, err := conntrackStatsFromFile(tmpfile.Name(), false) assert.Nil(t, err) for i, st := range totals { assert.Equal(t, summary.Entries, st.Entries) assert.Equal(t, summary.Searched, st.Searched) assert.Equal(t, summary.Found, st.Found) assert.Equal(t, summary.New, st.New) assert.Equal(t, summary.Invalid, st.Invalid) assert.Equal(t, summary.Ignore, st.Ignore) assert.Equal(t, summary.Delete, st.Delete) assert.Equal(t, summary.DeleteList, st.DeleteList) assert.Equal(t, summary.Insert, st.Insert) assert.Equal(t, summary.InsertFailed, st.InsertFailed) assert.Equal(t, summary.Drop, st.Drop) assert.Equal(t, summary.EarlyDrop, st.EarlyDrop) assert.Equal(t, summary.IcmpError, st.IcmpError) assert.Equal(t, summary.ExpectNew, st.ExpectNew) assert.Equal(t, summary.ExpectCreate, st.ExpectCreate) assert.Equal(t, summary.ExpectDelete, st.ExpectDelete) assert.Equal(t, summary.SearchRestart, st.SearchRestart) assert.Equal(t, 0, i) // Should only have one element } } gopsutil-3.24.1/net/net_openbsd.go000066400000000000000000000161661455407747200171150ustar00rootroot00000000000000//go:build openbsd // +build openbsd package net import ( "context" "fmt" "os/exec" "regexp" "strconv" "strings" "syscall" "github.com/shirou/gopsutil/v3/internal/common" ) var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`) func ParseNetstat(output string, mode string, iocs map[string]IOCountersStat) error { lines := strings.Split(output, "\n") exists := make([]string, 0, len(lines)-1) columns := 6 if mode == "ind" { columns = 10 } for _, line := range lines { values := strings.Fields(line) if len(values) < 1 || values[0] == "Name" { continue } if common.StringsHas(exists, values[0]) { // skip if already get continue } if len(values) < columns { continue } base := 1 // sometimes Address is omitted if len(values) < columns { base = 0 } parsed := make([]uint64, 0, 8) var vv []string if mode == "inb" { vv = []string{ values[base+3], // BytesRecv values[base+4], // BytesSent } } else { vv = []string{ values[base+3], // Ipkts values[base+4], // Ierrs values[base+5], // Opkts values[base+6], // Oerrs values[base+8], // Drops } } for _, target := range vv { if target == "-" { parsed = append(parsed, 0) continue } t, err := strconv.ParseUint(target, 10, 64) if err != nil { return err } parsed = append(parsed, t) } exists = append(exists, values[0]) n, present := iocs[values[0]] if !present { n = IOCountersStat{Name: values[0]} } if mode == "inb" { n.BytesRecv = parsed[0] n.BytesSent = parsed[1] } else { n.PacketsRecv = parsed[0] n.Errin = parsed[1] n.PacketsSent = parsed[2] n.Errout = parsed[3] n.Dropin = parsed[4] n.Dropout = parsed[4] } iocs[n.Name] = n } return nil } func IOCounters(pernic bool) ([]IOCountersStat, error) { return IOCountersWithContext(context.Background(), pernic) } func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { netstat, err := exec.LookPath("netstat") if err != nil { return nil, err } out, err := invoke.CommandWithContext(ctx, netstat, "-inb") if err != nil { return nil, err } out2, err := invoke.CommandWithContext(ctx, netstat, "-ind") if err != nil { return nil, err } iocs := make(map[string]IOCountersStat) lines := strings.Split(string(out), "\n") ret := make([]IOCountersStat, 0, len(lines)-1) err = ParseNetstat(string(out), "inb", iocs) if err != nil { return nil, err } err = ParseNetstat(string(out2), "ind", iocs) if err != nil { return nil, err } for _, ioc := range iocs { ret = append(ret, ioc) } if pernic == false { return getIOCountersAll(ret) } return ret, nil } // IOCountersByFile exists just for compatibility with Linux. func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { return IOCountersByFileWithContext(context.Background(), pernic, filename) } func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) { return IOCounters(pernic) } func FilterCounters() ([]FilterStat, error) { return FilterCountersWithContext(context.Background()) } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { return nil, common.ErrNotImplementedError } func ConntrackStats(percpu bool) ([]ConntrackStat, error) { return ConntrackStatsWithContext(context.Background(), percpu) } func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { return nil, common.ErrNotImplementedError } // ProtoCounters returns network statistics for the entire system // If protocols is empty then all protocols are returned, otherwise // just the protocols in the list are returned. // Not Implemented for OpenBSD func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { return ProtoCountersWithContext(context.Background(), protocols) } func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { return nil, common.ErrNotImplementedError } func parseNetstatLine(line string) (ConnectionStat, error) { f := strings.Fields(line) if len(f) < 5 { return ConnectionStat{}, fmt.Errorf("wrong line,%s", line) } var netType, netFamily uint32 switch f[0] { case "tcp": netType = syscall.SOCK_STREAM netFamily = syscall.AF_INET case "udp": netType = syscall.SOCK_DGRAM netFamily = syscall.AF_INET case "tcp6": netType = syscall.SOCK_STREAM netFamily = syscall.AF_INET6 case "udp6": netType = syscall.SOCK_DGRAM netFamily = syscall.AF_INET6 default: return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0]) } laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily) if err != nil { return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4]) } n := ConnectionStat{ Fd: uint32(0), // not supported Family: uint32(netFamily), Type: uint32(netType), Laddr: laddr, Raddr: raddr, Pid: int32(0), // not supported } if len(f) == 6 { n.Status = f[5] } return n, nil } func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) { parse := func(l string) (Addr, error) { matches := portMatch.FindStringSubmatch(l) if matches == nil { return Addr{}, fmt.Errorf("wrong addr, %s", l) } host := matches[1] port := matches[2] if host == "*" { switch family { case syscall.AF_INET: host = "0.0.0.0" case syscall.AF_INET6: host = "::" default: return Addr{}, fmt.Errorf("unknown family, %d", family) } } lport, err := strconv.Atoi(port) if err != nil { return Addr{}, err } return Addr{IP: host, Port: uint32(lport)}, nil } laddr, err = parse(local) if remote != "*.*" { // remote addr exists raddr, err = parse(remote) if err != nil { return laddr, raddr, err } } return laddr, raddr, err } // Return a list of network connections opened. func Connections(kind string) ([]ConnectionStat, error) { return ConnectionsWithContext(context.Background(), kind) } func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { var ret []ConnectionStat args := []string{"-na"} switch strings.ToLower(kind) { default: fallthrough case "": fallthrough case "all": fallthrough case "inet": // nothing to add case "inet4": args = append(args, "-finet") case "inet6": args = append(args, "-finet6") case "tcp": args = append(args, "-ptcp") case "tcp4": args = append(args, "-ptcp", "-finet") case "tcp6": args = append(args, "-ptcp", "-finet6") case "udp": args = append(args, "-pudp") case "udp4": args = append(args, "-pudp", "-finet") case "udp6": args = append(args, "-pudp", "-finet6") case "unix": return ret, common.ErrNotImplementedError } netstat, err := exec.LookPath("netstat") if err != nil { return nil, err } out, err := invoke.CommandWithContext(ctx, netstat, args...) if err != nil { return nil, err } lines := strings.Split(string(out), "\n") for _, line := range lines { if !(strings.HasPrefix(line, "tcp") || strings.HasPrefix(line, "udp")) { continue } n, err := parseNetstatLine(line) if err != nil { continue } ret = append(ret, n) } return ret, nil } gopsutil-3.24.1/net/net_solaris.go000066400000000000000000000110211455407747200171200ustar00rootroot00000000000000//go:build solaris // +build solaris package net import ( "context" "fmt" "regexp" "runtime" "strconv" "strings" "github.com/shirou/gopsutil/v3/internal/common" ) // NetIOCounters returnes network I/O statistics for every network // interface installed on the system. If pernic argument is false, // return only sum of all information (which name is 'all'). If true, // every network interface installed on the system is returned // separately. func IOCounters(pernic bool) ([]IOCountersStat, error) { return IOCountersWithContext(context.Background(), pernic) } var kstatSplit = regexp.MustCompile(`[:\s]+`) func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { // collect all the net class's links with below statistics filterstr := "/^(?!vnic)/::phys:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/" if runtime.GOOS == "illumos" { filterstr = "/[^vnic]/::mac:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/" } kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-c", "net", "-p", filterstr) if err != nil { return nil, fmt.Errorf("cannot execute kstat: %w", err) } lines := strings.Split(strings.TrimSpace(string(kstatSysOut)), "\n") if len(lines) == 0 { return nil, fmt.Errorf("no interface found") } rbytes64arr := make(map[string]uint64) ipackets64arr := make(map[string]uint64) idrops64arr := make(map[string]uint64) ierrorsarr := make(map[string]uint64) obytes64arr := make(map[string]uint64) opackets64arr := make(map[string]uint64) odrops64arr := make(map[string]uint64) oerrorsarr := make(map[string]uint64) for _, line := range lines { fields := kstatSplit.Split(line, -1) interfaceName := fields[0] instance := fields[1] switch fields[3] { case "rbytes64": rbytes64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, fmt.Errorf("cannot parse rbytes64: %w", err) } case "ipackets64": ipackets64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, fmt.Errorf("cannot parse ipackets64: %w", err) } case "idrops64": idrops64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, fmt.Errorf("cannot parse idrops64: %w", err) } case "ierrors": ierrorsarr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, fmt.Errorf("cannot parse ierrors: %w", err) } case "obytes64": obytes64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, fmt.Errorf("cannot parse obytes64: %w", err) } case "opackets64": opackets64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, fmt.Errorf("cannot parse opackets64: %w", err) } case "odrops64": odrops64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, fmt.Errorf("cannot parse odrops64: %w", err) } case "oerrors": oerrorsarr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, fmt.Errorf("cannot parse oerrors: %w", err) } } } ret := make([]IOCountersStat, 0) for k := range rbytes64arr { nic := IOCountersStat{ Name: k, BytesRecv: rbytes64arr[k], PacketsRecv: ipackets64arr[k], Errin: ierrorsarr[k], Dropin: idrops64arr[k], BytesSent: obytes64arr[k], PacketsSent: opackets64arr[k], Errout: oerrorsarr[k], Dropout: odrops64arr[k], } ret = append(ret, nic) } if !pernic { return getIOCountersAll(ret) } return ret, nil } func Connections(kind string) ([]ConnectionStat, error) { return ConnectionsWithContext(context.Background(), kind) } func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } func FilterCounters() ([]FilterStat, error) { return FilterCountersWithContext(context.Background()) } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { return []FilterStat{}, common.ErrNotImplementedError } func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { return ProtoCountersWithContext(context.Background(), protocols) } func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { return []ProtoCountersStat{}, common.ErrNotImplementedError } gopsutil-3.24.1/net/net_test.go000066400000000000000000000153471455407747200164420ustar00rootroot00000000000000package net import ( "errors" "fmt" "os" "runtime" "testing" "github.com/shirou/gopsutil/v3/internal/common" ) func skipIfNotImplementedErr(t *testing.T, err error) { if errors.Is(err, common.ErrNotImplementedError) { t.Skip("not implemented") } } func TestAddrString(t *testing.T) { v := Addr{IP: "192.168.0.1", Port: 8000} s := fmt.Sprintf("%v", v) if s != `{"ip":"192.168.0.1","port":8000}` { t.Errorf("Addr string is invalid: %v", v) } } func TestNetIOCountersStatString(t *testing.T) { v := IOCountersStat{ Name: "test", BytesSent: 100, } e := `{"name":"test","bytesSent":100,"bytesRecv":0,"packetsSent":0,"packetsRecv":0,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0}` if e != fmt.Sprintf("%v", v) { t.Errorf("NetIOCountersStat string is invalid: %v", v) } } func TestNetProtoCountersStatString(t *testing.T) { v := ProtoCountersStat{ Protocol: "tcp", Stats: map[string]int64{ "MaxConn": -1, "ActiveOpens": 4000, "PassiveOpens": 3000, }, } e := `{"protocol":"tcp","stats":{"ActiveOpens":4000,"MaxConn":-1,"PassiveOpens":3000}}` if e != fmt.Sprintf("%v", v) { t.Errorf("NetProtoCountersStat string is invalid: %v", v) } } func TestNetConnectionStatString(t *testing.T) { v := ConnectionStat{ Fd: 10, Family: 10, Type: 10, Uids: []int32{10, 10}, } e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","uids":[10,10],"pid":0}` if e != fmt.Sprintf("%v", v) { t.Errorf("NetConnectionStat string is invalid: %v", v) } } func TestNetIOCountersAll(t *testing.T) { v, err := IOCounters(false) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("Could not get NetIOCounters: %v", err) } per, err := IOCounters(true) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("Could not get NetIOCounters: %v", err) } if len(v) != 1 { t.Errorf("Could not get NetIOCounters: %v", v) } if v[0].Name != "all" { t.Errorf("Invalid NetIOCounters: %v", v) } var pr uint64 for _, p := range per { pr += p.PacketsRecv } // small diff is ok, compare instead of math.Abs(subtraction) with uint64 var diff uint64 if v[0].PacketsRecv > pr { diff = v[0].PacketsRecv - pr } else { diff = pr - v[0].PacketsRecv } if diff > 5 { if ci := os.Getenv("CI"); ci != "" { // This test often fails in CI. so just print even if failed. fmt.Printf("invalid sum value: %v, %v", v[0].PacketsRecv, pr) } else { t.Errorf("invalid sum value: %v, %v", v[0].PacketsRecv, pr) } } } func TestNetIOCountersPerNic(t *testing.T) { v, err := IOCounters(true) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("Could not get NetIOCounters: %v", err) } if len(v) == 0 { t.Errorf("Could not get NetIOCounters: %v", v) } for _, vv := range v { if vv.Name == "" { t.Errorf("Invalid NetIOCounters: %v", vv) } } } func TestGetNetIOCountersAll(t *testing.T) { n := []IOCountersStat{ { Name: "a", BytesRecv: 10, PacketsRecv: 10, }, { Name: "b", BytesRecv: 10, PacketsRecv: 10, Errin: 10, }, } ret, err := getIOCountersAll(n) skipIfNotImplementedErr(t, err) if err != nil { t.Error(err) } if len(ret) != 1 { t.Errorf("invalid return count") } if ret[0].Name != "all" { t.Errorf("invalid return name") } if ret[0].BytesRecv != 20 { t.Errorf("invalid count bytesrecv") } if ret[0].Errin != 10 { t.Errorf("invalid count errin") } } func TestNetInterfaces(t *testing.T) { v, err := Interfaces() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("Could not get NetInterfaceStat: %v", err) } if len(v) == 0 { t.Errorf("Could not get NetInterfaceStat: %v", err) } for _, vv := range v { if vv.Name == "" { t.Errorf("Invalid NetInterface: %v", vv) } } } func TestNetProtoCountersStatsAll(t *testing.T) { v, err := ProtoCounters(nil) skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("Could not get NetProtoCounters: %v", err) } if len(v) == 0 { t.Fatalf("Could not get NetProtoCounters: %v", err) } for _, vv := range v { if vv.Protocol == "" { t.Errorf("Invalid NetProtoCountersStat: %v", vv) } if len(vv.Stats) == 0 { t.Errorf("Invalid NetProtoCountersStat: %v", vv) } } } func TestNetProtoCountersStats(t *testing.T) { v, err := ProtoCounters([]string{"tcp", "ip"}) skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("Could not get NetProtoCounters: %v", err) } if len(v) == 0 { t.Fatalf("Could not get NetProtoCounters: %v", err) } if len(v) != 2 { t.Fatalf("Go incorrect number of NetProtoCounters: %v", err) } for _, vv := range v { if vv.Protocol != "tcp" && vv.Protocol != "ip" { t.Errorf("Invalid NetProtoCountersStat: %v", vv) } if len(vv.Stats) == 0 { t.Errorf("Invalid NetProtoCountersStat: %v", vv) } } } func TestNetConnections(t *testing.T) { if ci := os.Getenv("CI"); ci != "" { // skip if test on drone.io return } v, err := Connections("inet") skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("could not get NetConnections: %v", err) } if len(v) == 0 { t.Errorf("could not get NetConnections: %v", v) } for _, vv := range v { if vv.Family == 0 { t.Errorf("invalid NetConnections: %v", vv) } } } func TestNetFilterCounters(t *testing.T) { if ci := os.Getenv("CI"); ci != "" { // skip if test on drone.io return } if runtime.GOOS == "linux" { // some test environment has not the path. if !common.PathExists("/proc/sys/net/netfilter/nf_connTrackCount") { t.SkipNow() } } v, err := FilterCounters() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("could not get NetConnections: %v", err) } if len(v) == 0 { t.Errorf("could not get NetConnections: %v", v) } for _, vv := range v { if vv.ConnTrackMax == 0 { t.Errorf("nf_connTrackMax needs to be greater than zero: %v", vv) } } } func TestInterfaceStatString(t *testing.T) { v := InterfaceStat{ Index: 0, MTU: 1500, Name: "eth0", HardwareAddr: "01:23:45:67:89:ab", Flags: []string{"up", "down"}, Addrs: InterfaceAddrList{{Addr: "1.2.3.4"}, {Addr: "5.6.7.8"}}, } s := fmt.Sprintf("%v", v) if s != `{"index":0,"mtu":1500,"name":"eth0","hardwareAddr":"01:23:45:67:89:ab","flags":["up","down"],"addrs":[{"addr":"1.2.3.4"},{"addr":"5.6.7.8"}]}` { t.Errorf("InterfaceStat string is invalid: %v", s) } list := InterfaceStatList{v, v} s = fmt.Sprintf("%v", list) if s != `[{"index":0,"mtu":1500,"name":"eth0","hardwareAddr":"01:23:45:67:89:ab","flags":["up","down"],"addrs":[{"addr":"1.2.3.4"},{"addr":"5.6.7.8"}]},{"index":0,"mtu":1500,"name":"eth0","hardwareAddr":"01:23:45:67:89:ab","flags":["up","down"],"addrs":[{"addr":"1.2.3.4"},{"addr":"5.6.7.8"}]}]` { t.Errorf("InterfaceStatList string is invalid: %v", s) } } gopsutil-3.24.1/net/net_unix.go000066400000000000000000000137251455407747200164440ustar00rootroot00000000000000//go:build freebsd || darwin // +build freebsd darwin package net import ( "context" "fmt" "net" "strconv" "strings" "syscall" "github.com/shirou/gopsutil/v3/internal/common" ) // Return a list of network connections opened. func Connections(kind string) ([]ConnectionStat, error) { return ConnectionsWithContext(context.Background(), kind) } func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return ConnectionsPidWithContext(ctx, kind, 0) } // Return a list of network connections opened returning at most `max` // connections for each running process. func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) { return ConnectionsMaxWithContext(context.Background(), kind, max) } func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } // Return a list of network connections opened by a process. func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidWithContext(context.Background(), kind, pid) } func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { var ret []ConnectionStat args := []string{"-i"} switch strings.ToLower(kind) { default: fallthrough case "": fallthrough case "all": fallthrough case "inet": args = append(args, "tcp", "-i", "udp") case "inet4": args = append(args, "4") case "inet6": args = append(args, "6") case "tcp": args = append(args, "tcp") case "tcp4": args = append(args, "4tcp") case "tcp6": args = append(args, "6tcp") case "udp": args = append(args, "udp") case "udp4": args = append(args, "4udp") case "udp6": args = append(args, "6udp") case "unix": args = []string{"-U"} } r, err := common.CallLsofWithContext(ctx, invoke, pid, args...) if err != nil { return nil, err } for _, rr := range r { if strings.HasPrefix(rr, "COMMAND") { continue } n, err := parseNetLine(rr) if err != nil { continue } ret = append(ret, n) } return ret, nil } var constMap = map[string]int{ "unix": syscall.AF_UNIX, "TCP": syscall.SOCK_STREAM, "UDP": syscall.SOCK_DGRAM, "IPv4": syscall.AF_INET, "IPv6": syscall.AF_INET6, } func parseNetLine(line string) (ConnectionStat, error) { f := strings.Fields(line) if len(f) < 8 { return ConnectionStat{}, fmt.Errorf("wrong line,%s", line) } if len(f) == 8 { f = append(f, f[7]) f[7] = "unix" } pid, err := strconv.Atoi(f[1]) if err != nil { return ConnectionStat{}, err } fd, err := strconv.Atoi(strings.Trim(f[3], "u")) if err != nil { return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3]) } netFamily, ok := constMap[f[4]] if !ok { return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4]) } netType, ok := constMap[f[7]] if !ok { return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7]) } var laddr, raddr Addr if f[7] == "unix" { laddr.IP = f[8] } else { laddr, raddr, err = parseNetAddr(f[8]) if err != nil { return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8]) } } n := ConnectionStat{ Fd: uint32(fd), Family: uint32(netFamily), Type: uint32(netType), Laddr: laddr, Raddr: raddr, Pid: int32(pid), } if len(f) == 10 { n.Status = strings.Trim(f[9], "()") } return n, nil } func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) { parse := func(l string) (Addr, error) { host, port, err := net.SplitHostPort(l) if err != nil { return Addr{}, fmt.Errorf("wrong addr, %s", l) } lport, err := strconv.Atoi(port) if err != nil { return Addr{}, err } return Addr{IP: host, Port: uint32(lport)}, nil } addrs := strings.Split(line, "->") if len(addrs) == 0 { return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line) } laddr, err = parse(addrs[0]) if len(addrs) == 2 { // remote addr exists raddr, err = parse(addrs[1]) if err != nil { return laddr, raddr, err } } return laddr, raddr, err } // Return up to `max` network connections opened by a process. func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max) } func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } // Return a list of network connections opened, omitting `Uids`. // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be // removed from the API in the future. func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) { return ConnectionsWithoutUidsWithContext(context.Background(), kind) } func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0) } func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max) } func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid) } func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0) } func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max) } func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max) } func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } gopsutil-3.24.1/net/net_windows.go000066400000000000000000000477451455407747200171640ustar00rootroot00000000000000//go:build windows // +build windows package net import ( "context" "fmt" "net" "os" "syscall" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/windows" ) var ( modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") procGetExtendedTCPTable = modiphlpapi.NewProc("GetExtendedTcpTable") procGetExtendedUDPTable = modiphlpapi.NewProc("GetExtendedUdpTable") procGetIfEntry2 = modiphlpapi.NewProc("GetIfEntry2") ) const ( TCPTableBasicListener = iota TCPTableBasicConnections TCPTableBasicAll TCPTableOwnerPIDListener TCPTableOwnerPIDConnections TCPTableOwnerPIDAll TCPTableOwnerModuleListener TCPTableOwnerModuleConnections TCPTableOwnerModuleAll ) type netConnectionKindType struct { family uint32 sockType uint32 filename string } var kindTCP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_STREAM, filename: "tcp", } var kindTCP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_STREAM, filename: "tcp6", } var kindUDP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_DGRAM, filename: "udp", } var kindUDP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_DGRAM, filename: "udp6", } var netConnectionKindMap = map[string][]netConnectionKindType{ "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6}, "tcp": {kindTCP4, kindTCP6}, "tcp4": {kindTCP4}, "tcp6": {kindTCP6}, "udp": {kindUDP4, kindUDP6}, "udp4": {kindUDP4}, "udp6": {kindUDP6}, "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6}, "inet4": {kindTCP4, kindUDP4}, "inet6": {kindTCP6, kindUDP6}, } // https://github.com/microsoft/ethr/blob/aecdaf923970e5a9b4c461b4e2e3963d781ad2cc/plt_windows.go#L114-L170 type guid struct { Data1 uint32 Data2 uint16 Data3 uint16 Data4 [8]byte } const ( maxStringSize = 256 maxPhysAddressLength = 32 pad0for64_4for32 = 0 ) type mibIfRow2 struct { InterfaceLuid uint64 InterfaceIndex uint32 InterfaceGuid guid Alias [maxStringSize + 1]uint16 Description [maxStringSize + 1]uint16 PhysicalAddressLength uint32 PhysicalAddress [maxPhysAddressLength]uint8 PermanentPhysicalAddress [maxPhysAddressLength]uint8 Mtu uint32 Type uint32 TunnelType uint32 MediaType uint32 PhysicalMediumType uint32 AccessType uint32 DirectionType uint32 InterfaceAndOperStatusFlags uint32 OperStatus uint32 AdminStatus uint32 MediaConnectState uint32 NetworkGuid guid ConnectionType uint32 padding1 [pad0for64_4for32]byte TransmitLinkSpeed uint64 ReceiveLinkSpeed uint64 InOctets uint64 InUcastPkts uint64 InNUcastPkts uint64 InDiscards uint64 InErrors uint64 InUnknownProtos uint64 InUcastOctets uint64 InMulticastOctets uint64 InBroadcastOctets uint64 OutOctets uint64 OutUcastPkts uint64 OutNUcastPkts uint64 OutDiscards uint64 OutErrors uint64 OutUcastOctets uint64 OutMulticastOctets uint64 OutBroadcastOctets uint64 OutQLen uint64 } func IOCounters(pernic bool) ([]IOCountersStat, error) { return IOCountersWithContext(context.Background(), pernic) } func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { ifs, err := net.Interfaces() if err != nil { return nil, err } var counters []IOCountersStat err = procGetIfEntry2.Find() if err == nil { // Vista+, uint64 values (issue#693) for _, ifi := range ifs { c := IOCountersStat{ Name: ifi.Name, } row := mibIfRow2{InterfaceIndex: uint32(ifi.Index)} ret, _, err := procGetIfEntry2.Call(uintptr(unsafe.Pointer(&row))) if ret != 0 { return nil, os.NewSyscallError("GetIfEntry2", err) } c.BytesSent = uint64(row.OutOctets) c.BytesRecv = uint64(row.InOctets) c.PacketsSent = uint64(row.OutUcastPkts) c.PacketsRecv = uint64(row.InUcastPkts) c.Errin = uint64(row.InErrors) c.Errout = uint64(row.OutErrors) c.Dropin = uint64(row.InDiscards) c.Dropout = uint64(row.OutDiscards) counters = append(counters, c) } } else { // WinXP fallback, uint32 values for _, ifi := range ifs { c := IOCountersStat{ Name: ifi.Name, } row := windows.MibIfRow{Index: uint32(ifi.Index)} err = windows.GetIfEntry(&row) if err != nil { return nil, os.NewSyscallError("GetIfEntry", err) } c.BytesSent = uint64(row.OutOctets) c.BytesRecv = uint64(row.InOctets) c.PacketsSent = uint64(row.OutUcastPkts) c.PacketsRecv = uint64(row.InUcastPkts) c.Errin = uint64(row.InErrors) c.Errout = uint64(row.OutErrors) c.Dropin = uint64(row.InDiscards) c.Dropout = uint64(row.OutDiscards) counters = append(counters, c) } } if !pernic { return getIOCountersAll(counters) } return counters, nil } // IOCountersByFile exists just for compatibility with Linux. func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { return IOCountersByFileWithContext(context.Background(), pernic, filename) } func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) { return IOCounters(pernic) } // Return a list of network connections // Available kind: // // reference to netConnectionKindMap func Connections(kind string) ([]ConnectionStat, error) { return ConnectionsWithContext(context.Background(), kind) } func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return ConnectionsPidWithContext(ctx, kind, 0) } // ConnectionsPid Return a list of network connections opened by a process func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidWithContext(context.Background(), kind, pid) } func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { tmap, ok := netConnectionKindMap[kind] if !ok { return nil, fmt.Errorf("invalid kind, %s", kind) } return getProcInet(tmap, pid) } func getProcInet(kinds []netConnectionKindType, pid int32) ([]ConnectionStat, error) { stats := make([]ConnectionStat, 0) for _, kind := range kinds { s, err := getNetStatWithKind(kind) if err != nil { continue } if pid == 0 { stats = append(stats, s...) } else { for _, ns := range s { if ns.Pid != pid { continue } stats = append(stats, ns) } } } return stats, nil } func getNetStatWithKind(kindType netConnectionKindType) ([]ConnectionStat, error) { if kindType.filename == "" { return nil, fmt.Errorf("kind filename must be required") } switch kindType.filename { case kindTCP4.filename: return getTCPConnections(kindTCP4.family) case kindTCP6.filename: return getTCPConnections(kindTCP6.family) case kindUDP4.filename: return getUDPConnections(kindUDP4.family) case kindUDP6.filename: return getUDPConnections(kindUDP6.family) } return nil, fmt.Errorf("invalid kind filename, %s", kindType.filename) } // Return a list of network connections opened returning at most `max` // connections for each running process. func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) { return ConnectionsMaxWithContext(context.Background(), kind, max) } func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } // Return a list of network connections opened, omitting `Uids`. // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be // removed from the API in the future. func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) { return ConnectionsWithoutUidsWithContext(context.Background(), kind) } func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0) } func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max) } func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid) } func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0) } func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max) } func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max) } func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) { return []ConnectionStat{}, common.ErrNotImplementedError } func FilterCounters() ([]FilterStat, error) { return FilterCountersWithContext(context.Background()) } func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { return nil, common.ErrNotImplementedError } func ConntrackStats(percpu bool) ([]ConntrackStat, error) { return ConntrackStatsWithContext(context.Background(), percpu) } func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) { return nil, common.ErrNotImplementedError } // ProtoCounters returns network statistics for the entire system // If protocols is empty then all protocols are returned, otherwise // just the protocols in the list are returned. // Not Implemented for Windows func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) { return ProtoCountersWithContext(context.Background(), protocols) } func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) { return nil, common.ErrNotImplementedError } func getTableUintptr(family uint32, buf []byte) uintptr { var ( pmibTCPTable pmibTCPTableOwnerPidAll pmibTCP6Table pmibTCP6TableOwnerPidAll p uintptr ) switch family { case kindTCP4.family: if len(buf) > 0 { pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0])) p = uintptr(unsafe.Pointer(pmibTCPTable)) } else { p = uintptr(unsafe.Pointer(pmibTCPTable)) } case kindTCP6.family: if len(buf) > 0 { pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0])) p = uintptr(unsafe.Pointer(pmibTCP6Table)) } else { p = uintptr(unsafe.Pointer(pmibTCP6Table)) } } return p } func getTableInfo(filename string, table interface{}) (index, step, length int) { switch filename { case kindTCP4.filename: index = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).DwNumEntries)) step = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).Table)) length = int(table.(pmibTCPTableOwnerPidAll).DwNumEntries) case kindTCP6.filename: index = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).DwNumEntries)) step = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).Table)) length = int(table.(pmibTCP6TableOwnerPidAll).DwNumEntries) case kindUDP4.filename: index = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).DwNumEntries)) step = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).Table)) length = int(table.(pmibUDPTableOwnerPid).DwNumEntries) case kindUDP6.filename: index = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).DwNumEntries)) step = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).Table)) length = int(table.(pmibUDP6TableOwnerPid).DwNumEntries) } return } func getTCPConnections(family uint32) ([]ConnectionStat, error) { var ( p uintptr buf []byte size uint32 pmibTCPTable pmibTCPTableOwnerPidAll pmibTCP6Table pmibTCP6TableOwnerPidAll ) if family == 0 { return nil, fmt.Errorf("faimly must be required") } for { switch family { case kindTCP4.family: if len(buf) > 0 { pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0])) p = uintptr(unsafe.Pointer(pmibTCPTable)) } else { p = uintptr(unsafe.Pointer(pmibTCPTable)) } case kindTCP6.family: if len(buf) > 0 { pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0])) p = uintptr(unsafe.Pointer(pmibTCP6Table)) } else { p = uintptr(unsafe.Pointer(pmibTCP6Table)) } } err := getExtendedTcpTable(p, &size, true, family, tcpTableOwnerPidAll, 0) if err == nil { break } if err != windows.ERROR_INSUFFICIENT_BUFFER { return nil, err } buf = make([]byte, size) } var ( index, step int length int ) stats := make([]ConnectionStat, 0) switch family { case kindTCP4.family: index, step, length = getTableInfo(kindTCP4.filename, pmibTCPTable) case kindTCP6.family: index, step, length = getTableInfo(kindTCP6.filename, pmibTCP6Table) } if length == 0 { return nil, nil } for i := 0; i < length; i++ { switch family { case kindTCP4.family: mibs := (*mibTCPRowOwnerPid)(unsafe.Pointer(&buf[index])) ns := mibs.convertToConnectionStat() stats = append(stats, ns) case kindTCP6.family: mibs := (*mibTCP6RowOwnerPid)(unsafe.Pointer(&buf[index])) ns := mibs.convertToConnectionStat() stats = append(stats, ns) } index += step } return stats, nil } func getUDPConnections(family uint32) ([]ConnectionStat, error) { var ( p uintptr buf []byte size uint32 pmibUDPTable pmibUDPTableOwnerPid pmibUDP6Table pmibUDP6TableOwnerPid ) if family == 0 { return nil, fmt.Errorf("faimly must be required") } for { switch family { case kindUDP4.family: if len(buf) > 0 { pmibUDPTable = (*mibUDPTableOwnerPid)(unsafe.Pointer(&buf[0])) p = uintptr(unsafe.Pointer(pmibUDPTable)) } else { p = uintptr(unsafe.Pointer(pmibUDPTable)) } case kindUDP6.family: if len(buf) > 0 { pmibUDP6Table = (*mibUDP6TableOwnerPid)(unsafe.Pointer(&buf[0])) p = uintptr(unsafe.Pointer(pmibUDP6Table)) } else { p = uintptr(unsafe.Pointer(pmibUDP6Table)) } } err := getExtendedUdpTable( p, &size, true, family, udpTableOwnerPid, 0, ) if err == nil { break } if err != windows.ERROR_INSUFFICIENT_BUFFER { return nil, err } buf = make([]byte, size) } var index, step, length int stats := make([]ConnectionStat, 0) switch family { case kindUDP4.family: index, step, length = getTableInfo(kindUDP4.filename, pmibUDPTable) case kindUDP6.family: index, step, length = getTableInfo(kindUDP6.filename, pmibUDP6Table) } if length == 0 { return nil, nil } for i := 0; i < length; i++ { switch family { case kindUDP4.family: mibs := (*mibUDPRowOwnerPid)(unsafe.Pointer(&buf[index])) ns := mibs.convertToConnectionStat() stats = append(stats, ns) case kindUDP6.family: mibs := (*mibUDP6RowOwnerPid)(unsafe.Pointer(&buf[index])) ns := mibs.convertToConnectionStat() stats = append(stats, ns) } index += step } return stats, nil } // tcpStatuses https://msdn.microsoft.com/en-us/library/windows/desktop/bb485761(v=vs.85).aspx var tcpStatuses = map[mibTCPState]string{ 1: "CLOSED", 2: "LISTEN", 3: "SYN_SENT", 4: "SYN_RECEIVED", 5: "ESTABLISHED", 6: "FIN_WAIT_1", 7: "FIN_WAIT_2", 8: "CLOSE_WAIT", 9: "CLOSING", 10: "LAST_ACK", 11: "TIME_WAIT", 12: "DELETE", } func getExtendedTcpTable(pTcpTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass tcpTableClass, reserved uint32) (errcode error) { r1, _, _ := syscall.Syscall6(procGetExtendedTCPTable.Addr(), 6, pTcpTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved)) if r1 != 0 { errcode = syscall.Errno(r1) } return } func getExtendedUdpTable(pUdpTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass udpTableClass, reserved uint32) (errcode error) { r1, _, _ := syscall.Syscall6(procGetExtendedUDPTable.Addr(), 6, pUdpTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved)) if r1 != 0 { errcode = syscall.Errno(r1) } return } func getUintptrFromBool(b bool) uintptr { if b { return 1 } return 0 } const anySize = 1 // type MIB_TCP_STATE int32 type mibTCPState int32 type tcpTableClass int32 const ( tcpTableBasicListener tcpTableClass = iota tcpTableBasicConnections tcpTableBasicAll tcpTableOwnerPidListener tcpTableOwnerPidConnections tcpTableOwnerPidAll tcpTableOwnerModuleListener tcpTableOwnerModuleConnections tcpTableOwnerModuleAll ) type udpTableClass int32 const ( udpTableBasic udpTableClass = iota udpTableOwnerPid udpTableOwnerModule ) // TCP type mibTCPRowOwnerPid struct { DwState uint32 DwLocalAddr uint32 DwLocalPort uint32 DwRemoteAddr uint32 DwRemotePort uint32 DwOwningPid uint32 } func (m *mibTCPRowOwnerPid) convertToConnectionStat() ConnectionStat { ns := ConnectionStat{ Family: kindTCP4.family, Type: kindTCP4.sockType, Laddr: Addr{ IP: parseIPv4HexString(m.DwLocalAddr), Port: uint32(decodePort(m.DwLocalPort)), }, Raddr: Addr{ IP: parseIPv4HexString(m.DwRemoteAddr), Port: uint32(decodePort(m.DwRemotePort)), }, Pid: int32(m.DwOwningPid), Status: tcpStatuses[mibTCPState(m.DwState)], } return ns } type mibTCPTableOwnerPid struct { DwNumEntries uint32 Table [anySize]mibTCPRowOwnerPid } type mibTCP6RowOwnerPid struct { UcLocalAddr [16]byte DwLocalScopeId uint32 DwLocalPort uint32 UcRemoteAddr [16]byte DwRemoteScopeId uint32 DwRemotePort uint32 DwState uint32 DwOwningPid uint32 } func (m *mibTCP6RowOwnerPid) convertToConnectionStat() ConnectionStat { ns := ConnectionStat{ Family: kindTCP6.family, Type: kindTCP6.sockType, Laddr: Addr{ IP: parseIPv6HexString(m.UcLocalAddr), Port: uint32(decodePort(m.DwLocalPort)), }, Raddr: Addr{ IP: parseIPv6HexString(m.UcRemoteAddr), Port: uint32(decodePort(m.DwRemotePort)), }, Pid: int32(m.DwOwningPid), Status: tcpStatuses[mibTCPState(m.DwState)], } return ns } type mibTCP6TableOwnerPid struct { DwNumEntries uint32 Table [anySize]mibTCP6RowOwnerPid } type ( pmibTCPTableOwnerPidAll *mibTCPTableOwnerPid pmibTCP6TableOwnerPidAll *mibTCP6TableOwnerPid ) // UDP type mibUDPRowOwnerPid struct { DwLocalAddr uint32 DwLocalPort uint32 DwOwningPid uint32 } func (m *mibUDPRowOwnerPid) convertToConnectionStat() ConnectionStat { ns := ConnectionStat{ Family: kindUDP4.family, Type: kindUDP4.sockType, Laddr: Addr{ IP: parseIPv4HexString(m.DwLocalAddr), Port: uint32(decodePort(m.DwLocalPort)), }, Pid: int32(m.DwOwningPid), } return ns } type mibUDPTableOwnerPid struct { DwNumEntries uint32 Table [anySize]mibUDPRowOwnerPid } type mibUDP6RowOwnerPid struct { UcLocalAddr [16]byte DwLocalScopeId uint32 DwLocalPort uint32 DwOwningPid uint32 } func (m *mibUDP6RowOwnerPid) convertToConnectionStat() ConnectionStat { ns := ConnectionStat{ Family: kindUDP6.family, Type: kindUDP6.sockType, Laddr: Addr{ IP: parseIPv6HexString(m.UcLocalAddr), Port: uint32(decodePort(m.DwLocalPort)), }, Pid: int32(m.DwOwningPid), } return ns } type mibUDP6TableOwnerPid struct { DwNumEntries uint32 Table [anySize]mibUDP6RowOwnerPid } type ( pmibUDPTableOwnerPid *mibUDPTableOwnerPid pmibUDP6TableOwnerPid *mibUDP6TableOwnerPid ) func decodePort(port uint32) uint16 { return syscall.Ntohs(uint16(port)) } func parseIPv4HexString(addr uint32) string { return fmt.Sprintf("%d.%d.%d.%d", addr&255, addr>>8&255, addr>>16&255, addr>>24&255) } func parseIPv6HexString(addr [16]byte) string { var ret [16]byte for i := 0; i < 16; i++ { ret[i] = uint8(addr[i]) } // convert []byte to net.IP ip := net.IP(ret[:]) return ip.String() } gopsutil-3.24.1/net/types_darwin.go000066400000000000000000000017441455407747200173210ustar00rootroot00000000000000//go:build ignore // +build ignore // Hand writing: _Ctype_struct___3, 4 /* Input to cgo -godefs. */ package net /* #include #include #include #include enum { sizeofPtr = sizeof(void*), }; */ import "C" // Machine characteristics; for internal use. const ( sizeofPtr = C.sizeofPtr sizeofShort = C.sizeof_short sizeofInt = C.sizeof_int sizeofLong = C.sizeof_long sizeofLongLong = C.sizeof_longlong sizeofLongDouble = C.sizeof_longlong ) // Basic types type ( _C_short C.short _C_int C.int _C_long C.long _C_long_long C.longlong _C_long_double C.longlong ) type ( Xinpgen C.struct_xinpgen Inpcb C.struct_inpcb in_addr C.struct_in_addr Inpcb_list_entry C.struct__inpcb_list_entry Xsocket C.struct_xsocket Xsockbuf C.struct_xsockbuf Xinpcb C.struct_xinpcb ) // type u_quad_t C.struct_u_quad_t gopsutil-3.24.1/process/000077500000000000000000000000001455407747200151445ustar00rootroot00000000000000gopsutil-3.24.1/process/process.go000066400000000000000000000430641455407747200171600ustar00rootroot00000000000000package process import ( "context" "encoding/json" "errors" "runtime" "sort" "sync" "time" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v3/net" ) var ( invoke common.Invoker = common.Invoke{} ErrorNoChildren = errors.New("process does not have children") ErrorProcessNotRunning = errors.New("process does not exist") ErrorNotPermitted = errors.New("operation not permitted") ) type Process struct { Pid int32 `json:"pid"` name string status string parent int32 parentMutex sync.RWMutex // for windows ppid cache numCtxSwitches *NumCtxSwitchesStat uids []int32 gids []int32 groups []int32 numThreads int32 memInfo *MemoryInfoStat sigInfo *SignalInfoStat createTime int64 lastCPUTimes *cpu.TimesStat lastCPUTime time.Time tgid int32 } // Process status const ( // Running marks a task a running or runnable (on the run queue) Running = "running" // Blocked marks a task waiting on a short, uninterruptible operation (usually I/O) Blocked = "blocked" // Idle marks a task sleeping for more than about 20 seconds Idle = "idle" // Lock marks a task waiting to acquire a lock Lock = "lock" // Sleep marks task waiting for short, interruptible operation Sleep = "sleep" // Stop marks a stopped process Stop = "stop" // Wait marks an idle interrupt thread (or paging in pre 2.6.xx Linux) Wait = "wait" // Zombie marks a defunct process, terminated but not reaped by its parent Zombie = "zombie" // Solaris states. See https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115 Daemon = "daemon" Detached = "detached" System = "system" Orphan = "orphan" UnknownState = "" ) type OpenFilesStat struct { Path string `json:"path"` Fd uint64 `json:"fd"` } type MemoryInfoStat struct { RSS uint64 `json:"rss"` // bytes VMS uint64 `json:"vms"` // bytes HWM uint64 `json:"hwm"` // bytes Data uint64 `json:"data"` // bytes Stack uint64 `json:"stack"` // bytes Locked uint64 `json:"locked"` // bytes Swap uint64 `json:"swap"` // bytes } type SignalInfoStat struct { PendingProcess uint64 `json:"pending_process"` PendingThread uint64 `json:"pending_thread"` Blocked uint64 `json:"blocked"` Ignored uint64 `json:"ignored"` Caught uint64 `json:"caught"` } type RlimitStat struct { Resource int32 `json:"resource"` Soft uint64 `json:"soft"` Hard uint64 `json:"hard"` Used uint64 `json:"used"` } type IOCountersStat struct { ReadCount uint64 `json:"readCount"` WriteCount uint64 `json:"writeCount"` ReadBytes uint64 `json:"readBytes"` WriteBytes uint64 `json:"writeBytes"` } type NumCtxSwitchesStat struct { Voluntary int64 `json:"voluntary"` Involuntary int64 `json:"involuntary"` } type PageFaultsStat struct { MinorFaults uint64 `json:"minorFaults"` MajorFaults uint64 `json:"majorFaults"` ChildMinorFaults uint64 `json:"childMinorFaults"` ChildMajorFaults uint64 `json:"childMajorFaults"` } // Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h // from libc6-dev package in Ubuntu 16.10 const ( RLIMIT_CPU int32 = 0 RLIMIT_FSIZE int32 = 1 RLIMIT_DATA int32 = 2 RLIMIT_STACK int32 = 3 RLIMIT_CORE int32 = 4 RLIMIT_RSS int32 = 5 RLIMIT_NPROC int32 = 6 RLIMIT_NOFILE int32 = 7 RLIMIT_MEMLOCK int32 = 8 RLIMIT_AS int32 = 9 RLIMIT_LOCKS int32 = 10 RLIMIT_SIGPENDING int32 = 11 RLIMIT_MSGQUEUE int32 = 12 RLIMIT_NICE int32 = 13 RLIMIT_RTPRIO int32 = 14 RLIMIT_RTTIME int32 = 15 ) func (p Process) String() string { s, _ := json.Marshal(p) return string(s) } func (o OpenFilesStat) String() string { s, _ := json.Marshal(o) return string(s) } func (m MemoryInfoStat) String() string { s, _ := json.Marshal(m) return string(s) } func (r RlimitStat) String() string { s, _ := json.Marshal(r) return string(s) } func (i IOCountersStat) String() string { s, _ := json.Marshal(i) return string(s) } func (p NumCtxSwitchesStat) String() string { s, _ := json.Marshal(p) 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. func Pids() ([]int32, error) { return PidsWithContext(context.Background()) } func PidsWithContext(ctx context.Context) ([]int32, error) { pids, err := pidsWithContext(ctx) sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] }) return pids, err } // Processes returns a slice of pointers to Process structs for all // currently running processes. func Processes() ([]*Process, error) { return ProcessesWithContext(context.Background()) } // NewProcess creates a new Process instance, it only stores the pid and // checks that the process exists. Other method on Process can be used // to get more information about the process. An error will be returned // if the process does not exist. func NewProcess(pid int32) (*Process, error) { return NewProcessWithContext(context.Background(), pid) } func NewProcessWithContext(ctx context.Context, pid int32) (*Process, error) { p := &Process{ Pid: pid, } exists, err := PidExistsWithContext(ctx, pid) if err != nil { return p, err } if !exists { return p, ErrorProcessNotRunning } p.CreateTimeWithContext(ctx) return p, nil } func PidExists(pid int32) (bool, error) { return PidExistsWithContext(context.Background(), pid) } // Background returns true if the process is in background, false otherwise. func (p *Process) Background() (bool, error) { return p.BackgroundWithContext(context.Background()) } func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) { fg, err := p.ForegroundWithContext(ctx) if err != nil { return false, err } return !fg, err } // If interval is 0, return difference from last call(non-blocking). // If interval > 0, wait interval sec and return difference between start and end. func (p *Process) Percent(interval time.Duration) (float64, error) { return p.PercentWithContext(context.Background(), interval) } func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) { cpuTimes, err := p.TimesWithContext(ctx) if err != nil { return 0, err } now := time.Now() if interval > 0 { p.lastCPUTimes = cpuTimes p.lastCPUTime = now if err := common.Sleep(ctx, interval); err != nil { return 0, err } cpuTimes, err = p.TimesWithContext(ctx) now = time.Now() if err != nil { return 0, err } } else { if p.lastCPUTimes == nil { // invoked first time p.lastCPUTimes = cpuTimes p.lastCPUTime = now return 0, nil } } numcpu := runtime.NumCPU() delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu) ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu) p.lastCPUTimes = cpuTimes p.lastCPUTime = now return ret, nil } // IsRunning returns whether the process is still running or not. func (p *Process) IsRunning() (bool, error) { return p.IsRunningWithContext(context.Background()) } func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) { createTime, err := p.CreateTimeWithContext(ctx) if err != nil { return false, err } p2, err := NewProcessWithContext(ctx, p.Pid) if errors.Is(err, ErrorProcessNotRunning) { return false, nil } createTime2, err := p2.CreateTimeWithContext(ctx) if err != nil { return false, err } return createTime == createTime2, nil } // CreateTime returns created time of the process in milliseconds since the epoch, in UTC. func (p *Process) CreateTime() (int64, error) { return p.CreateTimeWithContext(context.Background()) } func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) { if p.createTime != 0 { return p.createTime, nil } createTime, err := p.createTimeWithContext(ctx) p.createTime = createTime return p.createTime, err } func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 { if delta == 0 { return 0 } delta_proc := t2.Total() - t1.Total() overall_percent := ((delta_proc / delta) * 100) * float64(numcpu) return overall_percent } // MemoryPercent returns how many percent of the total RAM this process uses func (p *Process) MemoryPercent() (float32, error) { return p.MemoryPercentWithContext(context.Background()) } func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) { machineMemory, err := mem.VirtualMemoryWithContext(ctx) if err != nil { return 0, err } total := machineMemory.Total processMemory, err := p.MemoryInfoWithContext(ctx) if err != nil { return 0, err } used := processMemory.RSS return (100 * float32(used) / float32(total)), nil } // CPUPercent returns how many percent of the CPU time this process uses func (p *Process) CPUPercent() (float64, error) { return p.CPUPercentWithContext(context.Background()) } func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) { crt_time, err := p.createTimeWithContext(ctx) if err != nil { return 0, err } cput, err := p.TimesWithContext(ctx) if err != nil { return 0, err } created := time.Unix(0, crt_time*int64(time.Millisecond)) totalTime := time.Since(created).Seconds() if totalTime <= 0 { return 0, nil } return 100 * cput.Total() / totalTime, nil } // Groups returns all group IDs(include supplementary groups) of the process as a slice of the int func (p *Process) Groups() ([]int32, error) { return p.GroupsWithContext(context.Background()) } // Ppid returns Parent Process ID of the process. func (p *Process) Ppid() (int32, error) { return p.PpidWithContext(context.Background()) } // Name returns name of the process. func (p *Process) Name() (string, error) { return p.NameWithContext(context.Background()) } // Exe returns executable path of the process. func (p *Process) Exe() (string, error) { return p.ExeWithContext(context.Background()) } // Cmdline returns the command line arguments of the process as a string with // each argument separated by 0x20 ascii character. func (p *Process) Cmdline() (string, error) { return p.CmdlineWithContext(context.Background()) } // CmdlineSlice returns the command line arguments of the process as a slice with each // element being an argument. func (p *Process) CmdlineSlice() ([]string, error) { return p.CmdlineSliceWithContext(context.Background()) } // Cwd returns current working directory of the process. func (p *Process) Cwd() (string, error) { return p.CwdWithContext(context.Background()) } // Parent returns parent Process of the process. func (p *Process) Parent() (*Process, error) { return p.ParentWithContext(context.Background()) } // ParentWithContext returns parent Process of the process. func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { ppid, err := p.PpidWithContext(ctx) if err != nil { return nil, err } return NewProcessWithContext(ctx, ppid) } // Status returns the process status. // Return value could be one of these. // R: Running S: Sleep T: Stop I: Idle // Z: Zombie W: Wait L: Lock // The character is same within all supported platforms. func (p *Process) Status() ([]string, error) { return p.StatusWithContext(context.Background()) } // Foreground returns true if the process is in foreground, false otherwise. func (p *Process) Foreground() (bool, error) { return p.ForegroundWithContext(context.Background()) } // Uids returns user ids of the process as a slice of the int func (p *Process) Uids() ([]int32, error) { return p.UidsWithContext(context.Background()) } // Gids returns group ids of the process as a slice of the int func (p *Process) Gids() ([]int32, error) { return p.GidsWithContext(context.Background()) } // Terminal returns a terminal which is associated with the process. func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } // Nice returns a nice value (priority). func (p *Process) Nice() (int32, error) { return p.NiceWithContext(context.Background()) } // IOnice returns process I/O nice value (priority). func (p *Process) IOnice() (int32, error) { return p.IOniceWithContext(context.Background()) } // Rlimit returns Resource Limits. func (p *Process) Rlimit() ([]RlimitStat, error) { return p.RlimitWithContext(context.Background()) } // RlimitUsage returns Resource Limits. // If gatherUsed is true, the currently used value will be gathered and added // to the resulting RlimitStat. func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) { return p.RlimitUsageWithContext(context.Background(), gatherUsed) } // IOCounters returns IO Counters. func (p *Process) IOCounters() (*IOCountersStat, error) { return p.IOCountersWithContext(context.Background()) } // NumCtxSwitches returns the number of the context switches of the process. func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { return p.NumCtxSwitchesWithContext(context.Background()) } // NumFDs returns the number of File Descriptors used by the process. func (p *Process) NumFDs() (int32, error) { return p.NumFDsWithContext(context.Background()) } // NumThreads returns the number of threads used by the process. func (p *Process) NumThreads() (int32, error) { return p.NumThreadsWithContext(context.Background()) } func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) { return p.ThreadsWithContext(context.Background()) } // Times returns CPU times of the process. func (p *Process) Times() (*cpu.TimesStat, error) { return p.TimesWithContext(context.Background()) } // CPUAffinity returns CPU affinity of the process. func (p *Process) CPUAffinity() ([]int32, error) { return p.CPUAffinityWithContext(context.Background()) } // MemoryInfo returns generic process memory information, // such as RSS and VMS. func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { return p.MemoryInfoWithContext(context.Background()) } // MemoryInfoEx returns platform-specific process memory information. func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { return p.MemoryInfoExWithContext(context.Background()) } // PageFaults returns the process's page fault counters. func (p *Process) PageFaults() (*PageFaultsStat, error) { return p.PageFaultsWithContext(context.Background()) } // Children returns the children of the process represented as a slice // of pointers to Process type. func (p *Process) Children() ([]*Process, error) { return p.ChildrenWithContext(context.Background()) } // OpenFiles returns a slice of OpenFilesStat opend by the process. // OpenFilesStat includes a file path and file descriptor. func (p *Process) OpenFiles() ([]OpenFilesStat, error) { return p.OpenFilesWithContext(context.Background()) } // Connections returns a slice of net.ConnectionStat used by the process. // This returns all kind of the connection. This means TCP, UDP or UNIX. func (p *Process) Connections() ([]net.ConnectionStat, error) { return p.ConnectionsWithContext(context.Background()) } // ConnectionsMax returns a slice of net.ConnectionStat used by the process at most `max`. func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) { return p.ConnectionsMaxWithContext(context.Background(), max) } // MemoryMaps get memory maps from /proc/(pid)/smaps func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) { return p.MemoryMapsWithContext(context.Background(), grouped) } // Tgid returns thread group id of the process. func (p *Process) Tgid() (int32, error) { return p.TgidWithContext(context.Background()) } // SendSignal sends a unix.Signal to the process. func (p *Process) SendSignal(sig Signal) error { return p.SendSignalWithContext(context.Background(), sig) } // Suspend sends SIGSTOP to the process. func (p *Process) Suspend() error { return p.SuspendWithContext(context.Background()) } // Resume sends SIGCONT to the process. func (p *Process) Resume() error { return p.ResumeWithContext(context.Background()) } // Terminate sends SIGTERM to the process. func (p *Process) Terminate() error { return p.TerminateWithContext(context.Background()) } // Kill sends SIGKILL to the process. func (p *Process) Kill() error { return p.KillWithContext(context.Background()) } // Username returns a username of the process. func (p *Process) Username() (string, error) { return p.UsernameWithContext(context.Background()) } // Environ returns the environment variables of the process. func (p *Process) Environ() ([]string, error) { return p.EnvironWithContext(context.Background()) } // convertStatusChar as reported by the ps command across different platforms. func convertStatusChar(letter string) string { // Sources // Darwin: http://www.mywebuniversity.com/Man_Pages/Darwin/man_ps.html // FreeBSD: https://www.freebsd.org/cgi/man.cgi?ps // Linux https://man7.org/linux/man-pages/man1/ps.1.html // OpenBSD: https://man.openbsd.org/ps.1#state // Solaris: https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115 switch letter { case "A": return Daemon case "D", "U": return Blocked case "E": return Detached case "I": return Idle case "L": return Lock case "O": return Orphan case "R": return Running case "S": return Sleep case "T", "t": // "t" is used by Linux to signal stopped by the debugger during tracing return Stop case "W": return Wait case "Y": return System case "Z": return Zombie default: return UnknownState } } gopsutil-3.24.1/process/process_bsd.go000066400000000000000000000041731455407747200200060ustar00rootroot00000000000000//go:build darwin || freebsd || openbsd // +build darwin freebsd openbsd package process import ( "bytes" "context" "encoding/binary" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" ) type MemoryInfoExStat struct{} type MemoryMapsStat struct{} func (p *Process) TgidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { return nil, common.ErrNotImplementedError } func parseKinfoProc(buf []byte) (KinfoProc, error) { var k KinfoProc br := bytes.NewReader(buf) err := common.Read(br, binary.LittleEndian, &k) return k, err } gopsutil-3.24.1/process/process_darwin.go000066400000000000000000000164301455407747200205210ustar00rootroot00000000000000//go:build darwin // +build darwin package process import ( "context" "fmt" "path/filepath" "strconv" "strings" "github.com/tklauser/go-sysconf" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/net" ) // copied from sys/sysctl.h const ( CTLKern = 1 // "high kernel": proc, limits KernProc = 14 // struct: process entries KernProcPID = 1 // by process id KernProcProc = 8 // only return procs KernProcAll = 0 // everything KernProcPathname = 12 // path to executable ) var clockTicks = 100 // default value func init() { clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK) // ignore errors if err == nil { clockTicks = int(clkTck) } } type _Ctype_struct___0 struct { Pad uint64 } func pidsWithContext(ctx context.Context) ([]int32, error) { var ret []int32 kprocs, err := unix.SysctlKinfoProcSlice("kern.proc.all") if err != nil { return ret, err } for _, proc := range kprocs { ret = append(ret, int32(proc.Proc.P_pid)) } return ret, nil } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { k, err := p.getKProc() if err != nil { return 0, err } return k.Eproc.Ppid, nil } func (p *Process) NameWithContext(ctx context.Context) (string, error) { k, err := p.getKProc() if err != nil { return "", err } name := common.ByteToString(k.Proc.P_comm[:]) if len(name) >= 15 { cmdName, err := p.cmdNameWithContext(ctx) if err != nil { return "", err } if len(cmdName) > 0 { extendedName := filepath.Base(cmdName) if strings.HasPrefix(extendedName, p.name) { name = extendedName } } } return name, nil } func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { k, err := p.getKProc() if err != nil { return 0, err } return k.Proc.P_starttime.Sec*1000 + int64(k.Proc.P_starttime.Usec)/1000, nil } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { r, err := callPsWithContext(ctx, "state", p.Pid, false, false) if err != nil { return []string{""}, err } status := convertStatusChar(r[0][0][0:1]) return []string{status}, err } func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details pid := p.Pid out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid))) if err != nil { return false, err } return strings.IndexByte(string(out), '+') != -1, nil } func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { return nil, err } // See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html userEffectiveUID := int32(k.Eproc.Ucred.Uid) return []int32{userEffectiveUID}, nil } func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { return nil, err } gids := make([]int32, 0, 3) gids = append(gids, int32(k.Eproc.Pcred.P_rgid), int32(k.Eproc.Pcred.P_rgid), int32(k.Eproc.Pcred.P_svgid)) return gids, nil } func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError // k, err := p.getKProc() // if err != nil { // return nil, err // } // groups := make([]int32, k.Eproc.Ucred.Ngroups) // for i := int16(0); i < k.Eproc.Ucred.Ngroups; i++ { // groups[i] = int32(k.Eproc.Ucred.Groups[i]) // } // return groups, nil } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError /* k, err := p.getKProc() if err != nil { return "", err } ttyNr := uint64(k.Eproc.Tdev) termmap, err := getTerminalMap() if err != nil { return "", err } return termmap[ttyNr], nil */ } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { k, err := p.getKProc() if err != nil { return 0, err } return int32(k.Proc.P_nice), nil } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { return nil, common.ErrNotImplementedError } func convertCPUTimes(s string) (ret float64, err error) { var t int var _tmp string if strings.Contains(s, ":") { _t := strings.Split(s, ":") switch len(_t) { case 3: hour, err := strconv.Atoi(_t[0]) if err != nil { return ret, err } t += hour * 60 * 60 * clockTicks mins, err := strconv.Atoi(_t[1]) if err != nil { return ret, err } t += mins * 60 * clockTicks _tmp = _t[2] case 2: mins, err := strconv.Atoi(_t[0]) if err != nil { return ret, err } t += mins * 60 * clockTicks _tmp = _t[1] case 1, 0: _tmp = s default: return ret, fmt.Errorf("wrong cpu time string") } } else { _tmp = s } _t := strings.Split(_tmp, ".") if err != nil { return ret, err } h, err := strconv.Atoi(_t[0]) t += h * clockTicks h, err = strconv.Atoi(_t[1]) t += h return float64(t) / float64(clockTicks), nil } func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid) if err != nil { return nil, err } ret := make([]*Process, 0, len(pids)) for _, pid := range pids { np, err := NewProcessWithContext(ctx, pid) if err != nil { return nil, err } ret = append(ret, np) } return ret, nil } func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { return net.ConnectionsPidWithContext(ctx, "all", p.Pid) } func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, max) } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { out := []*Process{} pids, err := PidsWithContext(ctx) if err != nil { return out, err } for _, pid := range pids { p, err := NewProcessWithContext(ctx, pid) if err != nil { continue } out = append(out, p) } return out, nil } // Returns a proc as defined here: // http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html func (p *Process) getKProc() (*unix.KinfoProc, error) { return unix.SysctlKinfoProc("kern.proc.pid", int(p.Pid)) } // call ps command. // Return value deletes Header line(you must not input wrong arg). // And splited by Space. Caller have responsibility to manage. // If passed arg pid is 0, get information from all process. func callPsWithContext(ctx context.Context, arg string, pid int32, threadOption bool, nameOption bool) ([][]string, error) { var cmd []string if pid == 0 { // will get from all processes. cmd = []string{"-ax", "-o", arg} } else if threadOption { cmd = []string{"-x", "-o", arg, "-M", "-p", strconv.Itoa(int(pid))} } else { cmd = []string{"-x", "-o", arg, "-p", strconv.Itoa(int(pid))} } if nameOption { cmd = append(cmd, "-c") } out, err := invoke.CommandWithContext(ctx, "ps", cmd...) if err != nil { return [][]string{}, err } lines := strings.Split(string(out), "\n") var ret [][]string for _, l := range lines[1:] { var lr []string if nameOption { lr = append(lr, l) } else { for _, r := range strings.Split(l, " ") { if r == "" { continue } lr = append(lr, strings.TrimSpace(r)) } } if len(lr) != 0 { ret = append(ret, lr) } } return ret, nil } gopsutil-3.24.1/process/process_darwin_amd64.go000066400000000000000000000070201455407747200215070ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_darwin.go package process const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 ) 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 int32 Pad_cgo_0 [4]byte } 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 UGid_t uint32 type KinfoProc struct { Proc ExternProc Eproc Eproc } type Eproc struct { Paddr *uint64 Sess *Session Pcred Upcred Ucred Uucred Pad_cgo_0 [4]byte Vm Vmspace Ppid int32 Pgid int32 Jobc int16 Pad_cgo_1 [2]byte Tdev int32 Tpgid int32 Pad_cgo_2 [4]byte Tsess *Session Wmesg [8]int8 Xsize int32 Xrssize int16 Xccount int16 Xswrss int16 Pad_cgo_3 [2]byte Flag int32 Login [12]int8 Spare [4]int32 Pad_cgo_4 [4]byte } type Proc struct{} type Session struct{} type ucred struct { Link _Ctype_struct___0 Ref uint64 Posix Posix_cred Label *Label Audit Au_session } type Uucred struct { Ref int32 UID uint32 Ngroups int16 Pad_cgo_0 [2]byte Groups [16]uint32 } type Upcred struct { Pc_lock [72]int8 Pc_ucred *ucred P_ruid uint32 P_svuid uint32 P_rgid uint32 P_svgid uint32 P_refcnt int32 Pad_cgo_0 [4]byte } type Vmspace struct { Dummy int32 Pad_cgo_0 [4]byte Dummy2 *int8 Dummy3 [5]int32 Pad_cgo_1 [4]byte Dummy4 [3]*int8 } type Sigacts struct{} type ExternProc struct { P_un [16]byte P_vmspace uint64 P_sigacts uint64 Pad_cgo_0 [3]byte P_flag int32 P_stat int8 P_pid int32 P_oppid int32 P_dupfd int32 Pad_cgo_1 [4]byte User_stack uint64 Exit_thread uint64 P_debugger int32 Sigwait int32 P_estcpu uint32 P_cpticks int32 P_pctcpu uint32 Pad_cgo_2 [4]byte P_wchan uint64 P_wmesg uint64 P_swtime uint32 P_slptime uint32 P_realtimer Itimerval P_rtime Timeval P_uticks uint64 P_sticks uint64 P_iticks uint64 P_traceflag int32 Pad_cgo_3 [4]byte P_tracep uint64 P_siglist int32 Pad_cgo_4 [4]byte P_textvp uint64 P_holdcnt int32 P_sigmask uint32 P_sigignore uint32 P_sigcatch uint32 P_priority uint8 P_usrpri uint8 P_nice int8 P_comm [17]int8 Pad_cgo_5 [4]byte P_pgrp uint64 P_addr uint64 P_xstat uint16 P_acflag uint16 Pad_cgo_6 [4]byte P_ru uint64 } type Itimerval struct { Interval Timeval Value Timeval } type Vnode struct{} type Pgrp struct{} type UserStruct struct{} type Au_session struct { Aia_p *AuditinfoAddr Mask AuMask } type Posix_cred struct { UID uint32 Ruid uint32 Svuid uint32 Ngroups int16 Pad_cgo_0 [2]byte Groups [16]uint32 Rgid uint32 Svgid uint32 Gmuid uint32 Flags int32 } type Label struct{} type AuditinfoAddr struct { Auid uint32 Mask AuMask Termid AuTidAddr Asid int32 Flags uint64 } type AuMask struct { Success uint32 Failure uint32 } type AuTidAddr struct { Port int32 Type uint32 Addr [4]uint32 } type UcredQueue struct { Next *ucred Prev **ucred } gopsutil-3.24.1/process/process_darwin_arm64.go000066400000000000000000000062451455407747200215350ustar00rootroot00000000000000//go:build darwin && arm64 // +build darwin,arm64 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs process/types_darwin.go package process const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 ) 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 int32 Pad_cgo_0 [4]byte } 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 UGid_t uint32 type KinfoProc struct { Proc ExternProc Eproc Eproc } type Eproc struct { Paddr *Proc Sess *Session Pcred Upcred Ucred Uucred Vm Vmspace Ppid int32 Pgid int32 Jobc int16 Tdev int32 Tpgid int32 Tsess *Session Wmesg [8]int8 Xsize int32 Xrssize int16 Xccount int16 Xswrss int16 Flag int32 Login [12]int8 Spare [4]int32 Pad_cgo_0 [4]byte } type Proc struct{} type Session struct{} type ucred struct{} type Uucred struct { Ref int32 UID uint32 Ngroups int16 Groups [16]uint32 } type Upcred struct { Pc_lock [72]int8 Pc_ucred *ucred P_ruid uint32 P_svuid uint32 P_rgid uint32 P_svgid uint32 P_refcnt int32 Pad_cgo_0 [4]byte } type Vmspace struct { Dummy int32 Dummy2 *int8 Dummy3 [5]int32 Dummy4 [3]*int8 } type Sigacts struct{} type ExternProc struct { P_un [16]byte P_vmspace uint64 P_sigacts uint64 Pad_cgo_0 [3]byte P_flag int32 P_stat int8 P_pid int32 P_oppid int32 P_dupfd int32 Pad_cgo_1 [4]byte User_stack uint64 Exit_thread uint64 P_debugger int32 Sigwait int32 P_estcpu uint32 P_cpticks int32 P_pctcpu uint32 Pad_cgo_2 [4]byte P_wchan uint64 P_wmesg uint64 P_swtime uint32 P_slptime uint32 P_realtimer Itimerval P_rtime Timeval P_uticks uint64 P_sticks uint64 P_iticks uint64 P_traceflag int32 Pad_cgo_3 [4]byte P_tracep uint64 P_siglist int32 Pad_cgo_4 [4]byte P_textvp uint64 P_holdcnt int32 P_sigmask uint32 P_sigignore uint32 P_sigcatch uint32 P_priority uint8 P_usrpri uint8 P_nice int8 P_comm [17]int8 Pad_cgo_5 [4]byte P_pgrp uint64 P_addr uint64 P_xstat uint16 P_acflag uint16 Pad_cgo_6 [4]byte P_ru uint64 } type Itimerval struct { Interval Timeval Value Timeval } type Vnode struct{} type Pgrp struct{} type UserStruct struct{} type Au_session struct { Aia_p *AuditinfoAddr Mask AuMask } type Posix_cred struct{} type Label struct{} type AuditinfoAddr struct { Auid uint32 Mask AuMask Termid AuTidAddr Asid int32 Flags uint64 } type AuMask struct { Success uint32 Failure uint32 } type AuTidAddr struct { Port int32 Type uint32 Addr [4]uint32 } type UcredQueue struct { Next *ucred Prev **ucred } gopsutil-3.24.1/process/process_darwin_cgo.go000066400000000000000000000137631455407747200213570ustar00rootroot00000000000000//go:build darwin && cgo // +build darwin,cgo package process // #include // #include // #include // #include // #include // #include // #include import "C" import ( "bytes" "context" "fmt" "strings" "syscall" "unsafe" "github.com/shirou/gopsutil/v3/cpu" ) var ( argMax int timescaleToNanoSeconds float64 ) func init() { argMax = getArgMax() timescaleToNanoSeconds = getTimeScaleToNanoSeconds() } func getArgMax() int { var ( mib = [...]C.int{C.CTL_KERN, C.KERN_ARGMAX} argmax C.int size C.size_t = C.ulong(unsafe.Sizeof(argmax)) ) retval := C.sysctl(&mib[0], 2, unsafe.Pointer(&argmax), &size, C.NULL, 0) if retval == 0 { return int(argmax) } return 0 } func getTimeScaleToNanoSeconds() float64 { var timeBaseInfo C.struct_mach_timebase_info C.mach_timebase_info(&timeBaseInfo) return float64(timeBaseInfo.numer) / float64(timeBaseInfo.denom) } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { var c C.char // need a var for unsafe.Sizeof need a var const bufsize = C.PROC_PIDPATHINFO_MAXSIZE * unsafe.Sizeof(c) buffer := (*C.char)(C.malloc(C.size_t(bufsize))) defer C.free(unsafe.Pointer(buffer)) ret, err := C.proc_pidpath(C.int(p.Pid), unsafe.Pointer(buffer), C.uint32_t(bufsize)) if err != nil { return "", err } if ret <= 0 { return "", fmt.Errorf("unknown error: proc_pidpath returned %d", ret) } return C.GoString(buffer), nil } // CwdWithContext retrieves the Current Working Directory for the given process. // It uses the proc_pidinfo from libproc and will only work for processes the // EUID can access. Otherwise "operation not permitted" will be returned as the // error. // Note: This might also work for other *BSD OSs. func (p *Process) CwdWithContext(ctx context.Context) (string, error) { const vpiSize = C.sizeof_struct_proc_vnodepathinfo vpi := (*C.struct_proc_vnodepathinfo)(C.malloc(vpiSize)) defer C.free(unsafe.Pointer(vpi)) ret, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDVNODEPATHINFO, 0, unsafe.Pointer(vpi), vpiSize) if err != nil { // fmt.Printf("ret: %d %T\n", ret, err) if err == syscall.EPERM { return "", ErrorNotPermitted } return "", err } if ret <= 0 { return "", fmt.Errorf("unknown error: proc_pidinfo returned %d", ret) } if ret != C.sizeof_struct_proc_vnodepathinfo { return "", fmt.Errorf("too few bytes; expected %d, got %d", vpiSize, ret) } return C.GoString(&vpi.pvi_cdir.vip_path[0]), err } func procArgs(pid int32) ([]byte, int, error) { var ( mib = [...]C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)} size C.size_t = C.ulong(argMax) nargs C.int result []byte ) procargs := (*C.char)(C.malloc(C.ulong(argMax))) defer C.free(unsafe.Pointer(procargs)) retval, err := C.sysctl(&mib[0], 3, unsafe.Pointer(procargs), &size, C.NULL, 0) if retval == 0 { C.memcpy(unsafe.Pointer(&nargs), unsafe.Pointer(procargs), C.sizeof_int) result = C.GoBytes(unsafe.Pointer(procargs), C.int(size)) // fmt.Printf("size: %d %d\n%s\n", size, nargs, hex.Dump(result)) return result, int(nargs), nil } return nil, 0, err } func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { return p.cmdlineSliceWithContext(ctx, true) } func (p *Process) cmdlineSliceWithContext(ctx context.Context, fallback bool) ([]string, error) { pargs, nargs, err := procArgs(p.Pid) if err != nil { return nil, err } // The first bytes hold the nargs int, skip it. args := bytes.Split((pargs)[C.sizeof_int:], []byte{0}) var argStr string // The first element is the actual binary/command path. // command := args[0] var argSlice []string // var envSlice []string // All other, non-zero elements are arguments. The first "nargs" elements // are the arguments. Everything else in the slice is then the environment // of the process. for _, arg := range args[1:] { argStr = string(arg[:]) if len(argStr) > 0 { if nargs > 0 { argSlice = append(argSlice, argStr) nargs-- continue } break // envSlice = append(envSlice, argStr) } } return argSlice, err } // cmdNameWithContext returns the command name (including spaces) without any arguments func (p *Process) cmdNameWithContext(ctx context.Context) (string, error) { r, err := p.cmdlineSliceWithContext(ctx, false) if err != nil { return "", err } if len(r) == 0 { return "", nil } return r[0], err } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { r, err := p.CmdlineSliceWithContext(ctx) if err != nil { return "", err } return strings.Join(r, " "), err } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { const tiSize = C.sizeof_struct_proc_taskinfo ti := (*C.struct_proc_taskinfo)(C.malloc(tiSize)) defer C.free(unsafe.Pointer(ti)) _, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDTASKINFO, 0, unsafe.Pointer(ti), tiSize) if err != nil { return 0, err } return int32(ti.pti_threadnum), nil } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { const tiSize = C.sizeof_struct_proc_taskinfo ti := (*C.struct_proc_taskinfo)(C.malloc(tiSize)) defer C.free(unsafe.Pointer(ti)) _, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDTASKINFO, 0, unsafe.Pointer(ti), tiSize) if err != nil { return nil, err } ret := &cpu.TimesStat{ CPU: "cpu", User: float64(ti.pti_total_user) * timescaleToNanoSeconds / 1e9, System: float64(ti.pti_total_system) * timescaleToNanoSeconds / 1e9, } return ret, nil } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { const tiSize = C.sizeof_struct_proc_taskinfo ti := (*C.struct_proc_taskinfo)(C.malloc(tiSize)) defer C.free(unsafe.Pointer(ti)) _, err := C.proc_pidinfo(C.int(p.Pid), C.PROC_PIDTASKINFO, 0, unsafe.Pointer(ti), tiSize) if err != nil { return nil, err } ret := &MemoryInfoStat{ RSS: uint64(ti.pti_resident_size), VMS: uint64(ti.pti_virtual_size), Swap: uint64(ti.pti_pageins), } return ret, nil } gopsutil-3.24.1/process/process_darwin_nocgo.go000066400000000000000000000060551455407747200217100ustar00rootroot00000000000000//go:build darwin && !cgo // +build darwin,!cgo package process import ( "context" "fmt" "strconv" "strings" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" ) func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { out, err := invoke.CommandWithContext(ctx, "lsof", "-p", strconv.Itoa(int(p.Pid)), "-Fpfn") if err != nil { return "", fmt.Errorf("bad call to lsof: %s", err) } txtFound := 0 lines := strings.Split(string(out), "\n") for i := 1; i < len(lines); i++ { if lines[i] == "ftxt" { txtFound++ if txtFound == 2 { return lines[i-1][1:], nil } } } return "", fmt.Errorf("missing txt data returned by lsof") } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { r, err := callPsWithContext(ctx, "command", p.Pid, false, false) if err != nil { return "", err } return strings.Join(r[0], " "), err } func (p *Process) cmdNameWithContext(ctx context.Context) (string, error) { r, err := callPsWithContext(ctx, "command", p.Pid, false, true) if err != nil { return "", err } if len(r) > 0 && len(r[0]) > 0 { return r[0][0], err } return "", err } // CmdlineSliceWithContext returns the command line arguments of the process as a slice with each // element being an argument. Because of current deficiencies in the way that the command // line arguments are found, single arguments that have spaces in the will actually be // reported as two separate items. In order to do something better CGO would be needed // to use the native darwin functions. func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { r, err := callPsWithContext(ctx, "command", p.Pid, false, false) if err != nil { return nil, err } return r[0], err } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { r, err := callPsWithContext(ctx, "utime,stime", p.Pid, true, false) if err != nil { return 0, err } return int32(len(r)), nil } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { r, err := callPsWithContext(ctx, "utime,stime", p.Pid, false, false) if err != nil { return nil, err } utime, err := convertCPUTimes(r[0][0]) if err != nil { return nil, err } stime, err := convertCPUTimes(r[0][1]) if err != nil { return nil, err } ret := &cpu.TimesStat{ CPU: "cpu", User: utime, System: stime, } return ret, nil } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { r, err := callPsWithContext(ctx, "rss,vsize,pagein", p.Pid, false, false) if err != nil { return nil, err } rss, err := strconv.Atoi(r[0][0]) if err != nil { return nil, err } vms, err := strconv.Atoi(r[0][1]) if err != nil { return nil, err } pagein, err := strconv.Atoi(r[0][2]) if err != nil { return nil, err } ret := &MemoryInfoStat{ RSS: uint64(rss) * 1024, VMS: uint64(vms) * 1024, Swap: uint64(pagein), } return ret, nil } gopsutil-3.24.1/process/process_fallback.go000066400000000000000000000141041455407747200207700ustar00rootroot00000000000000//go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !plan9 // +build !darwin,!linux,!freebsd,!openbsd,!windows,!solaris,!plan9 package process import ( "context" "syscall" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/net" ) type Signal = syscall.Signal type MemoryMapsStat struct { Path string `json:"path"` Rss uint64 `json:"rss"` Size uint64 `json:"size"` Pss uint64 `json:"pss"` SharedClean uint64 `json:"sharedClean"` SharedDirty uint64 `json:"sharedDirty"` PrivateClean uint64 `json:"privateClean"` PrivateDirty uint64 `json:"privateDirty"` Referenced uint64 `json:"referenced"` Anonymous uint64 `json:"anonymous"` Swap uint64 `json:"swap"` } type MemoryInfoExStat struct{} func pidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { return nil, common.ErrNotImplementedError } func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { return false, common.ErrNotImplementedError } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) NameWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) TgidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { return nil, common.ErrNotImplementedError } func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { return 0, common.ErrNotImplementedError } func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { return []string{""}, common.ErrNotImplementedError } func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { return false, common.ErrNotImplementedError } func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { return nil, common.ErrNotImplementedError } func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) SendSignalWithContext(ctx context.Context, sig Signal) error { return common.ErrNotImplementedError } func (p *Process) SuspendWithContext(ctx context.Context) error { return common.ErrNotImplementedError } func (p *Process) ResumeWithContext(ctx context.Context) error { return common.ErrNotImplementedError } func (p *Process) TerminateWithContext(ctx context.Context) error { return common.ErrNotImplementedError } func (p *Process) KillWithContext(ctx context.Context) error { return common.ErrNotImplementedError } func (p *Process) UsernameWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/process/process_freebsd.go000066400000000000000000000163571455407747200206570ustar00rootroot00000000000000//go:build freebsd // +build freebsd package process import ( "bytes" "context" "path/filepath" "strconv" "strings" cpu "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" net "github.com/shirou/gopsutil/v3/net" "golang.org/x/sys/unix" ) func pidsWithContext(ctx context.Context) ([]int32, error) { var ret []int32 procs, err := ProcessesWithContext(ctx) if err != nil { return ret, nil } for _, p := range procs { ret = append(ret, p.Pid) } return ret, nil } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { k, err := p.getKProc() if err != nil { return 0, err } return k.Ppid, nil } func (p *Process) NameWithContext(ctx context.Context) (string, error) { k, err := p.getKProc() if err != nil { return "", err } name := common.IntToString(k.Comm[:]) if len(name) >= 15 { cmdlineSlice, err := p.CmdlineSliceWithContext(ctx) if err != nil { return "", err } if len(cmdlineSlice) > 0 { extendedName := filepath.Base(cmdlineSlice[0]) if strings.HasPrefix(extendedName, p.name) { name = extendedName } } } return name, nil } func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { mib := []int32{CTLKern, KernProc, KernProcPathname, p.Pid} buf, _, err := common.CallSyscall(mib) if err != nil { return "", err } return strings.Trim(string(buf), "\x00"), nil } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid} buf, _, err := common.CallSyscall(mib) if err != nil { return "", err } ret := strings.FieldsFunc(string(buf), func(r rune) bool { if r == '\u0000' { return true } return false }) return strings.Join(ret, " "), nil } func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid} buf, _, err := common.CallSyscall(mib) if err != nil { return nil, err } if len(buf) == 0 { return nil, nil } if buf[len(buf)-1] == 0 { buf = buf[:len(buf)-1] } parts := bytes.Split(buf, []byte{0}) var strParts []string for _, p := range parts { strParts = append(strParts, string(p)) } return strParts, nil } func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { k, err := p.getKProc() if err != nil { return 0, err } return int64(k.Start.Sec)*1000 + int64(k.Start.Usec)/1000, nil } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { k, err := p.getKProc() if err != nil { return []string{""}, err } var s string switch k.Stat { case SIDL: s = Idle case SRUN: s = Running case SSLEEP: s = Sleep case SSTOP: s = Stop case SZOMB: s = Zombie case SWAIT: s = Wait case SLOCK: s = Lock } return []string{s}, nil } func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details pid := p.Pid out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid))) if err != nil { return false, err } return strings.IndexByte(string(out), '+') != -1, nil } func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { return nil, err } uids := make([]int32, 0, 3) uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid)) return uids, nil } func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { return nil, err } gids := make([]int32, 0, 3) gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid)) return gids, nil } func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { return nil, err } groups := make([]int32, k.Ngroups) for i := int16(0); i < k.Ngroups; i++ { groups[i] = int32(k.Groups[i]) } return groups, nil } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { k, err := p.getKProc() if err != nil { return "", err } ttyNr := uint64(k.Tdev) termmap, err := getTerminalMap() if err != nil { return "", err } return termmap[ttyNr], nil } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { k, err := p.getKProc() if err != nil { return 0, err } return int32(k.Nice), nil } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { k, err := p.getKProc() if err != nil { return nil, err } return &IOCountersStat{ ReadCount: uint64(k.Rusage.Inblock), WriteCount: uint64(k.Rusage.Oublock), }, nil } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { k, err := p.getKProc() if err != nil { return 0, err } return k.Numthreads, nil } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { k, err := p.getKProc() if err != nil { return nil, err } return &cpu.TimesStat{ CPU: "cpu", User: float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000, System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000, }, nil } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { k, err := p.getKProc() if err != nil { return nil, err } v, err := unix.Sysctl("vm.stats.vm.v_page_size") if err != nil { return nil, err } pageSize := common.LittleEndian.Uint16([]byte(v)) return &MemoryInfoStat{ RSS: uint64(k.Rssize) * uint64(pageSize), VMS: uint64(k.Size), }, nil } func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid) if err != nil { return nil, err } ret := make([]*Process, 0, len(pids)) for _, pid := range pids { np, err := NewProcessWithContext(ctx, pid) if err != nil { return nil, err } ret = append(ret, np) } return ret, nil } func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { return net.ConnectionsPidWithContext(ctx, "all", p.Pid) } func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, max) } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { results := []*Process{} mib := []int32{CTLKern, KernProc, KernProcProc, 0} buf, length, err := common.CallSyscall(mib) if err != nil { return results, err } // get kinfo_proc size count := int(length / uint64(sizeOfKinfoProc)) // parse buf to procs for i := 0; i < count; i++ { b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc] k, err := parseKinfoProc(b) if err != nil { continue } p, err := NewProcessWithContext(ctx, int32(k.Pid)) if err != nil { continue } results = append(results, p) } return results, nil } func (p *Process) getKProc() (*KinfoProc, error) { mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid} buf, length, err := common.CallSyscall(mib) if err != nil { return nil, err } if length != sizeOfKinfoProc { return nil, err } k, err := parseKinfoProc(buf) if err != nil { return nil, err } return &k, nil } gopsutil-3.24.1/process/process_freebsd_386.go000066400000000000000000000067311455407747200212520ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go package process const ( CTLKern = 1 KernProc = 14 KernProcPID = 1 KernProcProc = 8 KernProcPathname = 12 KernProcArgs = 7 ) const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 ) const ( sizeOfKinfoVmentry = 0x488 sizeOfKinfoProc = 0x300 ) const ( SIDL = 1 SRUN = 2 SSLEEP = 3 SSTOP = 4 SZOMB = 5 SWAIT = 6 SLOCK = 7 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type Timespec struct { Sec int32 Nsec int32 } type Timeval struct { Sec int32 Usec int32 } type Rusage struct { Utime Timeval Stime Timeval Maxrss int32 Ixrss int32 Idrss int32 Isrss int32 Minflt int32 Majflt int32 Nswap int32 Inblock int32 Oublock int32 Msgsnd int32 Msgrcv int32 Nsignals int32 Nvcsw int32 Nivcsw int32 } type Rlimit struct { Cur int64 Max int64 } type KinfoProc struct { Structsize int32 Layout int32 Args int32 /* pargs */ Paddr int32 /* proc */ Addr int32 /* user */ Tracep int32 /* vnode */ Textvp int32 /* vnode */ Fd int32 /* filedesc */ Vmspace int32 /* vmspace */ Wchan int32 Pid int32 Ppid int32 Pgid int32 Tpgid int32 Sid int32 Tsid int32 Jobc int16 Spare_short1 int16 Tdev uint32 Siglist [16]byte /* sigset */ Sigmask [16]byte /* sigset */ Sigignore [16]byte /* sigset */ Sigcatch [16]byte /* sigset */ Uid uint32 Ruid uint32 Svuid uint32 Rgid uint32 Svgid uint32 Ngroups int16 Spare_short2 int16 Groups [16]uint32 Size uint32 Rssize int32 Swrss int32 Tsize int32 Dsize int32 Ssize int32 Xstat uint16 Acflag uint16 Pctcpu uint32 Estcpu uint32 Slptime uint32 Swtime uint32 Cow uint32 Runtime uint64 Start Timeval Childtime Timeval Flag int32 Kiflag int32 Traceflag int32 Stat int8 Nice int8 Lock int8 Rqindex int8 Oncpu uint8 Lastcpu uint8 Tdname [17]int8 Wmesg [9]int8 Login [18]int8 Lockname [9]int8 Comm [20]int8 Emul [17]int8 Loginclass [18]int8 Sparestrings [50]int8 Spareints [7]int32 Flag2 int32 Fibnum int32 Cr_flags uint32 Jid int32 Numthreads int32 Tid int32 Pri Priority Rusage Rusage Rusage_ch Rusage Pcb int32 /* pcb */ Kstack int32 Udata int32 Tdaddr int32 /* thread */ Spareptrs [6]int32 Sparelongs [12]int32 Sflag int32 Tdflags int32 } type Priority struct { Class uint8 Level uint8 Native uint8 User uint8 } type KinfoVmentry struct { Structsize int32 Type int32 Start uint64 End uint64 Offset uint64 Vn_fileid uint64 Vn_fsid uint32 Flags int32 Resident int32 Private_resident int32 Protection int32 Ref_count int32 Shadow_count int32 Vn_type int32 Vn_size uint64 Vn_rdev uint32 Vn_mode uint16 Status uint16 X_kve_ispare [12]int32 Path [1024]int8 } gopsutil-3.24.1/process/process_freebsd_amd64.go000066400000000000000000000067311455407747200216450ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go package process const ( CTLKern = 1 KernProc = 14 KernProcPID = 1 KernProcProc = 8 KernProcPathname = 12 KernProcArgs = 7 ) const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 ) const ( sizeOfKinfoVmentry = 0x488 sizeOfKinfoProc = 0x440 ) const ( SIDL = 1 SRUN = 2 SSLEEP = 3 SSTOP = 4 SZOMB = 5 SWAIT = 6 SLOCK = 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 int64 Max int64 } type KinfoProc struct { Structsize int32 Layout int32 Args int64 /* pargs */ Paddr int64 /* proc */ Addr int64 /* user */ Tracep int64 /* vnode */ Textvp int64 /* vnode */ Fd int64 /* filedesc */ Vmspace int64 /* vmspace */ Wchan int64 Pid int32 Ppid int32 Pgid int32 Tpgid int32 Sid int32 Tsid int32 Jobc int16 Spare_short1 int16 Tdev uint32 Siglist [16]byte /* sigset */ Sigmask [16]byte /* sigset */ Sigignore [16]byte /* sigset */ Sigcatch [16]byte /* sigset */ Uid uint32 Ruid uint32 Svuid uint32 Rgid uint32 Svgid uint32 Ngroups int16 Spare_short2 int16 Groups [16]uint32 Size uint64 Rssize int64 Swrss int64 Tsize int64 Dsize int64 Ssize int64 Xstat uint16 Acflag uint16 Pctcpu uint32 Estcpu uint32 Slptime uint32 Swtime uint32 Cow uint32 Runtime uint64 Start Timeval Childtime Timeval Flag int64 Kiflag int64 Traceflag int32 Stat int8 Nice int8 Lock int8 Rqindex int8 Oncpu uint8 Lastcpu uint8 Tdname [17]int8 Wmesg [9]int8 Login [18]int8 Lockname [9]int8 Comm [20]int8 Emul [17]int8 Loginclass [18]int8 Sparestrings [50]int8 Spareints [7]int32 Flag2 int32 Fibnum int32 Cr_flags uint32 Jid int32 Numthreads int32 Tid int32 Pri Priority Rusage Rusage Rusage_ch Rusage Pcb int64 /* pcb */ Kstack int64 Udata int64 Tdaddr int64 /* thread */ Spareptrs [6]int64 Sparelongs [12]int64 Sflag int64 Tdflags int64 } type Priority struct { Class uint8 Level uint8 Native uint8 User uint8 } type KinfoVmentry struct { Structsize int32 Type int32 Start uint64 End uint64 Offset uint64 Vn_fileid uint64 Vn_fsid uint32 Flags int32 Resident int32 Private_resident int32 Protection int32 Ref_count int32 Shadow_count int32 Vn_type int32 Vn_size uint64 Vn_rdev uint32 Vn_mode uint16 Status uint16 X_kve_ispare [12]int32 Path [1024]int8 } gopsutil-3.24.1/process/process_freebsd_arm.go000066400000000000000000000067311455407747200215110ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go package process const ( CTLKern = 1 KernProc = 14 KernProcPID = 1 KernProcProc = 8 KernProcPathname = 12 KernProcArgs = 7 ) const ( sizeofPtr = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 ) const ( sizeOfKinfoVmentry = 0x488 sizeOfKinfoProc = 0x440 ) const ( SIDL = 1 SRUN = 2 SSLEEP = 3 SSTOP = 4 SZOMB = 5 SWAIT = 6 SLOCK = 7 ) type ( _C_short int16 _C_int int32 _C_long int32 _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 int32 Ixrss int32 Idrss int32 Isrss int32 Minflt int32 Majflt int32 Nswap int32 Inblock int32 Oublock int32 Msgsnd int32 Msgrcv int32 Nsignals int32 Nvcsw int32 Nivcsw int32 } type Rlimit struct { Cur int32 Max int32 } type KinfoProc struct { Structsize int32 Layout int32 Args int32 /* pargs */ Paddr int32 /* proc */ Addr int32 /* user */ Tracep int32 /* vnode */ Textvp int32 /* vnode */ Fd int32 /* filedesc */ Vmspace int32 /* vmspace */ Wchan int32 Pid int32 Ppid int32 Pgid int32 Tpgid int32 Sid int32 Tsid int32 Jobc int16 Spare_short1 int16 Tdev uint32 Siglist [16]byte /* sigset */ Sigmask [16]byte /* sigset */ Sigignore [16]byte /* sigset */ Sigcatch [16]byte /* sigset */ Uid uint32 Ruid uint32 Svuid uint32 Rgid uint32 Svgid uint32 Ngroups int16 Spare_short2 int16 Groups [16]uint32 Size uint32 Rssize int32 Swrss int32 Tsize int32 Dsize int32 Ssize int32 Xstat uint16 Acflag uint16 Pctcpu uint32 Estcpu uint32 Slptime uint32 Swtime uint32 Cow uint32 Runtime uint64 Start Timeval Childtime Timeval Flag int32 Kiflag int32 Traceflag int32 Stat int8 Nice int8 Lock int8 Rqindex int8 Oncpu uint8 Lastcpu uint8 Tdname [17]int8 Wmesg [9]int8 Login [18]int8 Lockname [9]int8 Comm [20]int8 Emul [17]int8 Loginclass [18]int8 Sparestrings [50]int8 Spareints [4]int32 Flag2 int32 Fibnum int32 Cr_flags uint32 Jid int32 Numthreads int32 Tid int32 Pri Priority Rusage Rusage Rusage_ch Rusage Pcb int32 /* pcb */ Kstack int32 Udata int32 Tdaddr int32 /* thread */ Spareptrs [6]int64 Sparelongs [12]int64 Sflag int64 Tdflags int64 } type Priority struct { Class uint8 Level uint8 Native uint8 User uint8 } type KinfoVmentry struct { Structsize int32 Type int32 Start uint64 End uint64 Offset uint64 Vn_fileid uint64 Vn_fsid uint32 Flags int32 Resident int32 Private_resident int32 Protection int32 Ref_count int32 Shadow_count int32 Vn_type int32 Vn_size uint64 Vn_rdev uint32 Vn_mode uint16 Status uint16 X_kve_ispare [12]int32 Path [1024]int8 } gopsutil-3.24.1/process/process_freebsd_arm64.go000066400000000000000000000076221455407747200216630ustar00rootroot00000000000000//go:build freebsd && arm64 // +build freebsd,arm64 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs process/types_freebsd.go package process const ( CTLKern = 1 KernProc = 14 KernProcPID = 1 KernProcProc = 8 KernProcPathname = 12 KernProcArgs = 7 ) const ( sizeofPtr = 0x8 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x8 sizeofLongLong = 0x8 ) const ( sizeOfKinfoVmentry = 0x488 sizeOfKinfoProc = 0x440 ) const ( SIDL = 1 SRUN = 2 SSLEEP = 3 SSTOP = 4 SZOMB = 5 SWAIT = 6 SLOCK = 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 int64 Max int64 } type KinfoProc struct { Structsize int32 Layout int32 Args *int64 /* pargs */ Paddr *int64 /* proc */ Addr *int64 /* user */ Tracep *int64 /* vnode */ Textvp *int64 /* vnode */ Fd *int64 /* filedesc */ Vmspace *int64 /* vmspace */ Wchan *byte Pid int32 Ppid int32 Pgid int32 Tpgid int32 Sid int32 Tsid int32 Jobc int16 Spare_short1 int16 Tdev_freebsd11 uint32 Siglist [16]byte /* sigset */ Sigmask [16]byte /* sigset */ Sigignore [16]byte /* sigset */ Sigcatch [16]byte /* sigset */ Uid uint32 Ruid uint32 Svuid uint32 Rgid uint32 Svgid uint32 Ngroups int16 Spare_short2 int16 Groups [16]uint32 Size uint64 Rssize int64 Swrss int64 Tsize int64 Dsize int64 Ssize int64 Xstat uint16 Acflag uint16 Pctcpu uint32 Estcpu uint32 Slptime uint32 Swtime uint32 Cow uint32 Runtime uint64 Start Timeval Childtime Timeval Flag int64 Kiflag int64 Traceflag int32 Stat uint8 Nice int8 Lock uint8 Rqindex uint8 Oncpu_old uint8 Lastcpu_old uint8 Tdname [17]uint8 Wmesg [9]uint8 Login [18]uint8 Lockname [9]uint8 Comm [20]int8 Emul [17]uint8 Loginclass [18]uint8 Moretdname [4]uint8 Sparestrings [46]uint8 Spareints [2]int32 Tdev uint64 Oncpu int32 Lastcpu int32 Tracer int32 Flag2 int32 Fibnum int32 Cr_flags uint32 Jid int32 Numthreads int32 Tid int32 Pri Priority Rusage Rusage Rusage_ch Rusage Pcb *int64 /* pcb */ Kstack *byte Udata *byte Tdaddr *int64 /* thread */ Spareptrs [6]*byte Sparelongs [12]int64 Sflag int64 Tdflags int64 } type Priority struct { Class uint8 Level uint8 Native uint8 User uint8 } type KinfoVmentry struct { Structsize int32 Type int32 Start uint64 End uint64 Offset uint64 Vn_fileid uint64 Vn_fsid_freebsd11 uint32 Flags int32 Resident int32 Private_resident int32 Protection int32 Ref_count int32 Shadow_count int32 Vn_type int32 Vn_size uint64 Vn_rdev_freebsd11 uint32 Vn_mode uint16 Status uint16 Vn_fsid uint64 Vn_rdev uint64 X_kve_ispare [8]int32 Path [1024]uint8 } gopsutil-3.24.1/process/process_linux.go000066400000000000000000000731371455407747200204030ustar00rootroot00000000000000//go:build linux // +build linux package process import ( "bufio" "bytes" "context" "encoding/json" "fmt" "math" "os" "path/filepath" "strconv" "strings" "github.com/tklauser/go-sysconf" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/net" ) var pageSize = uint64(os.Getpagesize()) const prioProcess = 0 // linux/resource.h var clockTicks = 100 // default value func init() { clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK) // ignore errors if err == nil { clockTicks = int(clkTck) } } // MemoryInfoExStat is different between OSes type MemoryInfoExStat struct { RSS uint64 `json:"rss"` // bytes VMS uint64 `json:"vms"` // bytes Shared uint64 `json:"shared"` // bytes Text uint64 `json:"text"` // bytes Lib uint64 `json:"lib"` // bytes Data uint64 `json:"data"` // bytes Dirty uint64 `json:"dirty"` // bytes } func (m MemoryInfoExStat) String() string { s, _ := json.Marshal(m) return string(s) } type MemoryMapsStat struct { Path string `json:"path"` Rss uint64 `json:"rss"` Size uint64 `json:"size"` Pss uint64 `json:"pss"` SharedClean uint64 `json:"sharedClean"` SharedDirty uint64 `json:"sharedDirty"` PrivateClean uint64 `json:"privateClean"` PrivateDirty uint64 `json:"privateDirty"` Referenced uint64 `json:"referenced"` Anonymous uint64 `json:"anonymous"` Swap uint64 `json:"swap"` } // String returns JSON value of the process. func (m MemoryMapsStat) String() string { s, _ := json.Marshal(m) return string(s) } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { _, ppid, _, _, _, _, _, err := p.fillFromStatWithContext(ctx) if err != nil { return -1, err } return ppid, nil } func (p *Process) NameWithContext(ctx context.Context) (string, error) { if p.name == "" { if err := p.fillNameWithContext(ctx); err != nil { return "", err } } return p.name, nil } func (p *Process) TgidWithContext(ctx context.Context) (int32, error) { if p.tgid == 0 { if err := p.fillFromStatusWithContext(ctx); err != nil { return 0, err } } return p.tgid, nil } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { return p.fillFromExeWithContext(ctx) } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { return p.fillFromCmdlineWithContext(ctx) } func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { return p.fillSliceFromCmdlineWithContext(ctx) } func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { _, _, _, createTime, _, _, _, err := p.fillFromStatWithContext(ctx) if err != nil { return 0, err } return createTime, nil } func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return p.fillFromCwdWithContext(ctx) } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { err := p.fillFromStatusWithContext(ctx) if err != nil { return []string{""}, err } return []string{p.status}, nil } func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat") contents, err := os.ReadFile(statPath) if err != nil { return false, err } fields := strings.Fields(string(contents)) if len(fields) < 8 { return false, fmt.Errorf("insufficient data in %s", statPath) } pgid := fields[4] tpgid := fields[7] return pgid == tpgid, nil } func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { err := p.fillFromStatusWithContext(ctx) if err != nil { return []int32{}, err } return p.uids, nil } func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { err := p.fillFromStatusWithContext(ctx) if err != nil { return []int32{}, err } return p.gids, nil } func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { err := p.fillFromStatusWithContext(ctx) if err != nil { return []int32{}, err } return p.groups, nil } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { t, _, _, _, _, _, _, err := p.fillFromStatWithContext(ctx) if err != nil { return "", err } termmap, err := getTerminalMap() if err != nil { return "", err } terminal := termmap[t] return terminal, nil } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { _, _, _, _, _, nice, _, err := p.fillFromStatWithContext(ctx) if err != nil { return 0, err } return nice, nil } func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { return p.RlimitUsageWithContext(ctx, false) } func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { rlimits, err := p.fillFromLimitsWithContext(ctx) if !gatherUsed || err != nil { return rlimits, err } _, _, _, _, rtprio, nice, _, err := p.fillFromStatWithContext(ctx) if err != nil { return nil, err } if err := p.fillFromStatusWithContext(ctx); err != nil { return nil, err } for i := range rlimits { rs := &rlimits[i] switch rs.Resource { case RLIMIT_CPU: times, err := p.TimesWithContext(ctx) if err != nil { return nil, err } rs.Used = uint64(times.User + times.System) case RLIMIT_DATA: rs.Used = uint64(p.memInfo.Data) case RLIMIT_STACK: rs.Used = uint64(p.memInfo.Stack) case RLIMIT_RSS: rs.Used = uint64(p.memInfo.RSS) case RLIMIT_NOFILE: n, err := p.NumFDsWithContext(ctx) if err != nil { return nil, err } rs.Used = uint64(n) case RLIMIT_MEMLOCK: rs.Used = uint64(p.memInfo.Locked) case RLIMIT_AS: rs.Used = uint64(p.memInfo.VMS) case RLIMIT_LOCKS: // TODO we can get the used value from /proc/$pid/locks. But linux doesn't enforce it, so not a high priority. case RLIMIT_SIGPENDING: rs.Used = p.sigInfo.PendingProcess case RLIMIT_NICE: // The rlimit for nice is a little unusual, in that 0 means the niceness cannot be decreased beyond the current value, but it can be increased. // So effectively: if rs.Soft == 0 { rs.Soft = rs.Used } rs.Used = uint64(nice) case RLIMIT_RTPRIO: rs.Used = uint64(rtprio) } } return rlimits, err } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { return p.fillFromIOWithContext(ctx) } func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { err := p.fillFromStatusWithContext(ctx) if err != nil { return nil, err } return p.numCtxSwitches, nil } func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { _, fnames, err := p.fillFromfdListWithContext(ctx) return int32(len(fnames)), err } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { err := p.fillFromStatusWithContext(ctx) if err != nil { return 0, err } return p.numThreads, nil } func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { ret := make(map[int32]*cpu.TimesStat) taskPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "task") tids, err := readPidsFromDir(taskPath) if err != nil { return nil, err } for _, tid := range tids { _, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStatWithContext(ctx, tid) if err != nil { return nil, err } ret[tid] = cpuTimes } return ret, nil } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { _, _, cpuTimes, _, _, _, _, err := p.fillFromStatWithContext(ctx) if err != nil { return nil, err } return cpuTimes, nil } func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { meminfo, _, err := p.fillFromStatmWithContext(ctx) if err != nil { return nil, err } return meminfo, nil } func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { _, memInfoEx, err := p.fillFromStatmWithContext(ctx) if err != nil { return nil, err } return memInfoEx, nil } func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { _, _, _, _, _, _, pageFaults, err := p.fillFromStatWithContext(ctx) if err != nil { return nil, err } return pageFaults, nil } func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid) if err != nil { return nil, err } if len(pids) == 0 { return nil, ErrorNoChildren } ret := make([]*Process, 0, len(pids)) for _, pid := range pids { np, err := NewProcessWithContext(ctx, pid) if err != nil { return nil, err } ret = append(ret, np) } return ret, nil } func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { _, ofs, err := p.fillFromfdWithContext(ctx) if err != nil { return nil, err } ret := make([]OpenFilesStat, len(ofs)) for i, o := range ofs { ret[i] = *o } return ret, nil } func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { return net.ConnectionsPidWithContext(ctx, "all", p.Pid) } func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, max) } func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { pid := p.Pid var ret []MemoryMapsStat smapsPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "smaps") if grouped { ret = make([]MemoryMapsStat, 1) // If smaps_rollup exists (require kernel >= 4.15), then we will use it // for pre-summed memory information for a process. smapsRollupPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "smaps_rollup") if _, err := os.Stat(smapsRollupPath); !os.IsNotExist(err) { smapsPath = smapsRollupPath } } contents, err := os.ReadFile(smapsPath) if err != nil { return nil, err } lines := strings.Split(string(contents), "\n") // function of parsing a block getBlock := func(firstLine []string, block []string) (MemoryMapsStat, error) { m := MemoryMapsStat{} m.Path = firstLine[len(firstLine)-1] for _, line := range block { if strings.Contains(line, "VmFlags") { continue } field := strings.Split(line, ":") if len(field) < 2 { continue } v := strings.Trim(field[1], "kB") // remove last "kB" v = strings.TrimSpace(v) t, err := strconv.ParseUint(v, 10, 64) if err != nil { return m, err } switch field[0] { case "Size": m.Size = t case "Rss": m.Rss = t case "Pss": m.Pss = t case "Shared_Clean": m.SharedClean = t case "Shared_Dirty": m.SharedDirty = t case "Private_Clean": m.PrivateClean = t case "Private_Dirty": m.PrivateDirty = t case "Referenced": m.Referenced = t case "Anonymous": m.Anonymous = t case "Swap": m.Swap = t } } return m, nil } var firstLine []string blocks := make([]string, 0, 16) for i, line := range lines { fields := strings.Fields(line) if (len(fields) > 0 && !strings.HasSuffix(fields[0], ":")) || i == len(lines)-1 { // new block section if len(firstLine) > 0 && len(blocks) > 0 { g, err := getBlock(firstLine, blocks) if err != nil { return &ret, err } if grouped { ret[0].Size += g.Size ret[0].Rss += g.Rss ret[0].Pss += g.Pss ret[0].SharedClean += g.SharedClean ret[0].SharedDirty += g.SharedDirty ret[0].PrivateClean += g.PrivateClean ret[0].PrivateDirty += g.PrivateDirty ret[0].Referenced += g.Referenced ret[0].Anonymous += g.Anonymous ret[0].Swap += g.Swap } else { ret = append(ret, g) } } // starts new block blocks = make([]string, 0, 16) firstLine = fields } else { blocks = append(blocks, line) } } return &ret, nil } func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { environPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "environ") environContent, err := os.ReadFile(environPath) if err != nil { return nil, err } return strings.Split(string(environContent), "\000"), nil } /** ** Internal functions **/ func limitToUint(val string) (uint64, error) { if val == "unlimited" { return math.MaxUint64, nil } res, err := strconv.ParseUint(val, 10, 64) if err != nil { return 0, err } return res, nil } // Get num_fds from /proc/(pid)/limits func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, error) { pid := p.Pid limitsFile := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "limits") d, err := os.Open(limitsFile) if err != nil { return nil, err } defer d.Close() var limitStats []RlimitStat limitsScanner := bufio.NewScanner(d) for limitsScanner.Scan() { var statItem RlimitStat str := strings.Fields(limitsScanner.Text()) // Remove the header line if strings.Contains(str[len(str)-1], "Units") { continue } // Assert that last item is a Hard limit statItem.Hard, err = limitToUint(str[len(str)-1]) if err != nil { // On error remove last item and try once again since it can be unit or header line str = str[:len(str)-1] statItem.Hard, err = limitToUint(str[len(str)-1]) if err != nil { return nil, err } } // Remove last item from string str = str[:len(str)-1] // Now last item is a Soft limit statItem.Soft, err = limitToUint(str[len(str)-1]) if err != nil { return nil, err } // Remove last item from string str = str[:len(str)-1] // The rest is a stats name resourceName := strings.Join(str, " ") switch resourceName { case "Max cpu time": statItem.Resource = RLIMIT_CPU case "Max file size": statItem.Resource = RLIMIT_FSIZE case "Max data size": statItem.Resource = RLIMIT_DATA case "Max stack size": statItem.Resource = RLIMIT_STACK case "Max core file size": statItem.Resource = RLIMIT_CORE case "Max resident set": statItem.Resource = RLIMIT_RSS case "Max processes": statItem.Resource = RLIMIT_NPROC case "Max open files": statItem.Resource = RLIMIT_NOFILE case "Max locked memory": statItem.Resource = RLIMIT_MEMLOCK case "Max address space": statItem.Resource = RLIMIT_AS case "Max file locks": statItem.Resource = RLIMIT_LOCKS case "Max pending signals": statItem.Resource = RLIMIT_SIGPENDING case "Max msgqueue size": statItem.Resource = RLIMIT_MSGQUEUE case "Max nice priority": statItem.Resource = RLIMIT_NICE case "Max realtime priority": statItem.Resource = RLIMIT_RTPRIO case "Max realtime timeout": statItem.Resource = RLIMIT_RTTIME default: continue } limitStats = append(limitStats, statItem) } if err := limitsScanner.Err(); err != nil { return nil, err } return limitStats, nil } // Get list of /proc/(pid)/fd files func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) { pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "fd") d, err := os.Open(statPath) if err != nil { return statPath, []string{}, err } defer d.Close() fnames, err := d.Readdirnames(-1) return statPath, fnames, err } // Get num_fds from /proc/(pid)/fd func (p *Process) fillFromfdWithContext(ctx context.Context) (int32, []*OpenFilesStat, error) { statPath, fnames, err := p.fillFromfdListWithContext(ctx) if err != nil { return 0, nil, err } numFDs := int32(len(fnames)) var openfiles []*OpenFilesStat for _, fd := range fnames { fpath := filepath.Join(statPath, fd) filepath, err := os.Readlink(fpath) if err != nil { continue } t, err := strconv.ParseUint(fd, 10, 64) if err != nil { return numFDs, openfiles, err } o := &OpenFilesStat{ Path: filepath, Fd: t, } openfiles = append(openfiles, o) } return numFDs, openfiles, nil } // Get cwd from /proc/(pid)/cwd func (p *Process) fillFromCwdWithContext(ctx context.Context) (string, error) { pid := p.Pid cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cwd") cwd, err := os.Readlink(cwdPath) if err != nil { return "", err } return string(cwd), nil } // Get exe from /proc/(pid)/exe func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) { pid := p.Pid exePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "exe") exe, err := os.Readlink(exePath) if err != nil { return "", err } return string(exe), nil } // Get cmdline from /proc/(pid)/cmdline func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) { pid := p.Pid cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdline, err := os.ReadFile(cmdPath) if err != nil { return "", err } ret := strings.FieldsFunc(string(cmdline), func(r rune) bool { return r == '\u0000' }) return strings.Join(ret, " "), nil } func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) { pid := p.Pid cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdline, err := os.ReadFile(cmdPath) if err != nil { return nil, err } if len(cmdline) == 0 { return nil, nil } cmdline = bytes.TrimRight(cmdline, "\x00") parts := bytes.Split(cmdline, []byte{0}) var strParts []string for _, p := range parts { strParts = append(strParts, string(p)) } return strParts, nil } // Get IO status from /proc/(pid)/io func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) { pid := p.Pid ioPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "io") ioline, err := os.ReadFile(ioPath) if err != nil { return nil, err } lines := strings.Split(string(ioline), "\n") ret := &IOCountersStat{} for _, line := range lines { field := strings.Fields(line) if len(field) < 2 { continue } t, err := strconv.ParseUint(field[1], 10, 64) if err != nil { return nil, err } param := strings.TrimSuffix(field[0], ":") switch param { case "syscr": ret.ReadCount = t case "syscw": ret.WriteCount = t case "read_bytes": ret.ReadBytes = t case "write_bytes": ret.WriteBytes = t } } return ret, nil } // Get memory info from /proc/(pid)/statm func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) { pid := p.Pid memPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "statm") contents, err := os.ReadFile(memPath) if err != nil { return nil, nil, err } fields := strings.Split(string(contents), " ") vms, err := strconv.ParseUint(fields[0], 10, 64) if err != nil { return nil, nil, err } rss, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { return nil, nil, err } memInfo := &MemoryInfoStat{ RSS: rss * pageSize, VMS: vms * pageSize, } shared, err := strconv.ParseUint(fields[2], 10, 64) if err != nil { return nil, nil, err } text, err := strconv.ParseUint(fields[3], 10, 64) if err != nil { return nil, nil, err } lib, err := strconv.ParseUint(fields[4], 10, 64) if err != nil { return nil, nil, err } dirty, err := strconv.ParseUint(fields[5], 10, 64) if err != nil { return nil, nil, err } memInfoEx := &MemoryInfoExStat{ RSS: rss * pageSize, VMS: vms * pageSize, Shared: shared * pageSize, Text: text * pageSize, Lib: lib * pageSize, Dirty: dirty * pageSize, } return memInfo, memInfoEx, nil } // Get name from /proc/(pid)/comm or /proc/(pid)/status func (p *Process) fillNameWithContext(ctx context.Context) error { err := p.fillFromCommWithContext(ctx) if err == nil && p.name != "" && len(p.name) < 15 { return nil } return p.fillFromStatusWithContext(ctx) } // Get name from /proc/(pid)/comm func (p *Process) fillFromCommWithContext(ctx context.Context) error { pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "comm") contents, err := os.ReadFile(statPath) if err != nil { return err } p.name = strings.TrimSuffix(string(contents), "\n") return nil } // Get various status from /proc/(pid)/status func (p *Process) fillFromStatus() error { return p.fillFromStatusWithContext(context.Background()) } func (p *Process) fillFromStatusWithContext(ctx context.Context) error { pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status") contents, err := os.ReadFile(statPath) if err != nil { return err } lines := strings.Split(string(contents), "\n") p.numCtxSwitches = &NumCtxSwitchesStat{} p.memInfo = &MemoryInfoStat{} p.sigInfo = &SignalInfoStat{} for _, line := range lines { tabParts := strings.SplitN(line, "\t", 2) if len(tabParts) < 2 { continue } value := tabParts[1] switch strings.TrimRight(tabParts[0], ":") { case "Name": p.name = strings.Trim(value, " \t") if len(p.name) >= 15 { cmdlineSlice, err := p.CmdlineSliceWithContext(ctx) if err != nil { return err } if len(cmdlineSlice) > 0 { extendedName := filepath.Base(cmdlineSlice[0]) if strings.HasPrefix(extendedName, p.name) { p.name = extendedName } } } // Ensure we have a copy and not reference into slice p.name = string([]byte(p.name)) case "State": p.status = convertStatusChar(value[0:1]) // Ensure we have a copy and not reference into slice p.status = string([]byte(p.status)) case "PPid", "Ppid": pval, err := strconv.ParseInt(value, 10, 32) if err != nil { return err } p.parent = int32(pval) case "Tgid": pval, err := strconv.ParseInt(value, 10, 32) if err != nil { return err } p.tgid = int32(pval) case "Uid": p.uids = make([]int32, 0, 4) for _, i := range strings.Split(value, "\t") { v, err := strconv.ParseInt(i, 10, 32) if err != nil { return err } p.uids = append(p.uids, int32(v)) } case "Gid": p.gids = make([]int32, 0, 4) for _, i := range strings.Split(value, "\t") { v, err := strconv.ParseInt(i, 10, 32) if err != nil { return err } p.gids = append(p.gids, int32(v)) } case "Groups": groups := strings.Fields(value) p.groups = make([]int32, 0, len(groups)) for _, i := range groups { v, err := strconv.ParseInt(i, 10, 32) if err != nil { return err } p.groups = append(p.groups, int32(v)) } case "Threads": v, err := strconv.ParseInt(value, 10, 32) if err != nil { return err } p.numThreads = int32(v) case "voluntary_ctxt_switches": v, err := strconv.ParseInt(value, 10, 64) if err != nil { return err } p.numCtxSwitches.Voluntary = v case "nonvoluntary_ctxt_switches": v, err := strconv.ParseInt(value, 10, 64) if err != nil { return err } p.numCtxSwitches.Involuntary = v case "VmRSS": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.RSS = v * 1024 case "VmSize": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.VMS = v * 1024 case "VmSwap": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.Swap = v * 1024 case "VmHWM": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.HWM = v * 1024 case "VmData": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.Data = v * 1024 case "VmStk": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.Stack = v * 1024 case "VmLck": value := strings.Trim(value, " kB") // remove last "kB" v, err := strconv.ParseUint(value, 10, 64) if err != nil { return err } p.memInfo.Locked = v * 1024 case "SigPnd": if len(value) > 16 { value = value[len(value)-16:] } v, err := strconv.ParseUint(value, 16, 64) if err != nil { return err } p.sigInfo.PendingThread = v case "ShdPnd": if len(value) > 16 { value = value[len(value)-16:] } v, err := strconv.ParseUint(value, 16, 64) if err != nil { return err } p.sigInfo.PendingProcess = v case "SigBlk": if len(value) > 16 { value = value[len(value)-16:] } v, err := strconv.ParseUint(value, 16, 64) if err != nil { return err } p.sigInfo.Blocked = v case "SigIgn": if len(value) > 16 { value = value[len(value)-16:] } v, err := strconv.ParseUint(value, 16, 64) if err != nil { return err } p.sigInfo.Ignored = v case "SigCgt": if len(value) > 16 { value = value[len(value)-16:] } v, err := strconv.ParseUint(value, 16, 64) if err != nil { return err } p.sigInfo.Caught = v } } return nil } func (p *Process) fillFromTIDStat(tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) { return p.fillFromTIDStatWithContext(context.Background(), tid) } func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) { pid := p.Pid var statPath string if tid == -1 { statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat") } else { statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat") } contents, err := os.ReadFile(statPath) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } // Indexing from one, as described in `man proc` about the file /proc/[pid]/stat fields := splitProcStat(contents) terminal, err := strconv.ParseUint(fields[7], 10, 64) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } ppid, err := strconv.ParseInt(fields[4], 10, 32) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } utime, err := strconv.ParseFloat(fields[14], 64) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } stime, err := strconv.ParseFloat(fields[15], 64) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } // There is no such thing as iotime in stat file. As an approximation, we // will use delayacct_blkio_ticks (aggregated block I/O delays, as per Linux // docs). Note: I am assuming at least Linux 2.6.18 var iotime float64 if len(fields) > 42 { iotime, err = strconv.ParseFloat(fields[42], 64) if err != nil { iotime = 0 // Ancient linux version, most likely } } else { iotime = 0 // e.g. SmartOS containers } cpuTimes := &cpu.TimesStat{ CPU: "cpu", User: utime / float64(clockTicks), System: stime / float64(clockTicks), Iowait: iotime / float64(clockTicks), } bootTime, _ := common.BootTimeWithContext(ctx, enableBootTimeCache) t, err := strconv.ParseUint(fields[22], 10, 64) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } ctime := (t / uint64(clockTicks)) + uint64(bootTime) createTime := int64(ctime * 1000) rtpriority, err := strconv.ParseInt(fields[18], 10, 32) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } if rtpriority < 0 { rtpriority = rtpriority*-1 - 1 } else { rtpriority = 0 } // p.Nice = mustParseInt32(fields[18]) // use syscall instead of parse Stat file snice, _ := unix.Getpriority(prioProcess, int(pid)) nice := int32(snice) // FIXME: is this true? minFault, err := strconv.ParseUint(fields[10], 10, 64) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } cMinFault, err := strconv.ParseUint(fields[11], 10, 64) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } majFault, err := strconv.ParseUint(fields[12], 10, 64) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } cMajFault, err := strconv.ParseUint(fields[13], 10, 64) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } faults := &PageFaultsStat{ MinorFaults: minFault, MajorFaults: majFault, ChildMinorFaults: cMinFault, ChildMajorFaults: cMajFault, } return terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, faults, nil } func (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) { return p.fillFromTIDStatWithContext(ctx, -1) } func pidsWithContext(ctx context.Context) ([]int32, error) { return readPidsFromDir(common.HostProcWithContext(ctx)) } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { out := []*Process{} pids, err := PidsWithContext(ctx) if err != nil { return out, err } for _, pid := range pids { p, err := NewProcessWithContext(ctx, pid) if err != nil { continue } out = append(out, p) } return out, nil } func readPidsFromDir(path string) ([]int32, error) { var ret []int32 d, err := os.Open(path) if err != nil { return nil, err } defer d.Close() fnames, err := d.Readdirnames(-1) if err != nil { return nil, err } for _, fname := range fnames { pid, err := strconv.ParseInt(fname, 10, 32) if err != nil { // if not numeric name, just skip continue } ret = append(ret, int32(pid)) } return ret, nil } func splitProcStat(content []byte) []string { nameStart := bytes.IndexByte(content, '(') nameEnd := bytes.LastIndexByte(content, ')') restFields := strings.Fields(string(content[nameEnd+2:])) // +2 skip ') ' name := content[nameStart+1 : nameEnd] pid := strings.TrimSpace(string(content[:nameStart])) fields := make([]string, 3, len(restFields)+3) fields[1] = string(pid) fields[2] = string(name) fields = append(fields, restFields...) return fields } gopsutil-3.24.1/process/process_linux_test.go000066400000000000000000000103051455407747200214260ustar00rootroot00000000000000//go:build linux // +build linux package process import ( "context" "fmt" "os" "strconv" "strings" "testing" "github.com/stretchr/testify/assert" ) func Test_Process_splitProcStat(t *testing.T) { expectedFieldsNum := 53 statLineContent := make([]string, expectedFieldsNum-1) for i := 0; i < expectedFieldsNum-1; i++ { statLineContent[i] = strconv.Itoa(i + 1) } cases := []string{ "ok", "ok)", "(ok", "ok )", "ok )(", "ok )()", "() ok )()", "() ok (()", " ) ok )", "(ok) (ok)", } consideredFields := []int{4, 7, 10, 11, 12, 13, 14, 15, 18, 22, 42} commandNameIndex := 2 for _, expectedName := range cases { statLineContent[commandNameIndex-1] = "(" + expectedName + ")" statLine := strings.Join(statLineContent, " ") t.Run(fmt.Sprintf("name: %s", expectedName), func(t *testing.T) { parsedStatLine := splitProcStat([]byte(statLine)) assert.Equal(t, expectedName, parsedStatLine[commandNameIndex]) for _, idx := range consideredFields { expected := strconv.Itoa(idx) parsed := parsedStatLine[idx] assert.Equal( t, expected, parsed, "field %d (index from 1 as in man proc) must be %q but %q is received", idx, expected, parsed, ) } }) } } func Test_Process_splitProcStat_fromFile(t *testing.T) { pids, err := os.ReadDir("testdata/linux/") if err != nil { t.Error(err) } t.Setenv("HOST_PROC", "testdata/linux") for _, pid := range pids { pid, err := strconv.ParseInt(pid.Name(), 0, 32) if err != nil { continue } statFile := fmt.Sprintf("testdata/linux/%d/stat", pid) if _, err := os.Stat(statFile); err != nil { continue } contents, err := os.ReadFile(statFile) assert.NoError(t, err) pidStr := strconv.Itoa(int(pid)) ppid := "68044" // TODO: how to pass ppid to test? fields := splitProcStat(contents) assert.Equal(t, fields[1], pidStr) assert.Equal(t, fields[2], "test(cmd).sh") assert.Equal(t, fields[3], "S") assert.Equal(t, fields[4], ppid) assert.Equal(t, fields[5], pidStr) // pgrp assert.Equal(t, fields[6], ppid) // session assert.Equal(t, fields[8], pidStr) // tpgrp assert.Equal(t, fields[18], "20") // priority assert.Equal(t, fields[20], "1") // num threads assert.Equal(t, fields[52], "0") // exit code } } func Test_fillFromCommWithContext(t *testing.T) { pids, err := os.ReadDir("testdata/linux/") if err != nil { t.Error(err) } t.Setenv("HOST_PROC", "testdata/linux") for _, pid := range pids { pid, err := strconv.ParseInt(pid.Name(), 0, 32) if err != nil { continue } if _, err := os.Stat(fmt.Sprintf("testdata/linux/%d/status", pid)); err != nil { continue } p, _ := NewProcess(int32(pid)) if err := p.fillFromCommWithContext(context.Background()); err != nil { t.Error(err) } } } func Test_fillFromStatusWithContext(t *testing.T) { pids, err := os.ReadDir("testdata/linux/") if err != nil { t.Error(err) } t.Setenv("HOST_PROC", "testdata/linux") for _, pid := range pids { pid, err := strconv.ParseInt(pid.Name(), 0, 32) if err != nil { continue } if _, err := os.Stat(fmt.Sprintf("testdata/linux/%d/status", pid)); err != nil { continue } p, _ := NewProcess(int32(pid)) if err := p.fillFromStatus(); err != nil { t.Error(err) } } } func Benchmark_fillFromCommWithContext(b *testing.B) { b.Setenv("HOST_PROC", "testdata/linux") pid := 1060 p, _ := NewProcess(int32(pid)) for i := 0; i < b.N; i++ { p.fillFromCommWithContext(context.Background()) } } func Benchmark_fillFromStatusWithContext(b *testing.B) { b.Setenv("HOST_PROC", "testdata/linux") pid := 1060 p, _ := NewProcess(int32(pid)) for i := 0; i < b.N; i++ { p.fillFromStatus() } } func Test_fillFromTIDStatWithContext_lx_brandz(t *testing.T) { pids, err := os.ReadDir("testdata/lx_brandz/") if err != nil { t.Error(err) } t.Setenv("HOST_PROC", "testdata/lx_brandz") for _, pid := range pids { pid, err := strconv.ParseInt(pid.Name(), 0, 32) if err != nil { continue } if _, err := os.Stat(fmt.Sprintf("testdata/lx_brandz/%d/stat", pid)); err != nil { continue } p, _ := NewProcess(int32(pid)) _, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStat(-1) if err != nil { t.Error(err) } assert.Equal(t, float64(0), cpuTimes.Iowait) } } gopsutil-3.24.1/process/process_openbsd.go000066400000000000000000000206371455407747200206730ustar00rootroot00000000000000//go:build openbsd // +build openbsd package process import ( "bytes" "context" "encoding/binary" "fmt" "io" "path/filepath" "strconv" "strings" "unsafe" cpu "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" mem "github.com/shirou/gopsutil/v3/mem" net "github.com/shirou/gopsutil/v3/net" "golang.org/x/sys/unix" ) func pidsWithContext(ctx context.Context) ([]int32, error) { var ret []int32 procs, err := ProcessesWithContext(ctx) if err != nil { return ret, nil } for _, p := range procs { ret = append(ret, p.Pid) } return ret, nil } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { k, err := p.getKProc() if err != nil { return 0, err } return k.Ppid, nil } func (p *Process) NameWithContext(ctx context.Context) (string, error) { k, err := p.getKProc() if err != nil { return "", err } name := common.IntToString(k.Comm[:]) if len(name) >= 15 { cmdlineSlice, err := p.CmdlineSliceWithContext(ctx) if err != nil { return "", err } if len(cmdlineSlice) > 0 { extendedName := filepath.Base(cmdlineSlice[0]) if strings.HasPrefix(extendedName, p.name) { name = extendedName } } } return name, nil } func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv} buf, _, err := common.CallSyscall(mib) if err != nil { return nil, err } /* From man sysctl(2): The buffer pointed to by oldp is filled with an array of char pointers followed by the strings themselves. The last char pointer is a NULL pointer. */ var strParts []string r := bytes.NewReader(buf) baseAddr := uintptr(unsafe.Pointer(&buf[0])) for { argvp, err := readPtr(r) if err != nil { return nil, err } if argvp == 0 { // check for a NULL pointer break } offset := argvp - baseAddr length := uintptr(bytes.IndexByte(buf[offset:], 0)) str := string(buf[offset : offset+length]) strParts = append(strParts, str) } return strParts, nil } // readPtr reads a pointer data from a given reader. WARNING: only little // endian architectures are supported. func readPtr(r io.Reader) (uintptr, error) { switch sizeofPtr { case 4: var p uint32 if err := binary.Read(r, binary.LittleEndian, &p); err != nil { return 0, err } return uintptr(p), nil case 8: var p uint64 if err := binary.Read(r, binary.LittleEndian, &p); err != nil { return 0, err } return uintptr(p), nil default: return 0, fmt.Errorf("unsupported pointer size") } } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { argv, err := p.CmdlineSliceWithContext(ctx) if err != nil { return "", err } return strings.Join(argv, " "), nil } func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { return 0, common.ErrNotImplementedError } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { k, err := p.getKProc() if err != nil { return []string{""}, err } var s string switch k.Stat { case SIDL: case SRUN: case SONPROC: s = Running case SSLEEP: s = Sleep case SSTOP: s = Stop case SDEAD: s = Zombie } return []string{s}, nil } func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details pid := p.Pid out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid))) if err != nil { return false, err } return strings.IndexByte(string(out), '+') != -1, nil } func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { return nil, err } uids := make([]int32, 0, 3) uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid)) return uids, nil } func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { return nil, err } gids := make([]int32, 0, 3) gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid)) return gids, nil } func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { return nil, err } groups := make([]int32, k.Ngroups) for i := int16(0); i < k.Ngroups; i++ { groups[i] = int32(k.Groups[i]) } return groups, nil } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { k, err := p.getKProc() if err != nil { return "", err } ttyNr := uint64(k.Tdev) termmap, err := getTerminalMap() if err != nil { return "", err } return termmap[ttyNr], nil } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { k, err := p.getKProc() if err != nil { return 0, err } return int32(k.Nice), nil } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { k, err := p.getKProc() if err != nil { return nil, err } return &IOCountersStat{ ReadCount: uint64(k.Uru_inblock), WriteCount: uint64(k.Uru_oublock), }, nil } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { /* not supported, just return 1 */ return 1, nil } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { k, err := p.getKProc() if err != nil { return nil, err } return &cpu.TimesStat{ CPU: "cpu", User: float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000, System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000, }, nil } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { k, err := p.getKProc() if err != nil { return nil, err } pageSize, err := mem.GetPageSizeWithContext(ctx) if err != nil { return nil, err } return &MemoryInfoStat{ RSS: uint64(k.Vm_rssize) * pageSize, VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) + uint64(k.Vm_ssize), }, nil } func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid) if err != nil { return nil, err } ret := make([]*Process, 0, len(pids)) for _, pid := range pids { np, err := NewProcessWithContext(ctx, pid) if err != nil { return nil, err } ret = append(ret, np) } return ret, nil } func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { results := []*Process{} buf, length, err := callKernProcSyscall(KernProcAll, 0) if err != nil { return results, err } // get kinfo_proc size count := int(length / uint64(sizeOfKinfoProc)) // parse buf to procs for i := 0; i < count; i++ { b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc] k, err := parseKinfoProc(b) if err != nil { continue } p, err := NewProcessWithContext(ctx, int32(k.Pid)) if err != nil { continue } results = append(results, p) } return results, nil } func (p *Process) getKProc() (*KinfoProc, error) { buf, length, err := callKernProcSyscall(KernProcPID, p.Pid) if err != nil { return nil, err } if length != sizeOfKinfoProc { return nil, err } k, err := parseKinfoProc(buf) if err != nil { return nil, err } return &k, nil } func callKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) { mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0} mibptr := unsafe.Pointer(&mib[0]) miblen := uint64(len(mib)) length := uint64(0) _, _, err := unix.Syscall6( unix.SYS___SYSCTL, uintptr(mibptr), uintptr(miblen), 0, uintptr(unsafe.Pointer(&length)), 0, 0) if err != 0 { return nil, length, err } count := int32(length / uint64(sizeOfKinfoProc)) mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count} mibptr = unsafe.Pointer(&mib[0]) miblen = uint64(len(mib)) // 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 } gopsutil-3.24.1/process/process_openbsd_386.go000066400000000000000000000067271455407747200212770ustar00rootroot00000000000000//go:build openbsd && 386 // +build openbsd,386 // 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 = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 ) const ( sizeOfKinfoVmentry = 0x38 sizeOfKinfoProc = 0x264 ) const ( SIDL = 1 SRUN = 2 SSLEEP = 3 SSTOP = 4 SZOMB = 5 SDEAD = 6 SONPROC = 7 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type Timespec struct { Sec int64 Nsec int32 } type Timeval struct { Sec int64 Usec int32 } type Rusage struct { Utime Timeval Stime Timeval Maxrss int32 Ixrss int32 Idrss int32 Isrss int32 Minflt int32 Majflt int32 Nswap int32 Inblock int32 Oublock int32 Msgsnd int32 Msgrcv int32 Nsignals int32 Nvcsw int32 Nivcsw int32 } 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 Acflag uint16 Comm [24]int8 Wmesg [8]int8 Wchan uint64 Login [32]int8 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 int32 Spare int32 Svuid uint32 Svgid uint32 Emul [8]int8 Rlim_rss_cur uint64 Cpuid uint64 Vm_map_size uint64 Tid int32 Rtableid uint32 } type Priority struct{} type KinfoVmentry struct { Start uint32 End uint32 Guard uint32 Fspace uint32 Fspace_augment uint32 Offset uint64 Wired_count int32 Etype int32 Protection int32 Max_protection int32 Advice int32 Inheritance int32 Flags uint8 Pad_cgo_0 [3]byte } gopsutil-3.24.1/process/process_openbsd_amd64.go000066400000000000000000000066511455407747200216660ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs 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 = 0x268 ) 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 Acflag uint16 Comm [24]int8 Wmesg [8]int8 Wchan uint64 Login [32]int8 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 Pad_cgo_0 [4]byte 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 int32 Spare int32 Svuid uint32 Svgid uint32 Emul [8]int8 Rlim_rss_cur uint64 Cpuid uint64 Vm_map_size uint64 Tid int32 Rtableid uint32 } 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 } gopsutil-3.24.1/process/process_openbsd_arm.go000066400000000000000000000067271455407747200215360ustar00rootroot00000000000000//go:build openbsd && arm // +build openbsd,arm // 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 = 0x4 sizeofShort = 0x2 sizeofInt = 0x4 sizeofLong = 0x4 sizeofLongLong = 0x8 ) const ( sizeOfKinfoVmentry = 0x38 sizeOfKinfoProc = 0x264 ) const ( SIDL = 1 SRUN = 2 SSLEEP = 3 SSTOP = 4 SZOMB = 5 SDEAD = 6 SONPROC = 7 ) type ( _C_short int16 _C_int int32 _C_long int32 _C_long_long int64 ) type Timespec struct { Sec int64 Nsec int32 } type Timeval struct { Sec int64 Usec int32 } type Rusage struct { Utime Timeval Stime Timeval Maxrss int32 Ixrss int32 Idrss int32 Isrss int32 Minflt int32 Majflt int32 Nswap int32 Inblock int32 Oublock int32 Msgsnd int32 Msgrcv int32 Nsignals int32 Nvcsw int32 Nivcsw int32 } 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 Acflag uint16 Comm [24]int8 Wmesg [8]int8 Wchan uint64 Login [32]int8 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 int32 Spare int32 Svuid uint32 Svgid uint32 Emul [8]int8 Rlim_rss_cur uint64 Cpuid uint64 Vm_map_size uint64 Tid int32 Rtableid uint32 } type Priority struct{} type KinfoVmentry struct { Start uint32 End uint32 Guard uint32 Fspace uint32 Fspace_augment uint32 Offset uint64 Wired_count int32 Etype int32 Protection int32 Max_protection int32 Advice int32 Inheritance int32 Flags uint8 Pad_cgo_0 [3]byte } gopsutil-3.24.1/process/process_openbsd_arm64.go000066400000000000000000000067641455407747200217110ustar00rootroot00000000000000//go:build openbsd && arm64 // +build openbsd,arm64 // 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 = 0x270 ) 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 Acflag 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 Spare int32 Svuid uint32 Svgid uint32 Emul [8]uint8 Rlim_rss_cur uint64 Cpuid uint64 Vm_map_size uint64 Tid int32 Rtableid uint32 Pledge uint64 } 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 } gopsutil-3.24.1/process/process_plan9.go000066400000000000000000000137101455407747200202560ustar00rootroot00000000000000//go:build plan9 // +build plan9 package process import ( "context" "syscall" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/net" ) type Signal = syscall.Note type MemoryMapsStat struct { Path string `json:"path"` Rss uint64 `json:"rss"` Size uint64 `json:"size"` Pss uint64 `json:"pss"` SharedClean uint64 `json:"sharedClean"` SharedDirty uint64 `json:"sharedDirty"` PrivateClean uint64 `json:"privateClean"` PrivateDirty uint64 `json:"privateDirty"` Referenced uint64 `json:"referenced"` Anonymous uint64 `json:"anonymous"` Swap uint64 `json:"swap"` } type MemoryInfoExStat struct{} func pidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { return nil, common.ErrNotImplementedError } func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { return false, common.ErrNotImplementedError } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) NameWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) TgidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { return nil, common.ErrNotImplementedError } func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { return 0, common.ErrNotImplementedError } func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { return []string{""}, common.ErrNotImplementedError } func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { return false, common.ErrNotImplementedError } func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { return nil, common.ErrNotImplementedError } func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) SendSignalWithContext(ctx context.Context, sig Signal) error { return common.ErrNotImplementedError } func (p *Process) SuspendWithContext(ctx context.Context) error { return common.ErrNotImplementedError } func (p *Process) ResumeWithContext(ctx context.Context) error { return common.ErrNotImplementedError } func (p *Process) TerminateWithContext(ctx context.Context) error { return common.ErrNotImplementedError } func (p *Process) KillWithContext(ctx context.Context) error { return common.ErrNotImplementedError } func (p *Process) UsernameWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { return nil, common.ErrNotImplementedError } gopsutil-3.24.1/process/process_posix.go000066400000000000000000000100631455407747200203730ustar00rootroot00000000000000//go:build linux || freebsd || openbsd || darwin || solaris // +build linux freebsd openbsd darwin solaris package process import ( "context" "errors" "fmt" "os" "os/user" "path/filepath" "strconv" "strings" "syscall" "golang.org/x/sys/unix" "github.com/shirou/gopsutil/v3/internal/common" ) type Signal = syscall.Signal // POSIX func getTerminalMap() (map[uint64]string, error) { ret := make(map[uint64]string) var termfiles []string d, err := os.Open("/dev") if err != nil { return nil, err } defer d.Close() devnames, err := d.Readdirnames(-1) if err != nil { return nil, err } for _, devname := range devnames { if strings.HasPrefix(devname, "/dev/tty") { termfiles = append(termfiles, "/dev/tty/"+devname) } } var ptsnames []string ptsd, err := os.Open("/dev/pts") if err != nil { ptsnames, _ = filepath.Glob("/dev/ttyp*") if ptsnames == nil { return nil, err } } defer ptsd.Close() if ptsnames == nil { defer ptsd.Close() ptsnames, err = ptsd.Readdirnames(-1) if err != nil { return nil, err } for _, ptsname := range ptsnames { termfiles = append(termfiles, "/dev/pts/"+ptsname) } } else { termfiles = ptsnames } for _, name := range termfiles { stat := unix.Stat_t{} if err = unix.Stat(name, &stat); err != nil { return nil, err } rdev := uint64(stat.Rdev) ret[rdev] = strings.Replace(name, "/dev", "", -1) } return ret, nil } // isMount is a port of python's os.path.ismount() // https://github.com/python/cpython/blob/08ff4369afca84587b1c82034af4e9f64caddbf2/Lib/posixpath.py#L186-L216 // https://docs.python.org/3/library/os.path.html#os.path.ismount func isMount(path string) bool { // Check symlinkness with os.Lstat; unix.DT_LNK is not portable fileInfo, err := os.Lstat(path) if err != nil { return false } if fileInfo.Mode()&os.ModeSymlink != 0 { return false } var stat1 unix.Stat_t if err := unix.Lstat(path, &stat1); err != nil { return false } parent := filepath.Join(path, "..") var stat2 unix.Stat_t if err := unix.Lstat(parent, &stat2); err != nil { return false } return stat1.Dev != stat2.Dev || stat1.Ino == stat2.Ino } func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { if pid <= 0 { return false, fmt.Errorf("invalid pid %v", pid) } proc, err := os.FindProcess(int(pid)) if err != nil { return false, err } if isMount(common.HostProcWithContext(ctx)) { // if //proc exists and is mounted, check if //proc/ folder exists _, err := os.Stat(common.HostProcWithContext(ctx, strconv.Itoa(int(pid)))) if os.IsNotExist(err) { return false, nil } return err == nil, err } // procfs does not exist or is not mounted, check PID existence by signalling the pid err = proc.Signal(syscall.Signal(0)) if err == nil { return true, nil } if errors.Is(err, os.ErrProcessDone) { return false, nil } var errno syscall.Errno if !errors.As(err, &errno) { return false, err } switch errno { case syscall.ESRCH: return false, nil case syscall.EPERM: return true, nil } return false, err } func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error { process, err := os.FindProcess(int(p.Pid)) if err != nil { return err } err = process.Signal(sig) if err != nil { return err } return nil } func (p *Process) SuspendWithContext(ctx context.Context) error { return p.SendSignalWithContext(ctx, unix.SIGSTOP) } func (p *Process) ResumeWithContext(ctx context.Context) error { return p.SendSignalWithContext(ctx, unix.SIGCONT) } func (p *Process) TerminateWithContext(ctx context.Context) error { return p.SendSignalWithContext(ctx, unix.SIGTERM) } func (p *Process) KillWithContext(ctx context.Context) error { return p.SendSignalWithContext(ctx, unix.SIGKILL) } func (p *Process) UsernameWithContext(ctx context.Context) (string, error) { uids, err := p.UidsWithContext(ctx) if err != nil { return "", err } if len(uids) > 0 { u, err := user.LookupId(strconv.Itoa(int(uids[0]))) if err != nil { return "", err } return u.Username, nil } return "", nil } gopsutil-3.24.1/process/process_posix_test.go000066400000000000000000000004741455407747200214370ustar00rootroot00000000000000//go:build linux || freebsd // +build linux freebsd package process import ( "os" "testing" "golang.org/x/sys/unix" ) func Test_SendSignal(t *testing.T) { checkPid := os.Getpid() p, _ := NewProcess(int32(checkPid)) err := p.SendSignal(unix.SIGCONT) if err != nil { t.Errorf("send signal %v", err) } } gopsutil-3.24.1/process/process_race_test.go000066400000000000000000000007271455407747200212100ustar00rootroot00000000000000//go:build race // +build race package process import ( "sync" "testing" ) func Test_Process_Ppid_Race(t *testing.T) { wg := sync.WaitGroup{} testCount := 10 p := testGetProcess() wg.Add(testCount) for i := 0; i < testCount; i++ { go func(j int) { ppid, err := p.Ppid() wg.Done() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("Ppid() failed, %v", err) } if j == 9 { t.Logf("Ppid(): %d", ppid) } }(i) } wg.Wait() } gopsutil-3.24.1/process/process_solaris.go000066400000000000000000000200431455407747200207040ustar00rootroot00000000000000package process import ( "bytes" "context" "os" "strconv" "strings" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/net" ) type MemoryMapsStat struct { Path string `json:"path"` Rss uint64 `json:"rss"` Size uint64 `json:"size"` Pss uint64 `json:"pss"` SharedClean uint64 `json:"sharedClean"` SharedDirty uint64 `json:"sharedDirty"` PrivateClean uint64 `json:"privateClean"` PrivateDirty uint64 `json:"privateDirty"` Referenced uint64 `json:"referenced"` Anonymous uint64 `json:"anonymous"` Swap uint64 `json:"swap"` } type MemoryInfoExStat struct{} func pidsWithContext(ctx context.Context) ([]int32, error) { return readPidsFromDir(common.HostProcWithContext(ctx)) } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { out := []*Process{} pids, err := PidsWithContext(ctx) if err != nil { return out, err } for _, pid := range pids { p, err := NewProcessWithContext(ctx, pid) if err != nil { continue } out = append(out, p) } return out, nil } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) NameWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) TgidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { exe, err := p.fillFromPathAOutWithContext(ctx) if os.IsNotExist(err) { exe, err = p.fillFromExecnameWithContext(ctx) } return exe, err } func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { return p.fillFromCmdlineWithContext(ctx) } func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { return p.fillSliceFromCmdlineWithContext(ctx) } func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { return 0, common.ErrNotImplementedError } func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return p.fillFromPathCwdWithContext(ctx) } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { return []string{""}, common.ErrNotImplementedError } func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { return false, common.ErrNotImplementedError } func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { _, fnames, err := p.fillFromfdListWithContext(ctx) return int32(len(fnames)), err } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { return nil, common.ErrNotImplementedError } func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { return nil, common.ErrNotImplementedError } /** ** Internal functions **/ func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) { pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "fd") d, err := os.Open(statPath) if err != nil { return statPath, []string{}, err } defer d.Close() fnames, err := d.Readdirnames(-1) return statPath, fnames, err } func (p *Process) fillFromPathCwdWithContext(ctx context.Context) (string, error) { pid := p.Pid cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "path", "cwd") cwd, err := os.Readlink(cwdPath) if err != nil { return "", err } return cwd, nil } func (p *Process) fillFromPathAOutWithContext(ctx context.Context) (string, error) { pid := p.Pid cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "path", "a.out") exe, err := os.Readlink(cwdPath) if err != nil { return "", err } return exe, nil } func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, error) { pid := p.Pid execNamePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "execname") exe, err := os.ReadFile(execNamePath) if err != nil { return "", err } return string(exe), nil } func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) { pid := p.Pid cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdline, err := os.ReadFile(cmdPath) if err != nil { return "", err } ret := strings.FieldsFunc(string(cmdline), func(r rune) bool { if r == '\u0000' { return true } return false }) return strings.Join(ret, " "), nil } func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) { pid := p.Pid cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") cmdline, err := os.ReadFile(cmdPath) if err != nil { return nil, err } if len(cmdline) == 0 { return nil, nil } if cmdline[len(cmdline)-1] == 0 { cmdline = cmdline[:len(cmdline)-1] } parts := bytes.Split(cmdline, []byte{0}) var strParts []string for _, p := range parts { strParts = append(strParts, string(p)) } return strParts, nil } func readPidsFromDir(path string) ([]int32, error) { var ret []int32 d, err := os.Open(path) if err != nil { return nil, err } defer d.Close() fnames, err := d.Readdirnames(-1) if err != nil { return nil, err } for _, fname := range fnames { pid, err := strconv.ParseInt(fname, 10, 32) if err != nil { // if not numeric name, just skip continue } ret = append(ret, int32(pid)) } return ret, nil } gopsutil-3.24.1/process/process_test.go000066400000000000000000000504651455407747200202220ustar00rootroot00000000000000package process import ( "bufio" "errors" "fmt" "io" "net" "os" "os/exec" "os/user" "path/filepath" "reflect" "runtime" "strconv" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/shirou/gopsutil/v3/internal/common" ) var mu sync.Mutex func skipIfNotImplementedErr(t *testing.T, err error) { if errors.Is(err, common.ErrNotImplementedError) { t.Skip("not implemented") } } func testGetProcess() Process { checkPid := os.Getpid() // process.test ret, _ := NewProcess(int32(checkPid)) return *ret } func Test_Pids(t *testing.T) { ret, err := Pids() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if len(ret) == 0 { t.Errorf("could not get pids %v", ret) } } func Test_Pid_exists(t *testing.T) { checkPid := os.Getpid() ret, err := PidExists(int32(checkPid)) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if ret == false { t.Errorf("could not get process exists: %v", ret) } } func Test_NewProcess(t *testing.T) { checkPid := os.Getpid() ret, err := NewProcess(int32(checkPid)) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } empty := &Process{} if runtime.GOOS != "windows" { // Windows pid is 0 if empty == ret { t.Errorf("error %v", ret) } } } func Test_Process_memory_maps(t *testing.T) { checkPid := os.Getpid() ret, err := NewProcess(int32(checkPid)) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } // ungrouped memory maps mmaps, err := ret.MemoryMaps(false) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("memory map get error %v", err) } empty := MemoryMapsStat{} for _, m := range *mmaps { if m == empty { t.Errorf("memory map get error %v", m) } } // grouped memory maps mmaps, err = ret.MemoryMaps(true) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("memory map get error %v", err) } if len(*mmaps) != 1 { t.Errorf("grouped memory maps length (%v) is not equal to 1", len(*mmaps)) } if (*mmaps)[0] == empty { t.Errorf("memory map is empty") } } func Test_Process_MemoryInfo(t *testing.T) { p := testGetProcess() v, err := p.MemoryInfo() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting memory info error %v", err) } empty := MemoryInfoStat{} if v == nil || *v == empty { t.Errorf("could not get memory info %v", v) } } func Test_Process_CmdLine(t *testing.T) { p := testGetProcess() v, err := p.Cmdline() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting cmdline error %v", err) } if !strings.Contains(v, "process.test") { t.Errorf("invalid cmd line %v", v) } } func Test_Process_CmdLineSlice(t *testing.T) { p := testGetProcess() v, err := p.CmdlineSlice() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("getting cmdline slice error %v", err) } if !reflect.DeepEqual(v, os.Args) { t.Errorf("returned cmdline slice not as expected:\nexp: %v\ngot: %v", os.Args, v) } } func Test_Process_Ppid(t *testing.T) { p := testGetProcess() v, err := p.Ppid() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting ppid error %v", err) } if v == 0 { t.Errorf("return value is 0 %v", v) } expected := os.Getppid() if v != int32(expected) { t.Errorf("return value is %v, expected %v", v, expected) } } func Test_Process_Status(t *testing.T) { p := testGetProcess() v, err := p.Status() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting status error %v", err) } if len(v) == 0 { t.Errorf("could not get state") } if v[0] != Running && v[0] != Sleep { t.Errorf("got wrong state, %v", v) } } func Test_Process_Terminal(t *testing.T) { p := testGetProcess() _, err := p.Terminal() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting terminal error %v", err) } } func Test_Process_IOCounters(t *testing.T) { p := testGetProcess() v, err := p.IOCounters() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting iocounter error %v", err) return } empty := &IOCountersStat{} if v == empty { t.Errorf("error %v", v) } } func Test_Process_NumCtx(t *testing.T) { p := testGetProcess() _, err := p.NumCtxSwitches() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting numctx error %v", err) return } } func Test_Process_Nice(t *testing.T) { 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() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting nice error %v", err) } if runtime.GOOS != "windows" && n != 0 && n != 20 && n != 8 { t.Errorf("invalid nice: %d", n) } } func Test_Process_Groups(t *testing.T) { p := testGetProcess() v, err := p.Groups() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting groups error %v", err) } if len(v) == 0 { t.Skip("Groups is empty") } if v[0] < 0 { t.Errorf("invalid Groups: %v", v) } } func Test_Process_NumThread(t *testing.T) { p := testGetProcess() n, err := p.NumThreads() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting NumThread error %v", err) } if n < 0 { t.Errorf("invalid NumThread: %d", n) } } func Test_Process_Threads(t *testing.T) { p := testGetProcess() n, err := p.NumThreads() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting NumThread error %v", err) } if n < 0 { t.Errorf("invalid NumThread: %d", n) } ts, err := p.Threads() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting Threads error %v", err) } if len(ts) != int(n) { t.Errorf("unexpected number of threads: %v vs %v", len(ts), n) } } func Test_Process_Name(t *testing.T) { p := testGetProcess() n, err := p.Name() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting name error %v", err) } if !strings.Contains(n, "process.test") { t.Errorf("invalid Name %s", n) } } func Test_Process_Long_Name_With_Spaces(t *testing.T) { tmpdir, err := os.MkdirTemp("", "") if err != nil { t.Fatalf("unable to create temp dir %v", err) } defer os.RemoveAll(tmpdir) // clean up tmpfilepath := filepath.Join(tmpdir, "loooong name with spaces.go") tmpfile, err := os.Create(tmpfilepath) if err != nil { t.Fatalf("unable to create temp file %v", err) } tmpfilecontent := []byte("package main\nimport(\n\"time\"\n)\nfunc main(){\nfor range time.Tick(time.Second) {}\n}") if _, err := tmpfile.Write(tmpfilecontent); err != nil { tmpfile.Close() t.Fatalf("unable to write temp file %v", err) } if err := tmpfile.Close(); err != nil { t.Fatalf("unable to close temp file %v", err) } err = exec.Command("go", "build", "-o", tmpfile.Name()+".exe", tmpfile.Name()).Run() if err != nil { t.Fatalf("unable to build temp file %v", err) } cmd := exec.Command(tmpfile.Name() + ".exe") assert.Nil(t, cmd.Start()) time.Sleep(100 * time.Millisecond) p, err := NewProcess(int32(cmd.Process.Pid)) skipIfNotImplementedErr(t, err) assert.Nil(t, err) n, err := p.Name() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("getting name error %v", err) } basename := filepath.Base(tmpfile.Name() + ".exe") if basename != n { t.Fatalf("%s != %s", basename, n) } cmd.Process.Kill() } func Test_Process_Long_Name(t *testing.T) { tmpdir, err := os.MkdirTemp("", "") if err != nil { t.Fatalf("unable to create temp dir %v", err) } defer os.RemoveAll(tmpdir) // clean up tmpfilepath := filepath.Join(tmpdir, "looooooooooooooooooooong.go") tmpfile, err := os.Create(tmpfilepath) if err != nil { t.Fatalf("unable to create temp file %v", err) } tmpfilecontent := []byte("package main\nimport(\n\"time\"\n)\nfunc main(){\nfor range time.Tick(time.Second) {}\n}") if _, err := tmpfile.Write(tmpfilecontent); err != nil { tmpfile.Close() t.Fatalf("unable to write temp file %v", err) } if err := tmpfile.Close(); err != nil { t.Fatalf("unable to close temp file %v", err) } err = exec.Command("go", "build", "-o", tmpfile.Name()+".exe", tmpfile.Name()).Run() if err != nil { t.Fatalf("unable to build temp file %v", err) } cmd := exec.Command(tmpfile.Name() + ".exe") assert.Nil(t, cmd.Start()) time.Sleep(100 * time.Millisecond) p, err := NewProcess(int32(cmd.Process.Pid)) skipIfNotImplementedErr(t, err) assert.Nil(t, err) n, err := p.Name() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("getting name error %v", err) } basename := filepath.Base(tmpfile.Name() + ".exe") if basename != n { t.Fatalf("%s != %s", basename, n) } cmd.Process.Kill() } func Test_Process_Name_Against_Python(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("only applies to posix") } py3Path, err := exec.LookPath("python3") if err != nil { t.Skipf("python3 not found: %s", err) } if out, err := exec.Command(py3Path, "-c", "import psutil").CombinedOutput(); err != nil { t.Skipf("psutil not found for %s: %s", py3Path, out) } tmpdir, err := os.MkdirTemp("", "") if err != nil { t.Fatalf("unable to create temp dir %v", err) } defer os.RemoveAll(tmpdir) // clean up tmpfilepath := filepath.Join(tmpdir, "looooooooooooooooooooong.py") tmpfile, err := os.Create(tmpfilepath) if err != nil { t.Fatalf("unable to create temp file %v", err) } tmpfilecontent := []byte("#!" + py3Path + "\nimport psutil, time\nprint(psutil.Process().name(), flush=True)\nwhile True:\n\ttime.sleep(1)") if _, err := tmpfile.Write(tmpfilecontent); err != nil { tmpfile.Close() t.Fatalf("unable to write temp file %v", err) } if err := tmpfile.Chmod(0o744); err != nil { t.Fatalf("unable to chmod u+x temp file %v", err) } if err := tmpfile.Close(); err != nil { t.Fatalf("unable to close temp file %v", err) } cmd := exec.Command(tmpfilepath) outPipe, _ := cmd.StdoutPipe() scanner := bufio.NewScanner(outPipe) cmd.Start() defer cmd.Process.Kill() scanner.Scan() pyName := scanner.Text() // first line printed by py3 script, its name t.Logf("pyName %s", pyName) p, err := NewProcess(int32(cmd.Process.Pid)) skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("getting process error %v", err) } name, err := p.Name() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("getting name error %v", err) } if pyName != name { t.Fatalf("psutil and gopsutil process.Name() results differ: expected %s, got %s", pyName, name) } } func Test_Process_Exe(t *testing.T) { p := testGetProcess() n, err := p.Exe() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting Exe error %v", err) } if !strings.Contains(n, "process.test") { t.Errorf("invalid Exe %s", n) } } func Test_Process_CpuPercent(t *testing.T) { p := testGetProcess() _, err := p.Percent(0) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } duration := time.Duration(1000) * time.Microsecond time.Sleep(duration) percent, err := p.Percent(0) if err != nil { t.Errorf("error %v", err) } numcpu := runtime.NumCPU() // if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO if percent < 0.0 { t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu) } } func Test_Process_CpuPercentLoop(t *testing.T) { p := testGetProcess() numcpu := runtime.NumCPU() for i := 0; i < 2; i++ { duration := time.Duration(100) * time.Microsecond percent, err := p.Percent(duration) skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } // if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO if percent < 0.0 { t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu) } } } func Test_Process_CreateTime(t *testing.T) { if os.Getenv("CI") == "true" { t.Skip("Skip CI") } p := testGetProcess() c, err := p.CreateTime() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("error %v", err) } if c < 1420000000 { t.Errorf("process created time is wrong.") } gotElapsed := time.Since(time.Unix(int64(c/1000), 0)) maxElapsed := time.Duration(20 * time.Second) if gotElapsed >= maxElapsed { t.Errorf("this process has not been running for %v", gotElapsed) } } func Test_Parent(t *testing.T) { p := testGetProcess() c, err := p.Parent() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("error %v", err) } if c == nil { t.Fatalf("could not get parent") } if c.Pid == 0 { t.Fatalf("wrong parent pid") } } func Test_Connections(t *testing.T) { p := testGetProcess() addr, err := net.ResolveTCPAddr("tcp", "localhost:0") // dynamically get a random open port from OS if err != nil { t.Fatalf("unable to resolve localhost: %v", err) } l, err := net.ListenTCP(addr.Network(), addr) if err != nil { t.Fatalf("unable to listen on %v: %v", addr, err) } defer l.Close() tcpServerAddr := l.Addr().String() tcpServerAddrIP := strings.Split(tcpServerAddr, ":")[0] tcpServerAddrPort, err := strconv.ParseUint(strings.Split(tcpServerAddr, ":")[1], 10, 32) if err != nil { t.Fatalf("unable to parse tcpServerAddr port: %v", err) } serverEstablished := make(chan struct{}) go func() { // TCP listening goroutine conn, err := l.Accept() if err != nil { panic(err) } defer conn.Close() serverEstablished <- struct{}{} _, err = io.ReadAll(conn) if err != nil { panic(err) } }() conn, err := net.Dial("tcp", tcpServerAddr) if err != nil { t.Fatalf("unable to dial %v: %v", tcpServerAddr, err) } defer conn.Close() // Rarely the call to net.Dial returns before the server connection is // established. Wait so that the test doesn't fail. <-serverEstablished c, err := p.Connections() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("error %v", err) } if len(c) == 0 { t.Fatal("no connections found") } serverConnections := 0 for _, connection := range c { if connection.Laddr.IP == tcpServerAddrIP && connection.Laddr.Port == uint32(tcpServerAddrPort) && connection.Raddr.Port != 0 { if connection.Status != "ESTABLISHED" { t.Fatalf("expected server connection to be ESTABLISHED, have %+v", connection) } serverConnections++ } } clientConnections := 0 for _, connection := range c { if connection.Raddr.IP == tcpServerAddrIP && connection.Raddr.Port == uint32(tcpServerAddrPort) { if connection.Status != "ESTABLISHED" { t.Fatalf("expected client connection to be ESTABLISHED, have %+v", connection) } clientConnections++ } } if serverConnections != 1 { // two established connections, one for the server, the other for the client t.Fatalf("expected 1 server connection, have %d.\nDetails: %+v", serverConnections, c) } if clientConnections != 1 { // two established connections, one for the server, the other for the client t.Fatalf("expected 1 server connection, have %d.\nDetails: %+v", clientConnections, c) } } func Test_Children(t *testing.T) { p := testGetProcess() var cmd *exec.Cmd if runtime.GOOS == "windows" { cmd = exec.Command("ping", "localhost", "-n", "4") } else { cmd = exec.Command("sleep", "3") } assert.Nil(t, cmd.Start()) time.Sleep(100 * time.Millisecond) c, err := p.Children() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("error %v", err) } if len(c) == 0 { t.Fatalf("children is empty") } found := false for _, child := range c { if child.Pid == int32(cmd.Process.Pid) { found = true break } } if !found { t.Errorf("could not find child %d", cmd.Process.Pid) } } func Test_Username(t *testing.T) { myPid := os.Getpid() currentUser, _ := user.Current() myUsername := currentUser.Username process, _ := NewProcess(int32(myPid)) pidUsername, err := process.Username() skipIfNotImplementedErr(t, err) assert.Equal(t, myUsername, pidUsername) t.Log(pidUsername) } func Test_CPUTimes(t *testing.T) { pid := os.Getpid() process, err := NewProcess(int32(pid)) skipIfNotImplementedErr(t, err) assert.Nil(t, err) spinSeconds := 0.2 cpuTimes0, err := process.Times() skipIfNotImplementedErr(t, err) assert.Nil(t, err) // Spin for a duration of spinSeconds t0 := time.Now() tGoal := t0.Add(time.Duration(spinSeconds*1000) * time.Millisecond) assert.Nil(t, err) for time.Now().Before(tGoal) { // This block intentionally left blank } cpuTimes1, err := process.Times() assert.Nil(t, err) if cpuTimes0 == nil || cpuTimes1 == nil { t.FailNow() } measuredElapsed := cpuTimes1.Total() - cpuTimes0.Total() message := fmt.Sprintf("Measured %fs != spun time of %fs\ncpuTimes0=%v\ncpuTimes1=%v", measuredElapsed, spinSeconds, cpuTimes0, cpuTimes1) assert.True(t, measuredElapsed > float64(spinSeconds)/5, message) assert.True(t, measuredElapsed < float64(spinSeconds)*5, message) } func Test_OpenFiles(t *testing.T) { fp, err := os.Open("process_test.go") assert.Nil(t, err) defer func() { err := fp.Close() assert.Nil(t, err) }() pid := os.Getpid() p, err := NewProcess(int32(pid)) skipIfNotImplementedErr(t, err) assert.Nil(t, err) v, err := p.OpenFiles() skipIfNotImplementedErr(t, err) assert.Nil(t, err) assert.NotEmpty(t, v) // test always open files. for _, vv := range v { assert.NotEqual(t, "", vv.Path) } } func Test_Kill(t *testing.T) { var cmd *exec.Cmd if runtime.GOOS == "windows" { cmd = exec.Command("ping", "localhost", "-n", "4") } else { cmd = exec.Command("sleep", "3") } assert.Nil(t, cmd.Start()) time.Sleep(100 * time.Millisecond) p, err := NewProcess(int32(cmd.Process.Pid)) skipIfNotImplementedErr(t, err) assert.Nil(t, err) err = p.Kill() skipIfNotImplementedErr(t, err) assert.Nil(t, err) cmd.Wait() } func Test_IsRunning(t *testing.T) { var cmd *exec.Cmd if runtime.GOOS == "windows" { cmd = exec.Command("ping", "localhost", "-n", "2") } else { cmd = exec.Command("sleep", "1") } cmd.Start() p, err := NewProcess(int32(cmd.Process.Pid)) skipIfNotImplementedErr(t, err) assert.Nil(t, err) running, err := p.IsRunning() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("IsRunning error: %v", err) } if !running { t.Fatalf("process should be found running") } cmd.Wait() running, err = p.IsRunning() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("IsRunning error: %v", err) } if running { t.Fatalf("process should NOT be found running") } } func Test_Process_Environ(t *testing.T) { tmpdir, err := os.MkdirTemp("", "") if err != nil { t.Fatalf("unable to create temp dir %v", err) } defer os.RemoveAll(tmpdir) // clean up tmpfilepath := filepath.Join(tmpdir, "test.go") tmpfile, err := os.Create(tmpfilepath) if err != nil { t.Fatalf("unable to create temp file %v", err) } tmpfilecontent := []byte("package main\nimport(\n\"time\"\n)\nfunc main(){\nfor range time.Tick(time.Second) {}\n}") if _, err := tmpfile.Write(tmpfilecontent); err != nil { tmpfile.Close() t.Fatalf("unable to write temp file %v", err) } if err := tmpfile.Close(); err != nil { t.Fatalf("unable to close temp file %v", err) } err = exec.Command("go", "build", "-o", tmpfile.Name()+".exe", tmpfile.Name()).Run() if err != nil { t.Fatalf("unable to build temp file %v", err) } cmd := exec.Command(tmpfile.Name() + ".exe") cmd.Env = []string{"testkey=envvalue"} assert.Nil(t, cmd.Start()) defer cmd.Process.Kill() time.Sleep(100 * time.Millisecond) p, err := NewProcess(int32(cmd.Process.Pid)) skipIfNotImplementedErr(t, err) assert.Nil(t, err) envs, err := p.Environ() skipIfNotImplementedErr(t, err) if err != nil { t.Errorf("getting environ error %v", err) } var envvarFound bool for _, envvar := range envs { if envvar == "testkey=envvalue" { envvarFound = true break } } if !envvarFound { t.Error("environment variable not found") } } func Test_Process_Cwd(t *testing.T) { myPid := os.Getpid() currentWorkingDirectory, _ := os.Getwd() process, _ := NewProcess(int32(myPid)) pidCwd, err := process.Cwd() skipIfNotImplementedErr(t, err) if err != nil { t.Fatalf("getting cwd error %v", err) } pidCwd = strings.TrimSuffix(pidCwd, string(os.PathSeparator)) assert.Equal(t, currentWorkingDirectory, pidCwd) t.Log(pidCwd) } func BenchmarkNewProcess(b *testing.B) { checkPid := os.Getpid() for i := 0; i < b.N; i++ { NewProcess(int32(checkPid)) } } func BenchmarkProcessName(b *testing.B) { p := testGetProcess() for i := 0; i < b.N; i++ { p.Name() } } func BenchmarkProcessPpid(b *testing.B) { p := testGetProcess() for i := 0; i < b.N; i++ { p.Ppid() } } func BenchmarkProcesses(b *testing.B) { for i := 0; i < b.N; i++ { ps, err := Processes() require.NoError(b, err) require.Greater(b, len(ps), 0) } } gopsutil-3.24.1/process/process_windows.go000066400000000000000000001007441455407747200207310ustar00rootroot00000000000000//go:build windows // +build windows package process import ( "bufio" "context" "errors" "fmt" "io" "os" "path/filepath" "reflect" "strings" "syscall" "time" "unicode/utf16" "unsafe" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/internal/common" "github.com/shirou/gopsutil/v3/net" "golang.org/x/sys/windows" ) type Signal = syscall.Signal var ( modntdll = windows.NewLazySystemDLL("ntdll.dll") procNtResumeProcess = modntdll.NewProc("NtResumeProcess") procNtSuspendProcess = modntdll.NewProc("NtSuspendProcess") modpsapi = windows.NewLazySystemDLL("psapi.dll") procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") procGetProcessImageFileNameW = modpsapi.NewProc("GetProcessImageFileNameW") advapi32 = windows.NewLazySystemDLL("advapi32.dll") procLookupPrivilegeValue = advapi32.NewProc("LookupPrivilegeValueW") procAdjustTokenPrivileges = advapi32.NewProc("AdjustTokenPrivileges") procQueryFullProcessImageNameW = common.Modkernel32.NewProc("QueryFullProcessImageNameW") procGetPriorityClass = common.Modkernel32.NewProc("GetPriorityClass") procGetProcessIoCounters = common.Modkernel32.NewProc("GetProcessIoCounters") procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo") processorArchitecture uint ) const processQueryInformation = windows.PROCESS_QUERY_LIMITED_INFORMATION type systemProcessorInformation struct { ProcessorArchitecture uint16 ProcessorLevel uint16 ProcessorRevision uint16 Reserved uint16 ProcessorFeatureBits uint16 } type systemInfo struct { wProcessorArchitecture uint16 wReserved uint16 dwpageSize uint32 lpMinimumApplicationAddress uintptr lpMaximumApplicationAddress uintptr dwActiveProcessorMask uintptr dwNumberOfProcessors uint32 dwProcessorType uint32 dwAllocationGranularity uint32 wProcessorLevel uint16 wProcessorRevision uint16 } // Memory_info_ex is different between OSes type MemoryInfoExStat struct{} type MemoryMapsStat struct{} // ioCounters is an equivalent representation of IO_COUNTERS in the Windows API. // https://docs.microsoft.com/windows/win32/api/winnt/ns-winnt-io_counters type ioCounters struct { ReadOperationCount uint64 WriteOperationCount uint64 OtherOperationCount uint64 ReadTransferCount uint64 WriteTransferCount uint64 OtherTransferCount uint64 } type processBasicInformation32 struct { Reserved1 uint32 PebBaseAddress uint32 Reserved2 uint32 Reserved3 uint32 UniqueProcessId uint32 Reserved4 uint32 } type processBasicInformation64 struct { Reserved1 uint64 PebBaseAddress uint64 Reserved2 uint64 Reserved3 uint64 UniqueProcessId uint64 Reserved4 uint64 } type processEnvironmentBlock32 struct { Reserved1 [2]uint8 BeingDebugged uint8 Reserved2 uint8 Reserved3 [2]uint32 Ldr uint32 ProcessParameters uint32 // More fields which we don't use so far } type processEnvironmentBlock64 struct { Reserved1 [2]uint8 BeingDebugged uint8 Reserved2 uint8 _ [4]uint8 // padding, since we are 64 bit, the next pointer is 64 bit aligned (when compiling for 32 bit, this is not the case without manual padding) Reserved3 [2]uint64 Ldr uint64 ProcessParameters uint64 // More fields which we don't use so far } type rtlUserProcessParameters32 struct { Reserved1 [16]uint8 ConsoleHandle uint32 ConsoleFlags uint32 StdInputHandle uint32 StdOutputHandle uint32 StdErrorHandle uint32 CurrentDirectoryPathNameLength uint16 _ uint16 // Max Length CurrentDirectoryPathAddress uint32 CurrentDirectoryHandle uint32 DllPathNameLength uint16 _ uint16 // Max Length DllPathAddress uint32 ImagePathNameLength uint16 _ uint16 // Max Length ImagePathAddress uint32 CommandLineLength uint16 _ uint16 // Max Length CommandLineAddress uint32 EnvironmentAddress uint32 // More fields which we don't use so far } type rtlUserProcessParameters64 struct { Reserved1 [16]uint8 ConsoleHandle uint64 ConsoleFlags uint64 StdInputHandle uint64 StdOutputHandle uint64 StdErrorHandle uint64 CurrentDirectoryPathNameLength uint16 _ uint16 // Max Length _ uint32 // Padding CurrentDirectoryPathAddress uint64 CurrentDirectoryHandle uint64 DllPathNameLength uint16 _ uint16 // Max Length _ uint32 // Padding DllPathAddress uint64 ImagePathNameLength uint16 _ uint16 // Max Length _ uint32 // Padding ImagePathAddress uint64 CommandLineLength uint16 _ uint16 // Max Length _ uint32 // Padding CommandLineAddress uint64 EnvironmentAddress uint64 // More fields which we don't use so far } type winLUID struct { LowPart winDWord HighPart winLong } // LUID_AND_ATTRIBUTES type winLUIDAndAttributes struct { Luid winLUID Attributes winDWord } // TOKEN_PRIVILEGES type winTokenPrivileges struct { PrivilegeCount winDWord Privileges [1]winLUIDAndAttributes } type ( winLong int32 winDWord uint32 ) func init() { var systemInfo systemInfo procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo))) processorArchitecture = uint(systemInfo.wProcessorArchitecture) // enable SeDebugPrivilege https://github.com/midstar/proci/blob/6ec79f57b90ba3d9efa2a7b16ef9c9369d4be875/proci_windows.go#L80-L119 handle, err := syscall.GetCurrentProcess() if err != nil { return } var token syscall.Token err = syscall.OpenProcessToken(handle, 0x0028, &token) if err != nil { return } defer token.Close() tokenPrivileges := winTokenPrivileges{PrivilegeCount: 1} lpName := syscall.StringToUTF16("SeDebugPrivilege") ret, _, _ := procLookupPrivilegeValue.Call( 0, uintptr(unsafe.Pointer(&lpName[0])), uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0].Luid))) if ret == 0 { return } tokenPrivileges.Privileges[0].Attributes = 0x00000002 // SE_PRIVILEGE_ENABLED procAdjustTokenPrivileges.Call( uintptr(token), 0, uintptr(unsafe.Pointer(&tokenPrivileges)), uintptr(unsafe.Sizeof(tokenPrivileges)), 0, 0) } 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 = 0 var psSize uint32 = 1024 const dwordSize uint32 = 4 for { ps := make([]uint32, psSize) if err := windows.EnumProcesses(ps, &read); err != nil { return nil, err } if uint32(len(ps)) == read/dwordSize { // ps buffer was too small to host every results, retry with a bigger one psSize += 1024 continue } for _, pid := range ps[:read/dwordSize] { ret = append(ret, int32(pid)) } return ret, nil } } func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { if pid == 0 { // special case for pid 0 System Idle Process return true, nil } if pid < 0 { return false, fmt.Errorf("invalid pid %v", pid) } if pid%4 != 0 { // OpenProcess will succeed even on non-existing pid here https://devblogs.microsoft.com/oldnewthing/20080606-00/?p=22043 // so we list every pid just to be sure and be future-proof pids, err := PidsWithContext(ctx) if err != nil { return false, err } for _, i := range pids { if i == pid { return true, err } } return false, err } h, err := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid)) if err == windows.ERROR_ACCESS_DENIED { return true, nil } if err == windows.ERROR_INVALID_PARAMETER { return false, nil } if err != nil { return false, err } defer windows.CloseHandle(h) event, err := windows.WaitForSingleObject(h, 0) return event == uint32(windows.WAIT_TIMEOUT), err } func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { // if cached already, return from cache cachedPpid := p.getPpid() if cachedPpid != 0 { return cachedPpid, nil } ppid, _, _, err := getFromSnapProcess(p.Pid) if err != nil { return 0, err } // no errors and not cached already, so cache it p.setPpid(ppid) return ppid, nil } func (p *Process) NameWithContext(ctx context.Context) (string, error) { if p.Pid == 0 { return "System Idle Process", nil } if p.Pid == 4 { return "System", nil } exe, err := p.ExeWithContext(ctx) if err != nil { return "", fmt.Errorf("could not get Name: %s", err) } return filepath.Base(exe), nil } func (p *Process) TgidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) ExeWithContext(ctx context.Context) (string, error) { c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid)) if err != nil { return "", err } defer windows.CloseHandle(c) buf := make([]uint16, syscall.MAX_LONG_PATH) size := uint32(syscall.MAX_LONG_PATH) if err := procQueryFullProcessImageNameW.Find(); err == nil { // Vista+ ret, _, err := procQueryFullProcessImageNameW.Call( uintptr(c), uintptr(0), uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&size))) if ret == 0 { return "", err } return windows.UTF16ToString(buf[:]), nil } // XP fallback ret, _, err := procGetProcessImageFileNameW.Call(uintptr(c), uintptr(unsafe.Pointer(&buf[0])), uintptr(size)) if ret == 0 { return "", err } return common.ConvertDOSPath(windows.UTF16ToString(buf[:])), nil } func (p *Process) CmdlineWithContext(_ context.Context) (string, error) { cmdline, err := getProcessCommandLine(p.Pid) if err != nil { return "", fmt.Errorf("could not get CommandLine: %s", err) } return cmdline, nil } func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { cmdline, err := p.CmdlineWithContext(ctx) if err != nil { return nil, err } 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: %s", err) } return ru.CreationTime.Nanoseconds() / 1000000, nil } func (p *Process) CwdWithContext(_ context.Context) (string, error) { h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid)) if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER { return "", nil } if err != nil { return "", err } defer syscall.CloseHandle(syscall.Handle(h)) procIs32Bits := is32BitProcess(h) if procIs32Bits { userProcParams, err := getUserProcessParams32(h) if err != nil { return "", err } if userProcParams.CurrentDirectoryPathNameLength > 0 { cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CurrentDirectoryPathAddress), uint(userProcParams.CurrentDirectoryPathNameLength)) if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) { return "", errors.New("cannot read current working directory") } return convertUTF16ToString(cwd), nil } } else { userProcParams, err := getUserProcessParams64(h) if err != nil { return "", err } if userProcParams.CurrentDirectoryPathNameLength > 0 { cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CurrentDirectoryPathAddress, uint(userProcParams.CurrentDirectoryPathNameLength)) if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) { return "", errors.New("cannot read current working directory") } return convertUTF16ToString(cwd), nil } } // if we reach here, we have no cwd return "", nil } func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { return []string{""}, common.ErrNotImplementedError } func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { return false, common.ErrNotImplementedError } func (p *Process) UsernameWithContext(ctx context.Context) (string, error) { pid := p.Pid c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid)) if err != nil { return "", err } defer windows.CloseHandle(c) var token syscall.Token err = syscall.OpenProcessToken(syscall.Handle(c), syscall.TOKEN_QUERY, &token) if err != nil { return "", err } defer token.Close() tokenUser, err := token.GetTokenUser() if err != nil { return "", err } user, domain, _, err := tokenUser.User.Sid.LookupAccount("") return domain + "\\" + user, err } func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } // priorityClasses maps a win32 priority class to its WMI equivalent Win32_Process.Priority // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getpriorityclass // https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process var priorityClasses = map[int]int32{ 0x00008000: 10, // ABOVE_NORMAL_PRIORITY_CLASS 0x00004000: 6, // BELOW_NORMAL_PRIORITY_CLASS 0x00000080: 13, // HIGH_PRIORITY_CLASS 0x00000040: 4, // IDLE_PRIORITY_CLASS 0x00000020: 8, // NORMAL_PRIORITY_CLASS 0x00000100: 24, // REALTIME_PRIORITY_CLASS } func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid)) if err != nil { return 0, err } defer windows.CloseHandle(c) ret, _, err := procGetPriorityClass.Call(uintptr(c)) if ret == 0 { return 0, err } priority, ok := priorityClasses[int(ret)] if !ok { return 0, fmt.Errorf("unknown priority class %v", ret) } return priority, nil } func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid)) if err != nil { return nil, err } defer windows.CloseHandle(c) var ioCounters ioCounters ret, _, err := procGetProcessIoCounters.Call(uintptr(c), uintptr(unsafe.Pointer(&ioCounters))) if ret == 0 { return nil, err } stats := &IOCountersStat{ ReadCount: ioCounters.ReadOperationCount, ReadBytes: ioCounters.ReadTransferCount, WriteCount: ioCounters.WriteOperationCount, WriteBytes: ioCounters.WriteTransferCount, } return stats, nil } func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { ppid, ret, _, err := getFromSnapProcess(p.Pid) if err != nil { return 0, err } // if no errors and not cached already, cache ppid p.parent = ppid if 0 == p.getPpid() { p.setPpid(ppid) } return ret, nil } func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { sysTimes, err := getProcessCPUTimes(p.Pid) if err != nil { return nil, err } // User and kernel times are represented as a FILETIME structure // which contains a 64-bit value representing the number of // 100-nanosecond intervals since January 1, 1601 (UTC): // http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx // To convert it into a float representing the seconds that the // process has executed in user/kernel mode I borrowed the code // below from psutil's _psutil_windows.c, and in turn from Python's // Modules/posixmodule.c user := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7 kernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7 return &cpu.TimesStat{ User: user, System: kernel, }, nil } func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { mem, err := getMemoryInfo(p.Pid) if err != nil { return nil, err } ret := &MemoryInfoStat{ RSS: uint64(mem.WorkingSetSize), VMS: uint64(mem.PagefileUsage), } return ret, nil } func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { out := []*Process{} snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(0)) if err != nil { return out, err } defer windows.CloseHandle(snap) var pe32 windows.ProcessEntry32 pe32.Size = uint32(unsafe.Sizeof(pe32)) if err := windows.Process32First(snap, &pe32); err != nil { return out, err } for { if pe32.ParentProcessID == uint32(p.Pid) { p, err := NewProcessWithContext(ctx, int32(pe32.ProcessID)) if err == nil { out = append(out, p) } } if err = windows.Process32Next(snap, &pe32); err != nil { break } } return out, nil } func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { files := make([]OpenFilesStat, 0) fileExists := make(map[string]bool) process, err := windows.OpenProcess(common.ProcessQueryInformation, false, uint32(p.Pid)) if err != nil { return nil, err } buffer := make([]byte, 1024) var size uint32 st := common.CallWithExpandingBuffer( func() common.NtStatus { return common.NtQuerySystemInformation( common.SystemExtendedHandleInformationClass, &buffer[0], uint32(len(buffer)), &size, ) }, &buffer, &size, ) if st.IsError() { return nil, st.Error() } handlesList := (*common.SystemExtendedHandleInformation)(unsafe.Pointer(&buffer[0])) handles := make([]common.SystemExtendedHandleTableEntryInformation, int(handlesList.NumberOfHandles)) hdr := (*reflect.SliceHeader)(unsafe.Pointer(&handles)) hdr.Data = uintptr(unsafe.Pointer(&handlesList.Handles[0])) currentProcess, err := windows.GetCurrentProcess() if err != nil { return nil, err } for _, handle := range handles { var file uintptr if int32(handle.UniqueProcessId) != p.Pid { continue } if windows.DuplicateHandle(process, windows.Handle(handle.HandleValue), currentProcess, (*windows.Handle)(&file), 0, true, windows.DUPLICATE_SAME_ACCESS) != nil { continue } // release the new handle defer windows.CloseHandle(windows.Handle(file)) fileType, err := windows.GetFileType(windows.Handle(file)) if err != nil || fileType != windows.FILE_TYPE_DISK { continue } var fileName string ch := make(chan struct{}) go func() { var buf [syscall.MAX_LONG_PATH]uint16 n, err := windows.GetFinalPathNameByHandle(windows.Handle(file), &buf[0], syscall.MAX_LONG_PATH, 0) if err != nil { return } fileName = string(utf16.Decode(buf[:n])) ch <- struct{}{} }() select { case <-time.NewTimer(100 * time.Millisecond).C: continue case <-ch: fileInfo, err := os.Stat(fileName) if err != nil || fileInfo.IsDir() { continue } if _, exists := fileExists[fileName]; !exists { files = append(files, OpenFilesStat{ Path: fileName, Fd: uint64(file), }) fileExists[fileName] = true } case <-ctx.Done(): return files, ctx.Err() } } return files, nil } func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { return net.ConnectionsPidWithContext(ctx, "all", p.Pid) } func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { return nil, common.ErrNotImplementedError } func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error { return common.ErrNotImplementedError } func (p *Process) SuspendWithContext(ctx context.Context) error { c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid)) if err != nil { return err } defer windows.CloseHandle(c) r1, _, _ := procNtSuspendProcess.Call(uintptr(c)) if r1 != 0 { // See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 return fmt.Errorf("NtStatus='0x%.8X'", r1) } return nil } func (p *Process) ResumeWithContext(ctx context.Context) error { c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid)) if err != nil { return err } defer windows.CloseHandle(c) r1, _, _ := procNtResumeProcess.Call(uintptr(c)) if r1 != 0 { // See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 return fmt.Errorf("NtStatus='0x%.8X'", r1) } return nil } func (p *Process) TerminateWithContext(ctx context.Context) error { proc, err := windows.OpenProcess(windows.PROCESS_TERMINATE, false, uint32(p.Pid)) if err != nil { return err } err = windows.TerminateProcess(proc, 0) windows.CloseHandle(proc) return err } func (p *Process) KillWithContext(ctx context.Context) error { process, err := os.FindProcess(int(p.Pid)) if err != nil { return err } return process.Kill() } func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { envVars, err := getProcessEnvironmentVariables(p.Pid, ctx) if err != nil { return nil, fmt.Errorf("could not get environment variables: %s", err) } return envVars, nil } // retrieve Ppid in a thread-safe manner func (p *Process) getPpid() int32 { p.parentMutex.RLock() defer p.parentMutex.RUnlock() return p.parent } // cache Ppid in a thread-safe manner (WINDOWS ONLY) // see https://psutil.readthedocs.io/en/latest/#psutil.Process.ppid func (p *Process) setPpid(ppid int32) { p.parentMutex.Lock() defer p.parentMutex.Unlock() p.parent = ppid } func getFromSnapProcess(pid int32) (int32, int32, string, error) { snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid)) if err != nil { return 0, 0, "", err } defer windows.CloseHandle(snap) var pe32 windows.ProcessEntry32 pe32.Size = uint32(unsafe.Sizeof(pe32)) if err = windows.Process32First(snap, &pe32); err != nil { return 0, 0, "", err } for { if pe32.ProcessID == uint32(pid) { szexe := windows.UTF16ToString(pe32.ExeFile[:]) return int32(pe32.ParentProcessID), int32(pe32.Threads), szexe, nil } if err = windows.Process32Next(snap, &pe32); err != nil { break } } return 0, 0, "", fmt.Errorf("couldn't find pid: %d", pid) } func ProcessesWithContext(ctx context.Context) ([]*Process, error) { out := []*Process{} pids, err := PidsWithContext(ctx) if err != nil { return out, fmt.Errorf("could not get Processes %s", err) } for _, pid := range pids { p, err := NewProcessWithContext(ctx, pid) if err != nil { continue } out = append(out, p) } return out, nil } func getRusage(pid int32) (*windows.Rusage, error) { var CPU windows.Rusage c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid)) if err != nil { return nil, err } defer windows.CloseHandle(c) if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil { return nil, err } return &CPU, nil } func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) { var mem PROCESS_MEMORY_COUNTERS c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid)) if err != nil { return mem, err } defer windows.CloseHandle(c) if err := getProcessMemoryInfo(c, &mem); err != nil { return mem, err } return mem, err } func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) { r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem))) if r1 == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return } type SYSTEM_TIMES struct { CreateTime syscall.Filetime ExitTime syscall.Filetime KernelTime syscall.Filetime UserTime syscall.Filetime } func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) { var times SYSTEM_TIMES h, err := windows.OpenProcess(processQueryInformation, false, uint32(pid)) if err != nil { return times, err } defer windows.CloseHandle(h) err = syscall.GetProcessTimes( syscall.Handle(h), ×.CreateTime, ×.ExitTime, ×.KernelTime, ×.UserTime, ) return times, err } func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32, error) { pebAddress, err := queryPebAddress(syscall.Handle(handle), true) if err != nil { return rtlUserProcessParameters32{}, fmt.Errorf("cannot locate process PEB: %w", err) } buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{}))) if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) { 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{}, fmt.Errorf("cannot read user process parameters") } return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil } func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64, error) { pebAddress, err := queryPebAddress(syscall.Handle(handle), false) if err != nil { return rtlUserProcessParameters64{}, fmt.Errorf("cannot locate process PEB: %w", err) } buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{}))) if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) { 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{}, fmt.Errorf("cannot read user process parameters") } return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil } func is32BitProcess(h windows.Handle) bool { const ( PROCESSOR_ARCHITECTURE_INTEL = 0 PROCESSOR_ARCHITECTURE_ARM = 5 PROCESSOR_ARCHITECTURE_ARM64 = 12 PROCESSOR_ARCHITECTURE_IA64 = 6 PROCESSOR_ARCHITECTURE_AMD64 = 9 ) var procIs32Bits bool switch processorArchitecture { case PROCESSOR_ARCHITECTURE_INTEL, PROCESSOR_ARCHITECTURE_ARM: procIs32Bits = true case PROCESSOR_ARCHITECTURE_ARM64, PROCESSOR_ARCHITECTURE_IA64, PROCESSOR_ARCHITECTURE_AMD64: var wow64 uint ret, _, _ := common.ProcNtQueryInformationProcess.Call( uintptr(h), uintptr(common.ProcessWow64Information), uintptr(unsafe.Pointer(&wow64)), uintptr(unsafe.Sizeof(wow64)), uintptr(0), ) if int(ret) >= 0 { if wow64 != 0 { procIs32Bits = true } } else { // if the OS does not support the call, we fallback into the bitness of the app if unsafe.Sizeof(wow64) == 4 { procIs32Bits = true } } default: // for other unknown platforms, we rely on process platform if unsafe.Sizeof(processorArchitecture) == 8 { procIs32Bits = false } else { procIs32Bits = true } } return procIs32Bits } func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, error) { h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid)) if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER { return nil, nil } if err != nil { return nil, err } defer syscall.CloseHandle(syscall.Handle(h)) procIs32Bits := is32BitProcess(h) var processParameterBlockAddress uint64 if procIs32Bits { peb, err := getUserProcessParams32(h) if err != nil { return nil, err } processParameterBlockAddress = uint64(peb.EnvironmentAddress) } else { peb, err := getUserProcessParams64(h) if err != nil { return nil, err } processParameterBlockAddress = peb.EnvironmentAddress } envvarScanner := bufio.NewScanner(&processReader{ processHandle: h, is32BitProcess: procIs32Bits, offset: processParameterBlockAddress, }) envvarScanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } // Check for UTF-16 zero character for i := 0; i < len(data)-1; i += 2 { if data[i] == 0 && data[i+1] == 0 { return i + 2, data[0:i], nil } } if atEOF { return len(data), data, nil } // Request more data return 0, nil, nil }) var envVars []string for envvarScanner.Scan() { entry := envvarScanner.Bytes() if len(entry) == 0 { break // Block is finished } envVars = append(envVars, convertUTF16ToString(entry)) select { case <-ctx.Done(): break default: continue } } if err := envvarScanner.Err(); err != nil { return nil, err } return envVars, nil } type processReader struct { processHandle windows.Handle is32BitProcess bool offset uint64 } func (p *processReader) Read(buf []byte) (int, error) { processMemory := readProcessMemory(syscall.Handle(p.processHandle), p.is32BitProcess, p.offset, uint(len(buf))) if len(processMemory) == 0 { return 0, io.EOF } copy(buf, processMemory) p.offset += uint64(len(processMemory)) return len(processMemory), nil } func getProcessCommandLine(pid int32) (string, error) { h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid)) if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER { return "", nil } if err != nil { return "", err } defer syscall.CloseHandle(syscall.Handle(h)) procIs32Bits := is32BitProcess(h) if procIs32Bits { userProcParams, err := getUserProcessParams32(h) if err != nil { return "", err } if userProcParams.CommandLineLength > 0 { cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CommandLineAddress), uint(userProcParams.CommandLineLength)) if len(cmdLine) != int(userProcParams.CommandLineLength) { return "", errors.New("cannot read cmdline") } return convertUTF16ToString(cmdLine), nil } } else { userProcParams, err := getUserProcessParams64(h) if err != nil { return "", err } if userProcParams.CommandLineLength > 0 { cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength)) if len(cmdLine) != int(userProcParams.CommandLineLength) { return "", errors.New("cannot read cmdline") } return convertUTF16ToString(cmdLine), nil } } // if we reach here, we have no command line return "", nil } func convertUTF16ToString(src []byte) string { srcLen := len(src) / 2 codePoints := make([]uint16, srcLen) srcIdx := 0 for i := 0; i < srcLen; i++ { codePoints[i] = uint16(src[srcIdx]) | uint16(src[srcIdx+1])<<8 srcIdx += 2 } return syscall.UTF16ToString(codePoints) } gopsutil-3.24.1/process/process_windows_32bit.go000066400000000000000000000056661455407747200217430ustar00rootroot00000000000000//go:build (windows && 386) || (windows && arm) // +build windows,386 windows,arm package process import ( "errors" "syscall" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/windows" ) type PROCESS_MEMORY_COUNTERS struct { CB uint32 PageFaultCount uint32 PeakWorkingSetSize uint32 WorkingSetSize uint32 QuotaPeakPagedPoolUsage uint32 QuotaPagedPoolUsage uint32 QuotaPeakNonPagedPoolUsage uint32 QuotaNonPagedPoolUsage uint32 PagefileUsage uint32 PeakPagefileUsage uint32 } func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) { if is32BitProcess { // we are on a 32-bit process reading an external 32-bit process var info processBasicInformation32 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 uint64(info.PebBaseAddress), nil } else { return 0, windows.NTStatus(ret) } } 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 } else { return 0, windows.NTStatus(ret) } } else { return 0, errors.New("can't find API to query 64 bit process from 32 bit") } } } func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, size uint) []byte { if is32BitProcess { var read uint buffer := make([]byte, size) ret, _, _ := common.ProcNtReadVirtualMemory.Call( uintptr(h), uintptr(address), uintptr(unsafe.Pointer(&buffer[0])), uintptr(size), uintptr(unsafe.Pointer(&read)), ) if int(ret) >= 0 && read > 0 { return buffer[:read] } } else { // reading a 64-bit process from a 32-bit one if common.ProcNtWow64ReadVirtualMemory64.Find() == nil { // avoid panic var read uint64 buffer := make([]byte, size) ret, _, _ := common.ProcNtWow64ReadVirtualMemory64.Call( uintptr(h), uintptr(address&0xFFFFFFFF), // the call expects a 64-bit value uintptr(address>>32), uintptr(unsafe.Pointer(&buffer[0])), uintptr(size), // the call expects a 64-bit value uintptr(0), // but size is 32-bit so pass zero as the high dword uintptr(unsafe.Pointer(&read)), ) if int(ret) >= 0 && read > 0 { return buffer[:uint(read)] } } } // if we reach here, an error happened return nil } gopsutil-3.24.1/process/process_windows_64bit.go000066400000000000000000000040161455407747200217340ustar00rootroot00000000000000//go:build (windows && amd64) || (windows && arm64) // +build windows,amd64 windows,arm64 package process import ( "syscall" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" "golang.org/x/sys/windows" ) type PROCESS_MEMORY_COUNTERS struct { CB uint32 PageFaultCount uint32 PeakWorkingSetSize uint64 WorkingSetSize uint64 QuotaPeakPagedPoolUsage uint64 QuotaPagedPoolUsage uint64 QuotaPeakNonPagedPoolUsage uint64 QuotaNonPagedPoolUsage uint64 PagefileUsage uint64 PeakPagefileUsage uint64 } func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) { if is32BitProcess { // we are on a 64-bit process reading an external 32-bit process var wow64 uint ret, _, _ := common.ProcNtQueryInformationProcess.Call( uintptr(procHandle), uintptr(common.ProcessWow64Information), uintptr(unsafe.Pointer(&wow64)), uintptr(unsafe.Sizeof(wow64)), uintptr(0), ) if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS { return uint64(wow64), nil } else { return 0, windows.NTStatus(ret) } } 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 } else { return 0, windows.NTStatus(ret) } } } func readProcessMemory(procHandle syscall.Handle, _ bool, address uint64, size uint) []byte { var read uint buffer := make([]byte, size) ret, _, _ := common.ProcNtReadVirtualMemory.Call( uintptr(procHandle), uintptr(address), uintptr(unsafe.Pointer(&buffer[0])), uintptr(size), uintptr(unsafe.Pointer(&read)), ) if int(ret) >= 0 && read > 0 { return buffer[:read] } return nil } gopsutil-3.24.1/process/testdata/000077500000000000000000000000001455407747200167555ustar00rootroot00000000000000gopsutil-3.24.1/process/testdata/linux/000077500000000000000000000000001455407747200201145ustar00rootroot00000000000000gopsutil-3.24.1/process/testdata/linux/1/000077500000000000000000000000001455407747200202545ustar00rootroot00000000000000gopsutil-3.24.1/process/testdata/linux/1/comm000066400000000000000000000000141455407747200211250ustar00rootroot00000000000000ksoftirqd/0 gopsutil-3.24.1/process/testdata/linux/1/status000066400000000000000000000016601455407747200215250ustar00rootroot00000000000000Name: ksoftirqd/0 Umask: 0000 State: S (sleeping) Tgid: 10 Ngid: 0 Pid: 10 PPid: 2 TracerPid: 0 Uid: 0 0 0 0 Gid: 0 0 0 0 FDSize: 64 Groups: NStgid: 10 NSpid: 10 NSpgid: 0 NSsid: 0 Threads: 1 SigQ: 0/27700 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: ffffffffffffffff SigCgt: 0000000000000000 CapInh: 0000000000000000 CapPrm: 0000003fffffffff CapEff: 0000003fffffffff CapBnd: 0000003fffffffff CapAmb: 0000000000000000 NoNewPrivs: 0 Seccomp: 0 Speculation_Store_Bypass: vulnerable Cpus_allowed: 1 Cpus_allowed_list: 0 Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001 Mems_allowed_list: 0 voluntary_ctxt_switches: 76887 nonvoluntary_ctxt_switches: 1771 gopsutil-3.24.1/process/testdata/linux/1060/000077500000000000000000000000001455407747200205025ustar00rootroot00000000000000gopsutil-3.24.1/process/testdata/linux/1060/comm000066400000000000000000000000071455407747200213550ustar00rootroot00000000000000server gopsutil-3.24.1/process/testdata/linux/1060/status000066400000000000000000000017321455407747200217530ustar00rootroot00000000000000Name: server Umask: 0022 State: S (sleeping) Tgid: 2549 Ngid: 0 Pid: 2549 PPid: 1 TracerPid: 0 Uid: 107 107 107 107 Gid: 113 113 113 113 FDSize: 64 Groups: 113 VmPeak: 664744 kB VmSize: 664744 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 2892 kB VmRSS: 2892 kB RssAnon: 524 kB RssFile: 2368 kB RssShmem: 0 kB VmData: 5932 kB VmStk: 132 kB VmExe: 1304 kB VmLib: 1180 kB VmPTE: 44 kB VmSwap: 0 kB CoreDumping: 0 THP_enabled: 1 Threads: 5 SigQ: 0/1823 SigPnd: 00000000000000000000000000000000 ShdPnd: 00000000000000000000000000000000 SigBlk: 00000000000000000000000000000000 SigIgn: 00000000000000000000000000000000 SigCgt: fffffffffffffffffffffffe783ffeff CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: 0000003fffffffff CapAmb: 0000000000000000 NoNewPrivs: 0 Speculation_Store_Bypass: unknown Cpus_allowed: 3 Cpus_allowed_list: 0-1 voluntary_ctxt_switches: 3 nonvoluntary_ctxt_switches: 146gopsutil-3.24.1/process/testdata/linux/68927/000077500000000000000000000000001455407747200206135ustar00rootroot00000000000000gopsutil-3.24.1/process/testdata/linux/68927/comm000066400000000000000000000000151455407747200214650ustar00rootroot00000000000000test(cmd).sh gopsutil-3.24.1/process/testdata/linux/68927/stat000066400000000000000000000005051455407747200215110ustar00rootroot0000000000000068927 (test(cmd).sh) S 68044 68927 68044 34818 68927 4194304 165 0 0 0 0 0 0 0 20 0 1 0 114413973 9961472 868 18446744073709551615 94388826710016 94388827626021 140725039102800 0 0 0 2 4 65536 1 0 0 17 1 0 0 0 0 0 94388827875984 94388827924080 94388835627008 140725039105503 140725039105528 140725039105528 140725039108073 0 gopsutil-3.24.1/process/testdata/lx_brandz/000077500000000000000000000000001455407747200207405ustar00rootroot00000000000000gopsutil-3.24.1/process/testdata/lx_brandz/1/000077500000000000000000000000001455407747200211005ustar00rootroot00000000000000gopsutil-3.24.1/process/testdata/lx_brandz/1/stat000066400000000000000000000002321455407747200217730ustar00rootroot000000000000001 (systemd) S 0 0 0 0 -1 0 0 0 0 0 8 15 48 52 1 0 0 0 25 31883264 1413 18446744073709551615 0 0 140737487261696 0 0 0 0 0 0 18446741901776689794 0 0 17 0 gopsutil-3.24.1/process/types_darwin.go000066400000000000000000000057511455407747200202130ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Hand Writing // - all pointer in ExternProc to uint64 //go:build ignore // +build ignore /* Input to cgo -godefs. */ // +godefs map struct_in_addr [4]byte /* in_addr */ // +godefs map struct_in6_addr [16]byte /* in6_addr */ // +godefs map struct_ [16]byte /* in6_addr */ package process /* #define __DARWIN_UNIX03 0 #define KERNEL #define _DARWIN_USE_64_BIT_INODE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum { sizeofPtr = sizeof(void*), }; union sockaddr_all { struct sockaddr s1; // this one gets used for fields struct sockaddr_in s2; // these pad it out struct sockaddr_in6 s3; struct sockaddr_un s4; struct sockaddr_dl s5; }; struct sockaddr_any { struct sockaddr addr; char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; }; struct ucred_queue { struct ucred *tqe_next; struct ucred **tqe_prev; TRACEBUF }; */ import "C" // Machine characteristics; for internal use. const ( sizeofPtr = C.sizeofPtr sizeofShort = C.sizeof_short sizeofInt = C.sizeof_int sizeofLong = C.sizeof_long sizeofLongLong = C.sizeof_longlong ) // Basic types type ( _C_short C.short _C_int C.int _C_long C.long _C_long_long C.longlong ) // Time type Timespec C.struct_timespec type Timeval C.struct_timeval // Processes type Rusage C.struct_rusage type Rlimit C.struct_rlimit type UGid_t C.gid_t type KinfoProc C.struct_kinfo_proc type Eproc C.struct_eproc type Proc C.struct_proc type Session C.struct_session type ucred C.struct_ucred type Uucred C.struct__ucred type Upcred C.struct__pcred type Vmspace C.struct_vmspace type Sigacts C.struct_sigacts type ExternProc C.struct_extern_proc type Itimerval C.struct_itimerval type Vnode C.struct_vnode type Pgrp C.struct_pgrp type UserStruct C.struct_user type Au_session C.struct_au_session type Posix_cred C.struct_posix_cred type Label C.struct_label type ( AuditinfoAddr C.struct_auditinfo_addr AuMask C.struct_au_mask AuTidAddr C.struct_au_tid_addr ) // TAILQ(ucred) type UcredQueue C.struct_ucred_queue gopsutil-3.24.1/process/types_freebsd.go000066400000000000000000000041431455407747200203330ustar00rootroot00000000000000//go:build ignore // +build ignore // We still need editing by hands. // go tool cgo -godefs types_freebsd.go | sed 's/\*int64/int64/' | sed 's/\*byte/int64/' > process_freebsd_amd64.go /* Input to cgo -godefs. */ // +godefs map struct_pargs int64 /* pargs */ // +godefs map struct_proc int64 /* proc */ // +godefs map struct_user int64 /* user */ // +godefs map struct_vnode int64 /* vnode */ // +godefs map struct_vnode int64 /* vnode */ // +godefs map struct_filedesc int64 /* filedesc */ // +godefs map struct_vmspace int64 /* vmspace */ // +godefs map struct_pcb int64 /* pcb */ // +godefs map struct_thread int64 /* thread */ // +godefs map struct___sigset [16]byte /* sigset */ package process /* #include #include enum { sizeofPtr = sizeof(void*), }; */ import "C" // Machine characteristics; for internal use. const ( CTLKern = 1 // "high kernel": proc, limits KernProc = 14 // struct: process entries KernProcPID = 1 // by process id KernProcProc = 8 // only return procs KernProcPathname = 12 // path to executable KernProcArgs = 7 // get/set arguments/proctitle ) const ( sizeofPtr = C.sizeofPtr sizeofShort = C.sizeof_short sizeofInt = C.sizeof_int sizeofLong = C.sizeof_long sizeofLongLong = C.sizeof_longlong ) const ( sizeOfKinfoVmentry = C.sizeof_struct_kinfo_vmentry sizeOfKinfoProc = C.sizeof_struct_kinfo_proc ) // from sys/proc.h const ( SIDL = 1 /* Process being created by fork. */ SRUN = 2 /* Currently runnable. */ SSLEEP = 3 /* Sleeping on an address. */ SSTOP = 4 /* Process debugging or suspension. */ SZOMB = 5 /* Awaiting collection by parent. */ SWAIT = 6 /* Waiting for interrupt. */ SLOCK = 7 /* Blocked on a lock. */ ) // Basic types type ( _C_short C.short _C_int C.int _C_long C.long _C_long_long C.longlong ) // Time type Timespec C.struct_timespec type Timeval C.struct_timeval // Processes type Rusage C.struct_rusage type Rlimit C.struct_rlimit type KinfoProc C.struct_kinfo_proc type Priority C.struct_priority type KinfoVmentry C.struct_kinfo_vmentry gopsutil-3.24.1/process/types_openbsd.go000066400000000000000000000044221455407747200203530ustar00rootroot00000000000000//go:build ignore // +build ignore // We still need editing by hands. // go tool cgo -godefs types_openbsd.go | sed 's/\*int64/int64/' | sed 's/\*byte/int64/' > process_openbsd_amd64.go /* Input to cgo -godefs. */ // +godefs map struct_pargs int64 /* pargs */ // +godefs map struct_proc int64 /* proc */ // +godefs map struct_user int64 /* user */ // +godefs map struct_vnode int64 /* vnode */ // +godefs map struct_vnode int64 /* vnode */ // +godefs map struct_filedesc int64 /* filedesc */ // +godefs map struct_vmspace int64 /* vmspace */ // +godefs map struct_pcb int64 /* pcb */ // +godefs map struct_thread int64 /* thread */ // +godefs map struct___sigset [16]byte /* sigset */ package process /* #include #include #include enum { sizeofPtr = sizeof(void*), }; */ import "C" // Machine characteristics; for internal use. const ( CTLKern = 1 // "high kernel": proc, limits KernProc = 66 // struct: process entries KernProcAll = 0 KernProcPID = 1 // by process id KernProcProc = 8 // only return procs KernProcPathname = 12 // path to executable KernProcArgs = 55 // get/set arguments/proctitle KernProcArgv = 1 KernProcEnv = 3 ) const ( ArgMax = 256 * 1024 // sys/syslimits.h:#define ARG_MAX ) const ( sizeofPtr = C.sizeofPtr sizeofShort = C.sizeof_short sizeofInt = C.sizeof_int sizeofLong = C.sizeof_long sizeofLongLong = C.sizeof_longlong ) const ( sizeOfKinfoVmentry = C.sizeof_struct_kinfo_vmentry sizeOfKinfoProc = C.sizeof_struct_kinfo_proc ) // from sys/proc.h const ( SIDL = 1 /* Process being created by fork. */ SRUN = 2 /* Currently runnable. */ SSLEEP = 3 /* Sleeping on an address. */ SSTOP = 4 /* Process debugging or suspension. */ SZOMB = 5 /* Awaiting collection by parent. */ SDEAD = 6 /* Thread is almost gone */ SONPROC = 7 /* Thread is currently on a CPU. */ ) // Basic types type ( _C_short C.short _C_int C.int _C_long C.long _C_long_long C.longlong ) // Time type Timespec C.struct_timespec type Timeval C.struct_timeval // Processes type Rusage C.struct_rusage type Rlimit C.struct_rlimit type KinfoProc C.struct_kinfo_proc type Priority C.struct_priority type KinfoVmentry C.struct_kinfo_vmentry gopsutil-3.24.1/windows_memo.rst000066400000000000000000000012061455407747200167260ustar00rootroot00000000000000Windows memo ===================== Size ---------- DWORD 32-bit unsigned integer DWORDLONG 64-bit unsigned integer DWORD_PTR unsigned long type for pointer precision DWORD32 32-bit unsigned integer DWORD64 64-bit unsigned integer HALF_PTR _WIN64 = int, else short INT 32-bit signed integer INT_PTR _WIN64 = __int64 else int LONG 32-bit signed integer LONGLONG 64-bit signed integer LONG_PTR _WIN64 = __int64 else long SHORT 16-bit integer SIZE_T maximum number of bytes to which a pointer can point. typedef ULONG_PTR SIZE_T; SSIZE_T signed version of SIZE_T. typedef LONG_PTR SSIZE_T; WORD 16-bit unsigned integergopsutil-3.24.1/winservices/000077500000000000000000000000001455407747200160275ustar00rootroot00000000000000gopsutil-3.24.1/winservices/manager.go000066400000000000000000000010271455407747200177700ustar00rootroot00000000000000//go:build windows // +build windows package winservices import ( "golang.org/x/sys/windows/svc/mgr" ) type scmanager struct { mgr *mgr.Mgr } func openSCManager() (*scmanager, error) { m, err := mgr.Connect() if err != nil { return nil, err } return &scmanager{m}, nil } func (sc *scmanager) close() error { return sc.mgr.Disconnect() } func getService(serviceName string) (*mgr.Service, error) { m, err := openSCManager() if err != nil { return nil, err } defer m.close() return m.mgr.OpenService(serviceName) } gopsutil-3.24.1/winservices/winservices.go000066400000000000000000000066211455407747200207240ustar00rootroot00000000000000//go:build windows // +build windows package winservices import ( "context" "unsafe" "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/mgr" ) // Service represent a windows service. type Service struct { Name string Config mgr.Config Status ServiceStatus srv *mgr.Service } // ServiceStatus combines State and Accepted commands to fully describe running service. type ServiceStatus struct { State svc.State Accepts svc.Accepted Pid uint32 Win32ExitCode uint32 } // NewService create and return a windows Service func NewService(name string) (*Service, error) { // call windows service function need to OpenService handler, // so first call func OpenService to get the specified service handler. service, err := getService(name) if err != nil { return nil, err } return &Service{ Name: name, srv: service, }, nil } // GetServiceDetail get a windows service by name func (s *Service) GetServiceDetail() error { return s.GetServiceDetailWithContext(context.Background()) } // GetServiceDetailWithContext get a windows service by name func (s *Service) GetServiceDetailWithContext(ctx context.Context) error { config, err := s.QueryServiceConfigWithContext(ctx) if err != nil { return err } s.Config = config status, err := s.QueryStatusWithContext(ctx) if err != nil { return err } s.Status = status return nil } // QueryServiceConfig return the specified service config func (s *Service) QueryServiceConfig() (mgr.Config, error) { return s.QueryServiceConfigWithContext(context.Background()) } // QueryServiceConfigWithContext call QueryServiceConfig() and QueryServiceConfig2() // implement windows https://msdn.microsoft.com/en-us/library/windows/desktop/ms684932(v=vs.85).aspx func (s *Service) QueryServiceConfigWithContext(ctx context.Context) (mgr.Config, error) { return s.srv.Config() } // QueryStatus return the specified name service currentState and ControlsAccepted func (s *Service) QueryStatus() (ServiceStatus, error) { return s.QueryStatusWithContext(context.Background()) } // QueryStatusWithContext return the specified name service currentState and ControlsAccepted func (s *Service) QueryStatusWithContext(ctx context.Context) (ServiceStatus, error) { var p *windows.SERVICE_STATUS_PROCESS var bytesNeeded uint32 var buf []byte if err := windows.QueryServiceStatusEx(s.srv.Handle, windows.SC_STATUS_PROCESS_INFO, nil, 0, &bytesNeeded); err != windows.ERROR_INSUFFICIENT_BUFFER { return ServiceStatus{}, err } buf = make([]byte, bytesNeeded) p = (*windows.SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0])) if err := windows.QueryServiceStatusEx(s.srv.Handle, windows.SC_STATUS_PROCESS_INFO, &buf[0], uint32(len(buf)), &bytesNeeded); err != nil { return ServiceStatus{}, err } return ServiceStatus{ State: svc.State(p.CurrentState), Accepts: svc.Accepted(p.ControlsAccepted), Pid: p.ProcessId, Win32ExitCode: p.Win32ExitCode, }, nil } // ListServices return all windows service // reference to golang.org/x/sys/windows/svc/mgr#ListServices() func ListServices() ([]Service, error) { m, err := openSCManager() if err != nil { return nil, err } defer m.close() names, err := m.mgr.ListServices() if err != nil { return nil, err } services := make([]Service, 0) for _, name := range names { services = append(services, Service{Name: name}) } return services, nil }