[
  {
    "path": ".gitattributes",
    "content": "# ensure that line endings for Windows builds are properly formatted\n# see https://github.com/golangci/golangci-lint-action?tab=readme-ov-file#how-to-use\n# at \"Multiple OS Example\" section\n*.go text eol=lf\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: shirou\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve gopsutil\n\n---\n\n**Describe the bug**\n[A clear and concise description of what the bug is.]\n\n**To Reproduce**\n```go\n// paste example code reproducing the bug you are reporting\n```\n\n**Expected behavior**\n[A clear and concise description of what you expected to happen.]\n\n**Environment (please complete the following information):**\n - [ ] Windows: [paste the result of `ver`]\n - [ ] Linux: [paste contents of `/etc/os-release` and the result of `uname -a`]\n - [ ] Mac OS: [paste the result of `sw_vers` and `uname -a`\n - [ ] FreeBSD: [paste the result of `freebsd-version -k -r -u` and  `uname -a`]\n - [ ] OpenBSD: [paste the result of `uname -a`]\n\n**Additional context**\n[Cross-compiling? Paste the command you are using to cross-compile and the result of the corresponding `go env`]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for gopsutil\n\n---\n\n**Is your feature request related to a problem? Please describe.**\n[A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]]\n\n**Describe the solution you'd like**\n[A clear and concise description of what you want to happen.]\n\n**Describe alternatives you've considered**\n[A clear and concise description of any alternative solutions or features you've considered.]\n\n**Additional context**\n[Add any other context or screenshots about the feature request here.]\n"
  },
  {
    "path": ".github/SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nSecurity updates are applied only to the latest release.\n\n## Reporting a Vulnerability\n\nIf 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.\n\nPlease disclose it at [Security Advisories](https://github.com/shirou/gopsutil/security/advisories/new).\n\nThis 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.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: gomod\n  directory: /\n  schedule:\n    interval: daily\n- package-ecosystem: github-actions\n  directory: /\n  schedule:\n    interval: daily\n"
  },
  {
    "path": ".github/labeler.yml",
    "content": "'package:cpu':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'cpu/**'\n\n'package:disk':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'disk/**'\n\n'package:docker':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'docker/**'\n\n'package:host':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'host/**'\n\n'package:load':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'load/**'\n\n'package:mem':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'mem/**'\n\n'package:net':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'net/**'\n\n'package:process':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'process/**'\n\n'package:sensors':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'sensors/**'\n\n'package:winservices':\n  - changed-files:\n    - any-glob-to-any-file:\n      - 'winservices/**'\n\n'os:linux':\n  - changed-files:\n    - any-glob-to-any-file:\n      - '**/*_linux.go'\n      - '**/*_linux_mips64.go'\n      - '**/*_linux_386.go'\n      - '**/*_linux_test.go'\n      - '**/*_linux_s390x.go'\n      - '**/*_linux_amd64.go'\n      - '**/*_linux_arm64.go'\n      - '**/*_linux_arm.go'\n      - '**/*_posix.go'\n\n'os:freebsd':\n  - changed-files:\n    - any-glob-to-any-file:\n      - '**/*_freebsd.go'\n      - '**/*_freebsd_386.go'\n      - '**/*_freebsd_test.go'\n      - '**/*_freebsd_amd64.go'\n      - '**/*_freebsd_arm64.go'\n      - '**/*_freebsd_arm.go'\n      - '**/*_bsd.go'\n      - '**/*_posix.go'\n\n'os:darwin':\n  - changed-files:\n    - any-glob-to-any-file:\n      - '**/*_darwin.go'\n      - '**/*_darwin_386.go'\n      - '**/*_darwin_test.go'\n      - '**/*_darwin_amd64.go'\n      - '**/*_darwin_arm64.go'\n      - '**/*_posix.go'\n\n'os:openbsd':\n  - changed-files:\n    - any-glob-to-any-file:\n      - '**/*_openbsd.go'\n      - '**/*_openbsd_386.go'\n      - '**/*_openbsd_test.go'\n      - '**/*_openbsd_amd64.go'\n      - '**/*_openbsd_arm64.go'\n      - '**/*_openbsd_arm.go'\n      - '**/*_bsd.go'\n      - '**/*_posix.go'\n\n'os:windows':\n  - changed-files:\n    - any-glob-to-any-file:\n      - '**/*_windows.go'\n      - '**/*_windows_386.go'\n      - '**/*_windows_test.go'\n      - '**/*_windows_amd64.go'\n      - '**/*_windows_32bit.go'\n      - '**/*_windows_64bit.go'\n\n'os:solaris':\n  - changed-files:\n    - any-glob-to-any-file:\n      - '**/*_solaris.go'\n      - '**/*_posix.go'\n\n'os:aix':\n  - changed-files:\n    - any-glob-to-any-file:\n      - '**/*_aix.go'\n      - '**/*_aix_test.go'\n      - '**/*_aix_*.go'\n      - '**/*_posix.go'\n"
  },
  {
    "path": ".github/release.yml",
    "content": "changelog:\n  exclude:\n    labels:\n      - ignore-for-release\n      - dependencies\n    authors:\n      - dependabot[bot]\n  categories:\n    - title: \"cpu\"\n      labels:\n        - \"package:cpu\"\n    - title: \"disk\"\n      labels:\n        - \"package:disk\"\n    - title: \"docker\"\n      labels:\n        - \"package:docker\"\n    - title: \"host\"\n      labels:\n        - \"package:host\"\n    - title: \"load\"\n      labels:\n        - \"package:load\"\n    - title: \"mem\"\n      labels:\n        - \"package:mem\"\n    - title: \"net\"\n      labels:\n        - \"package:net\"\n    - title: \"process\"\n      labels:\n        - \"package:process\"\n    - title: \"winservices\"\n      labels:\n        - \"package:winservices\"\n    - title: Other Changes\n      labels:\n        - \"*\""
  },
  {
    "path": ".github/workflows/build_test.yml",
    "content": "name: Build Test\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\npermissions:\n  contents: read\n\njobs:\n  go-versions:\n    runs-on: ubuntu-latest\n    outputs:\n      versions: ${{ steps.versions.outputs.value }}\n    steps:\n      - id: versions\n        run: |\n          versions=$(curl -s 'https://go.dev/dl/?mode=json' | jq -c 'map(.version[2:])')\n          echo \"value=${versions}\"  >> $GITHUB_OUTPUT\n  build_test:\n    needs: go-versions\n    strategy:\n      fail-fast: false\n      matrix:\n        go-version: ${{fromJson(needs.go-versions.outputs.versions)}}\n    runs-on: ubuntu-22.04\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Install Go\n        uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0\n        with:\n          go-version: ${{ matrix.go-version }}\n      - name: Build Test v3\n        run: |\n          make build_test\n"
  },
  {
    "path": ".github/workflows/labeler.yml",
    "content": "name: \"Pull Request Labeler\"\n\non:\n  pull_request_target:\n\npermissions:\n  contents: read\n\njobs:\n  triage:\n    permissions:\n      contents: read  # for actions/labeler to determine modified files\n      pull-requests: write  # for actions/labeler to add labels to PRs\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1\n        with:\n          repo-token: \"${{ secrets.GITHUB_TOKEN }}\"\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Golangci-lint\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\npermissions:\n  contents: read\n\njobs:\n  golangci:\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - {os: macos-latest, CGO_ENABLED: \"0\", GOOS: darwin, GOARCH: amd64}\n          - {os: macos-latest, CGO_ENABLED: \"1\", GOOS: darwin, GOARCH: amd64}\n          - {os: macos-latest, CGO_ENABLED: \"0\", GOOS: darwin, GOARCH: arm64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: aix, GOARCH: ppc64}\n#          - {os: ubuntu-latest, CGO_ENABLED: \"1\", GOOS: aix, GOARCH: ppc64} # FIXME\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: dragonfly, GOARCH: amd64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: freebsd, GOARCH: amd64}\n#          - {os: ubuntu-latest, CGO_ENABLED: \"1\", GOOS: freebsd, GOARCH: amd64} # FIXME\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: freebsd, GOARCH: 386}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: freebsd, GOARCH: arm}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: 386}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: amd64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: arm64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: arm}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: loong64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: mips64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: mips64le}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: mips}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: mipsle}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: ppc64le}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: ppc64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: riscv64}\n#          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: linux, GOARCH: s390x} # FIXME\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: netbsd, GOARCH: amd64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"1\", GOOS: netbsd, GOARCH: amd64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: openbsd, GOARCH: 386}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: openbsd, GOARCH: amd64}\n#          - {os: ubuntu-latest, CGO_ENABLED: \"1\", GOOS: openbsd, GOARCH: amd64} # FIXME\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: plan9, GOARCH: amd64}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: plan9, GOARCH: 386}\n          - {os: ubuntu-latest, CGO_ENABLED: \"0\", GOOS: solaris, GOARCH: amd64}\n          - {os: windows-latest, CGO_ENABLED: \"0\", GOOS: windows, GOARCH: amd64}\n          - {os: windows-latest, CGO_ENABLED: \"0\", GOOS: windows, GOARCH: 386}\n    permissions:\n      contents: read  # for actions/checkout to fetch code\n      pull-requests: read  # for golangci/golangci-lint-action to fetch pull requests\n    name: lint\n    runs-on: ${{ matrix.os }}\n    env:\n      CGO_ENABLED: \"${{ matrix.CGO_ENABLED }}\"\n      GOARCH: ${{ matrix.GOARCH }}\n      GOOS: ${{ matrix.GOOS }}\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Setup go\n        uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0\n        with:\n          go-version-file: go.mod\n      - name: Setup golangci-lint\n        uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9  # v8.0.0\n        with:\n          args: --verbose\n          version: latest\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  schedule:\n    - cron: '0 1 1 * *'  # UTC 01:00 on the first day of the Month\n\npermissions:\n  contents: write\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Release\n        run: make release\n"
  },
  {
    "path": ".github/workflows/sbom_generator.yml",
    "content": "name: SBOM Generator\n\non:\n  push:\n    branches: \n      - master\n  workflow_dispatch:\n\npermissions: read-all\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - uses: advanced-security/sbom-generator-action@6fe43abf522b2e7a19bc769aec1e6c848614b517 # v0.0.2\n        id: sbom\n        env: \n          GITHUB_TOKEN: ${{ github.token }}\n      - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0\n        with: \n          path: ${{steps.sbom.outputs.fileName }}\n          name: \"SBOM\"\n"
  },
  {
    "path": ".github/workflows/shellcheck.yml",
    "content": "name: Shellcheck\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\npermissions:\n  contents: read\n\njobs:\n  shellcheck:\n    name: Shellcheck\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Run ShellCheck\n        uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\npermissions:\n  contents: read\n\njobs:\n  go-versions:\n    runs-on: ubuntu-latest\n    outputs:\n      versions: ${{ steps.versions.outputs.value }}\n    steps:\n      - id: versions\n        run: |\n          versions=$(curl -s 'https://go.dev/dl/?mode=json' | jq -c 'map(.version[2:])')\n          echo \"value=${versions}\"  >> $GITHUB_OUTPUT\n  test:\n    needs: go-versions\n    strategy:\n      fail-fast: false\n      matrix:\n        go-version: ${{fromJson(needs.go-versions.outputs.versions)}}\n        os:\n          - ubuntu-24.04\n          - ubuntu-22.04\n          - macos-26\n          - macos-15\n          - macos-15-intel\n          - macos-14\n          - windows-2025\n          - windows-2022\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      - name: Install Go\n        uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0\n        with:\n          go-version: ${{ matrix.go-version }}\n      - name: Test\n        run: |\n          go test -coverprofile='coverage.out' -covermode=atomic ./...\n"
  },
  {
    "path": ".gitignore",
    "content": "*~\n#*\n_obj\n*.tmp\n.idea\nvendor\n"
  },
  {
    "path": ".golangci.yml",
    "content": "version: \"2\"\nformatters:\n  enable:\n    - gci\n    - gofumpt\n  settings:\n    gci:\n      sections:\n        - standard\n        - default\n        - prefix(github.com/shirou)\nissues:\n  max-same-issues: 0\nlinters:\n  enable:\n    - asciicheck\n    - contextcheck\n    - durationcheck\n    - errorlint\n    - fatcontext\n    - gocritic\n    - gomodguard\n    - gosec\n    - govet\n    - importas\n    - ineffassign\n    - misspell\n    - nakedret\n    - nilnesserr\n    - noctx\n    - nolintlint\n    - perfsprint\n    - predeclared\n    - revive\n    - staticcheck\n    - testifylint\n    - thelper\n    - unparam\n    - usetesting\n  disable:\n    - errcheck\n    - unused\n  settings:\n    gocritic:\n      disabled-checks:\n        - captLocal\n        - commentedOutCode\n        - deferInLoop\n        - hexLiteral\n        - hugeParam\n        - tooManyResultsChecker\n        - unnamedResult\n      enable-all: true\n    gomodguard:\n      blocked:\n        modules:\n          - io/ioutil:\n              recommendations:\n                - io\n                - os\n    gosec:\n      excludes:\n        - G115\n    govet:\n      disable:\n        - copylocks\n        - fieldalignment\n        - testinggoroutine\n      enable-all: true\n    perfsprint:\n      # Optimizes even if it requires an int or uint type cast.\n      int-conversion: true\n      # Optimizes into `err.Error()` even if it is only equivalent for non-nil errors.\n      err-error: true\n      # Optimizes `fmt.Errorf`.\n      errorf: true\n      # Optimizes `fmt.Sprintf` with only one argument.\n      sprintf1: true\n      # Optimizes into strings concatenation.\n      strconcat: true\n    revive:\n      rules:\n        - name: blank-imports\n        - name: context-as-argument\n          arguments:\n            - allowTypesBefore: \"*testing.T\"\n        - name: context-keys-type\n        - name: dot-imports\n        - name: duplicated-imports\n        - name: early-return\n          arguments:\n            - \"preserveScope\"\n        - name: empty-block\n          disabled: true\n        - name: error-naming\n        - name: error-return\n        - name: error-strings\n        - name: exported\n          disabled: true\n        - name: errorf\n        - name: increment-decrement\n        - name: indent-error-flow\n          arguments:\n            - \"preserveScope\"\n        - name: range\n        - name: receiver-naming\n        - name: redefines-builtin-id\n        - name: redundant-import-alias\n        - name: superfluous-else\n          arguments:\n            - \"preserveScope\"\n        - name: time-date\n        - name: time-equal\n        - name: time-naming\n        - name: unexported-return\n        - name: unnecessary-stmt\n        - name: unreachable-code\n        - name: unused-parameter\n        - name: unused-receiver\n        - name: use-any\n        - name: var-declaration\n        - name: var-naming\n          arguments:\n            - [\"ID\"] # AllowList\n            - [\"VM\"] # DenyList\n            - - upperCaseConst: true # Extra parameter (upperCaseConst|skipPackageNameChecks)\n                skipPackageNameChecks: true\n    staticcheck:\n      checks:\n        - all\n        - -SA1019 # Using a deprecated function, variable, constant or field\n        - -SA2002 # Called testing.T.FailNow or SkipNow in a goroutine, which isn’t allowed\n        - -SA4003 # Comparing unsigned values against negative values is pointless\n        - -SA4004 # The loop exits unconditionally after one iteration\n        - -SA4008 # The variable in the loop condition never changes, are you incrementing the wrong variable?\n        - -SA5003 # Defers in infinite loops will never execute\n        - -SA9003 # Empty body in an if or else branch\n        - -ST1003 # Poorly chosen identifier\n    testifylint:\n      enable-all: true\n    usetesting:\n      os-create-temp: false\n      os-mkdir-temp: false\n  exclusions:\n    generated: lax\n    presets:\n      - comments\n      - common-false-positives\n      - legacy\n      - std-error-handling\n    rules:\n      - text: 'shadow: declaration of \"err\" shadows declaration at line'\n        linters:\n          - govet\n    warn-unused: true\noutput:\n  show-stats: false\nrun:\n  timeout: 5m\n"
  },
  {
    "path": "LICENSE",
    "content": "gopsutil is distributed under BSD license reproduced below.\n\nCopyright (c) 2014, WAKAYAMA Shirou\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n * Neither the name of the gopsutil authors nor the names of its contributors\n   may be used to endorse or promote products derived from this software without\n   specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n-------\ninternal/common/binary.go in the gopsutil is copied and modified from golang/encoding/binary.go.\n\n\n\nCopyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n   * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "Makefile",
    "content": ".PHONY: help check\n.DEFAULT_GOAL := help\n\nSUBPKGS=cpu disk docker host internal load mem net process\n\nhelp:  ## Show help\n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\033[36m%-30s\\033[0m %s\\n\", $$1, $$2}'\n\ncheck:  ## Check\n\terrcheck -ignore=\"Close|Run|Write\" ./...\n\tgolint ./... | egrep -v 'underscores|HttpOnly|should have comment|comment on exported|CamelCase|VM|UID' && exit 1 || exit 0\n\nBUILD_FAIL_PATTERN=grep -v \"exec format error\" | grep \"build failed\" && exit 1 || exit 0\nbuild_test:  ## test only buildable\n\t# Supported operating systems\n\tGOOS=linux GOARCH=amd64 go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=linux GOARCH=386 go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=linux GOARCH=arm go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=linux GOARCH=arm64 go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=linux GOARCH=loong64 go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=linux GOARCH=riscv64 go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=linux GOARCH=s390x go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=linux GOARCH=mips go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=freebsd GOARCH=amd64 go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=freebsd GOARCH=386 go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=freebsd GOARCH=arm go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=freebsd GOARCH=arm64 go test ./... | $(BUILD_FAIL_PATTERN)\n\tCGO_ENABLED=0 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=windows go test ./... | $(BUILD_FAIL_PATTERN)\n\t# The following operating systems are tested only for successful builds.\n\t# Value testing is not performed.\n\tGOOS=solaris go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=dragonfly go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=netbsd go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=openbsd go test ./... | $(BUILD_FAIL_PATTERN)\n\tGOOS=plan9 go test ./... | $(BUILD_FAIL_PATTERN)\n\tCGO_ENABLED=0 GOOS=aix GOARCH=ppc64  go test ./... | $(BUILD_FAIL_PATTERN)\n\nifeq ($(shell uname -s), Darwin)\n\tCGO_ENABLED=1 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN)\nendif\n\t@echo 'Successfully built on all known operating systems'\n\nvet:\n\tGOOS=darwin GOARCH=amd64 go vet ./...\n\tGOOS=darwin GOARCH=arm64 go vet ./...\n\n\tGOOS=dragonfly GOARCH=amd64 go vet ./...\n\n\tGOOS=freebsd GOARCH=amd64 go vet ./...\n\tGOOS=freebsd GOARCH=386 go vet ./...\n\tGOOS=freebsd GOARCH=arm go vet ./...\n\n\tGOOS=linux GOARCH=386 go vet ./...\n\tGOOS=linux GOARCH=amd64 go vet ./...\n\tGOOS=linux GOARCH=arm64 go vet ./...\n\tGOOS=linux GOARCH=arm go vet ./...\n\tGOOS=linux GOARCH=loong64 go vet ./...\n\tGOOS=linux GOARCH=mips64 go vet ./...\n\tGOOS=linux GOARCH=mips64le go vet ./...\n\tGOOS=linux GOARCH=mips go vet ./...\n\tGOOS=linux GOARCH=mipsle go vet ./...\n\tGOOS=linux GOARCH=ppc64le go vet ./...\n\tGOOS=linux GOARCH=ppc64 go vet ./...\n\tGOOS=linux GOARCH=riscv64 go vet ./...\n\tGOOS=linux GOARCH=s390x go vet ./...\n\n\tGOOS=netbsd GOARCH=amd64 go vet ./...\n\n\tGOOS=openbsd GOARCH=386 go vet ./...\n\tGOOS=openbsd GOARCH=amd64 go vet ./...\n\n\tGOOS=solaris GOARCH=amd64 go vet ./...\n\n\tGOOS=windows GOARCH=amd64 go vet ./...\n\tGOOS=windows GOARCH=386 go vet ./...\n\n\tGOOS=plan9 GOARCH=amd64 go vet ./...\n\tGOOS=plan9 GOARCH=386 go vet ./...\n\n\tCGO_ENABLED=0 GOOS=aix GOARCH=ppc64 go vet ./...\n\nmacos_test:\n\tCGO_ENABLED=0 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN)\n\tCGO_ENABLED=1 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN)\n\ninit_tools:\n\tgo get github.com/golang/dep/cmd/dep\n\nTAG=$(shell date +'v4.%y.%-m' --date='last Month')\n\nrelease:\n\tgit tag $(TAG)\n\tgit push origin $(TAG)\n"
  },
  {
    "path": "README.md",
    "content": "# gopsutil: psutil for Go\n\n[![Test](https://github.com/shirou/gopsutil/actions/workflows/test.yml/badge.svg)](https://github.com/shirou/gopsutil/actions/workflows/test.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/shirou/gopsutil/v4.svg)](https://pkg.go.dev/github.com/shirou/gopsutil/v4) [![Calendar Versioning](https://img.shields.io/badge/calver-vMAJOR.YY.MM-22bfda.svg)](https://calver.org/)\n\nThis is a port of psutil (https://github.com/giampaolo/psutil). The\nchallenge is porting all psutil functions on some architectures.\n\n## migration\n\n### v4 migration\n\nThere are some breaking changes. Please see [v4 release note](https://github.com/shirou/gopsutil/releases/tag/v4.24.5).\n\n## Tag semantics\n\ngopsutil tag policy is almost same as Semantic Versioning, but\nautomatically increases like [Ubuntu versioning](https://calver.org/).\n\nFor example, v4.24.04 means\n\n- v4: major version\n- 24: release year, 2024\n- 04: release month\n\ngopsutil aims to keep backwards compatibility until major version change.\n\nTagged at every end of month, but if there are only a few commits, it\ncan be skipped.\n\n## Available Architectures\n\n- FreeBSD i386/amd64/arm\n- Linux i386/amd64/arm(raspberry pi)\n- Windows i386/amd64/arm/arm64\n- Darwin amd64/arm64\n- OpenBSD i386/amd64/armv7/arm64/riscv64 (Thank you @mpfz0r!)\n- Solaris amd64 (developed and tested on SmartOS/Illumos, Thank you @jen20!)\n\nThese have partial support:\n\n- CPU on DragonFly BSD (#893, Thank you @gballet!)\n- host on Linux RISC-V (#896, Thank you @tklauser!)\n\nAll works are implemented without cgo by porting C structs to Go structs.\n\n## Usage\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n\n    \"github.com/shirou/gopsutil/v4/mem\"\n)\n\nfunc main() {\n    v, _ := mem.VirtualMemory()\n\n    // almost every return value is a struct\n    fmt.Printf(\"Total: %v, Free:%v, UsedPercent:%f%%\\n\", v.Total, v.Free, v.UsedPercent)\n\n    // convert to JSON. String() is also implemented\n    fmt.Println(v)\n}\n```\n\nThe output is below.\n\n    Total: 3179569152, Free:284233728, UsedPercent:84.508194%\n    {\"total\":3179569152,\"available\":492572672,\"used\":2895335424,\"usedPercent\":84.50819439828305, (snip...)}\n\nYou can set alternative locations for various system directories by using the following environment variables:\n\n- /proc: `HOST_PROC`\n- /sys: `HOST_SYS`\n- /etc: `HOST_ETC`\n- /var: `HOST_VAR`\n- /run: `HOST_RUN`\n- /dev: `HOST_DEV`\n- /: `HOST_ROOT`\n- /proc/N/mountinfo: `HOST_PROC_MOUNTINFO`\n\n### Adding settings using `context` (from v3.23.6)\n\nAs 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.\n\n```\n\tctx := context.WithValue(context.Background(), \n\t\tcommon.EnvKey, common.EnvMap{common.HostProcEnvKey: \"/myproc\"},\n\t)\n\tv, err := mem.VirtualMemoryWithContext(ctx)\n```\n\nFirst priority is given to the value set in `context`, then the value from the environment variable, and finally the default location.\n\n### Caching\n\nAs of v3.24.1, it is now possible to cached some values. These values default to false, not cached. \n\nBe 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).\n\n- `host`\n  - EnableBootTimeCache\n- `process`\n  - EnableBootTimeCache\n\n### `Ex` struct (from v4.24.5)\n\ngopsutil is designed to work across multiple platforms. However, there are differences in the information available on different platforms, such as memory information that exists on Linux but not on Windows.\n\nAs of v4.24.5, to access this platform-specific information, gopsutil provides functions named `Ex` within the package. Currently, these functions are available in the mem and sensor packages.\n\nThe Ex structs are specific to each platform. For example, on Linux, there is an `ExLinux` struct, which can be obtained using the `mem.NewExLinux()` function. On Windows, it's `mem.ExWindows()`. These Ex structs provide platform-specific information.\n\n```\nex := NewExWindows()\nv, err := ex.VirtualMemory()\nif err != nil {\n    panic(err)\n}\n\nfmt.Println(v.VirtualAvail)\nfmt.Println(v.VirtualTotal)\n\n// Output:\n// 140731958648832\n// 140737488224256\n```\n\ngopsutil aims to minimize platform differences by offering common functions. However, there are many requests to obtain unique information for each platform. The Ex structs are designed to meet those requests. Additional functionalities might be added in the future. The use of these structures makes it clear that the information they provide is specific to each platform, which is why they have been designed in this way.\n\n## Documentation\n\nSee https://pkg.go.dev/github.com/shirou/gopsutil/v4 or https://godocs.io/github.com/shirou/gopsutil/v4\n\n## Requirements\n\n- go1.18 or above is required.\n\n## More Info\n\nSeveral methods have been added which are not present in psutil, but\nwill provide useful information.\n\n- host/HostInfo() (linux)\n  - Hostname\n  - Uptime\n  - Procs\n  - OS (ex: \"linux\")\n  - Platform (ex: \"ubuntu\", \"arch\")\n  - PlatformFamily (ex: \"debian\")\n  - PlatformVersion (ex: \"Ubuntu 13.10\")\n  - VirtualizationSystem (ex: \"LXC\")\n  - VirtualizationRole (ex: \"guest\"/\"host\")\n- IOCounters\n  - Label (linux only) The registered [device mapper\n    name](https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm)\n- cpu/CPUInfo() (linux, freebsd)\n  - CPU (ex: 0, 1, ...)\n  - VendorID (ex: \"GenuineIntel\")\n  - Family\n  - Model\n  - Stepping\n  - PhysicalID\n  - CoreID\n  - Cores (ex: 2)\n  - ModelName (ex: \"Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz\")\n  - Mhz\n  - CacheSize\n  - Flags (ex: \"fpu vme de pse tsc msr pae mce cx8 ...\")\n  - Microcode\n- load/Avg() (linux, freebsd, solaris)\n  - Load1\n  - Load5\n  - Load15\n- docker/GetDockerIDList() (linux only)\n  - container id list ([]string)\n- docker/CgroupCPU() (linux only)\n  - user\n  - system\n- docker/CgroupMem() (linux only)\n  - various status\n- net_protocols (linux only)\n  - system wide stats on network protocols (i.e IP, TCP, UDP, etc.)\n  - sourced from /proc/net/snmp\n- iptables nf_conntrack (linux only)\n  - system wide stats on netfilter conntrack module\n  - sourced from /proc/sys/net/netfilter/nf_conntrack_count\n\nSome code is ported from Ohai. Many thanks.\n\n## Current Status\n\n- x: works\n- b: almost works, but something is broken\n\n|name                  |Linux  |FreeBSD  |OpenBSD  |macOS   |Windows  |Solaris  |Plan 9   |AIX      |\n|----------------------|-------|---------|---------|--------|---------|---------|---------|---------|\n|cpu\\_times            |x      |x        |x        |x       |x        |         |b        |x        |\n|cpu\\_count            |x      |x        |x        |x       |x        |         |x        |x        |\n|cpu\\_percent          |x      |x        |x        |x       |x        |         |         |x        |\n|cpu\\_times\\_percent   |x      |x        |x        |x       |x        |         |         |x        |\n|virtual\\_memory       |x      |x        |x        |x       |x        |b        |x        |x        |\n|swap\\_memory          |x      |x        |x        |x       |         |         |x        |X        |\n|disk\\_partitions      |x      |x        |x        |x       |x        |         |         |x        |\n|disk\\_io\\_counters    |x      |x        |x        |x       |x        |         |         |         |\n|disk\\_usage           |x      |x        |x        |x       |x        |         |         |x        |\n|net\\_io\\_counters     |x      |x        |x        |b       |x        |x        |         |         |\n|boot\\_time            |x      |x        |x        |x       |x        |         |         |X        |\n|users                 |x      |x        |x        |x       |x        |         |         |x        |\n|pids                  |x      |x        |x        |x       |x        |         |         |         |\n|pid\\_exists           |x      |x        |x        |x       |x        |         |         |         |\n|net\\_connections      |x      |x        |x        |x       |         |         |         |x        |\n|net\\_protocols        |x      |         |         |        |         |         |         |x        |\n|net\\_if\\_addrs        |       |         |         |        |         |         |         |x        |\n|net\\_if\\_stats        |       |         |         |        |         |         |         |x        |\n|netfilter\\_conntrack  |x      |         |         |        |         |         |         |         |\n|sensors_temperature   |x      |         |         |x       |x        |x        |         |         |\n\n\n### Process class\n\n|name                |Linux  |FreeBSD  |OpenBSD  |macOS  |Windows  |\n|--------------------|-------|---------|---------|-------|---------|\n|pid                 |x      |x        |x        |x      |x        |\n|ppid                |x      |x        |x        |x      |x        |\n|name                |x      |x        |x        |x      |x        |\n|cmdline             |x      |x        |x        |x      |x        |\n|create\\_time        |x      |         |         |x      |x        |\n|status              |x      |x        |x        |x      |         |\n|cwd                 |x      |x        |x        |x      |x        |\n|exe                 |x      |x        |x        |       |x        |\n|uids                |x      |x        |x        |x      |         |\n|gids                |x      |x        |x        |x      |         |\n|terminal            |x      |x        |x        |       |         |\n|io\\_counters        |x      |x        |x        |       |x        |\n|nice                |x      |x        |x        |x      |x        |\n|num\\_fds            |x      |         |         |x      |x        |\n|num\\_ctx\\_switches  |x      |         |         |       |         |\n|num\\_threads        |x      |x        |x        |x      |x        |\n|cpu\\_times          |x      |         |         |       |x        |\n|memory\\_info        |x      |x        |x        |x      |x        |\n|memory\\_maps        |x      |         |         |       |         |\n|open\\_files         |x      |         |         |       |x        |\n|send\\_signal        |x      |x        |x        |x      |         |\n|suspend             |x      |x        |x        |x      |x        |\n|resume              |x      |x        |x        |x      |x        |\n|terminate           |x      |x        |x        |x      |x        |\n|kill                |x      |x        |x        |x      |         |\n|username            |x      |x        |x        |x      |x        |\n|ionice              |       |         |         |       |         |\n|rlimit              |x      |         |         |       |         |\n|num\\_handlers       |       |         |         |       |         |\n|threads             |x      |         |         |       |         |\n|cpu\\_percent        |x      |         |x        |x      |x        |\n|cpu\\_affinity       |       |         |         |       |         |\n|memory\\_percent     |x      |         |         |       |x        |\n|parent              |x      |         |x        |x      |x        |\n|children            |x      |x        |x        |x      |x        |\n|connections         |x      |         |x        |x      |         |\n|is\\_running         |       |         |         |       |         |\n|page\\_faults        |x      |         |         |       |x        |\n\n### gopsutil Original Metrics\n\n|item                    |Linux  |FreeBSD  |OpenBSD  |macOS   |Windows |Solaris  |AIX      |\n|------------------------|-------|---------|---------|--------|--------|---------|---------|\n|**HostInfo**            |       |         |         |        |        |         |         |\n|hostname                |x      |x        |x        |x       |x       |x        |X        |\n|uptime                  |x      |x        |x        |x       |        |x        |x        |\n|process                 |x      |x        |x        |        |        |x        |         |\n|os                      |x      |x        |x        |x       |x       |x        |x        |\n|platform                |x      |x        |x        |x       |        |x        |x        |\n|platformfamily          |x      |x        |x        |x       |        |x        |x        |\n|virtualization          |x      |         |         |        |        |         |         |\n|**CPU**                 |       |         |         |        |        |         |         |\n|VendorID                |x      |x        |x        |x       |x       |x        |x        |\n|Family                  |x      |x        |x        |x       |x       |x        |x        |\n|Model                   |x      |x        |x        |x       |x       |x        |x        |\n|Stepping                |x      |x        |x        |x       |x       |x        |         |\n|PhysicalID              |x      |         |         |        |        |x        |         |\n|CoreID                  |x      |         |         |        |        |x        |         |\n|Cores                   |x      |         |         |x       |x       |x        |x        |\n|ModelName               |x      |x        |x        |x       |x       |x        |x        |\n|Microcode               |x      |         |         |        |        |x        |         |\n|**LoadAvg**             |       |         |         |        |        |         |         |\n|Load1                   |x      |x        |x        |x       |x       |x        |x        |\n|Load5                   |x      |x        |x        |x       |x       |x        |x        |\n|Load15                  |x      |x        |x        |x       |x       |x        |x        |\n|**Docker GetDockerID**  |       |         |         |        |        |         |         |\n|container id            |x      |no       |no       |no      |no      |no       |no       |\n|**Docker CgroupsCPU**   |       |         |         |        |        |         |         |\n|user                    |x      |no       |no       |no      |no      |no       |no       |\n|system                  |x      |no       |no       |no      |no      |no       |no       |\n|**Docker CgroupsMem**   |       |         |         |        |        |         |         |\n|various                 |x      |no       |no       |no      |no      |no       |no       |\n\n- future work\n  - process_iter\n  - wait_procs\n  - Process class\n    - as_dict\n    - wait\n  - AIX processes\n\n## License\n\nNew BSD License (same as psutil)\n\n## Related Works\n\nI have been influenced by the following great works:\n\n- psutil: https://github.com/giampaolo/psutil\n- dstat: https://github.com/dagwieers/dstat\n- gosigar: https://github.com/cloudfoundry/gosigar/\n- goprocinfo: https://github.com/c9s/goprocinfo\n- go-ps: https://github.com/mitchellh/go-ps\n- ohai: https://github.com/opscode/ohai/\n- bosun:\n  https://github.com/bosun-monitor/bosun/tree/master/cmd/scollector/collectors\n- mackerel:\n  https://github.com/mackerelio/mackerel-agent/tree/master/metrics\n\n## How to Contribute\n\n1.  Fork it\n2.  Create your feature branch (git checkout -b my-new-feature)\n3.  Commit your changes (git commit -am 'Add some feature')\n4.  Push to the branch (git push origin my-new-feature)\n5.  Create new Pull Request\n\nEnglish is not my native language, so PRs correcting grammar or spelling are welcome and appreciated.\n"
  },
  {
    "path": "common/env.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage common\n\ntype EnvKeyType string\n\n// EnvKey is a context key that can be used to set programmatically the environment\n// gopsutil relies on to perform calls against the OS.\n// Example of use:\n//\n//\tctx := context.WithValue(context.Background(), common.EnvKey, EnvMap{common.HostProcEnvKey: \"/myproc\"})\n//\tavg, err := load.AvgWithContext(ctx)\nvar EnvKey = EnvKeyType(\"env\")\n\nconst (\n\tHostProcEnvKey    EnvKeyType = \"HOST_PROC\"\n\tHostSysEnvKey     EnvKeyType = \"HOST_SYS\"\n\tHostEtcEnvKey     EnvKeyType = \"HOST_ETC\"\n\tHostVarEnvKey     EnvKeyType = \"HOST_VAR\"\n\tHostRunEnvKey     EnvKeyType = \"HOST_RUN\"\n\tHostDevEnvKey     EnvKeyType = \"HOST_DEV\"\n\tHostRootEnvKey    EnvKeyType = \"HOST_ROOT\"\n\tHostProcMountinfo EnvKeyType = \"HOST_PROC_MOUNTINFO\"\n)\n\ntype EnvMap map[EnvKeyType]string\n"
  },
  {
    "path": "cpu/cpu.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// TimesStat contains the amounts of time the CPU has spent performing different\n// kinds of work. Time units are in seconds. It is based on linux /proc/stat file.\ntype TimesStat struct {\n\tCPU       string  `json:\"cpu\"`\n\tUser      float64 `json:\"user\"`\n\tSystem    float64 `json:\"system\"`\n\tIdle      float64 `json:\"idle\"`\n\tNice      float64 `json:\"nice\"`\n\tIowait    float64 `json:\"iowait\"`\n\tIrq       float64 `json:\"irq\"`\n\tSoftirq   float64 `json:\"softirq\"`\n\tSteal     float64 `json:\"steal\"`\n\tGuest     float64 `json:\"guest\"`\n\tGuestNice float64 `json:\"guestNice\"`\n}\n\ntype InfoStat struct {\n\tCPU        int32    `json:\"cpu\"`\n\tVendorID   string   `json:\"vendorId\"`\n\tFamily     string   `json:\"family\"`\n\tModel      string   `json:\"model\"`\n\tStepping   int32    `json:\"stepping\"`\n\tPhysicalID string   `json:\"physicalId\"`\n\tCoreID     string   `json:\"coreId\"`\n\tCores      int32    `json:\"cores\"`\n\tModelName  string   `json:\"modelName\"`\n\tMhz        float64  `json:\"mhz\"`\n\tCacheSize  int32    `json:\"cacheSize\"`\n\tFlags      []string `json:\"flags\"`\n\tMicrocode  string   `json:\"microcode\"`\n}\n\ntype lastPercent struct {\n\tsync.Mutex\n\tlastCPUTimes    []TimesStat\n\tlastPerCPUTimes []TimesStat\n}\n\nvar (\n\tlastCPUPercent lastPercent\n\tinvoke         common.Invoker = common.Invoke{}\n)\n\nfunc init() {\n\tlastCPUPercent.Lock()\n\tlastCPUPercent.lastCPUTimes, _ = Times(false)\n\tlastCPUPercent.lastPerCPUTimes, _ = Times(true)\n\tlastCPUPercent.Unlock()\n}\n\n// Counts returns the number of physical or logical cores in the system\nfunc Counts(logical bool) (int, error) {\n\treturn CountsWithContext(context.Background(), logical)\n}\n\nfunc (c TimesStat) String() string {\n\tv := []string{\n\t\t`\"cpu\":\"` + c.CPU + `\"`,\n\t\t`\"user\":` + strconv.FormatFloat(c.User, 'f', 1, 64),\n\t\t`\"system\":` + strconv.FormatFloat(c.System, 'f', 1, 64),\n\t\t`\"idle\":` + strconv.FormatFloat(c.Idle, 'f', 1, 64),\n\t\t`\"nice\":` + strconv.FormatFloat(c.Nice, 'f', 1, 64),\n\t\t`\"iowait\":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64),\n\t\t`\"irq\":` + strconv.FormatFloat(c.Irq, 'f', 1, 64),\n\t\t`\"softirq\":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),\n\t\t`\"steal\":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),\n\t\t`\"guest\":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),\n\t\t`\"guestNice\":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),\n\t}\n\n\treturn `{` + strings.Join(v, \",\") + `}`\n}\n\n// Deprecated: Total returns the total number of seconds in a CPUTimesStat\n// Please do not use this internal function.\nfunc (c TimesStat) Total() float64 {\n\ttotal := c.User + c.System + c.Idle + c.Nice + c.Iowait + c.Irq +\n\t\tc.Softirq + c.Steal + c.Guest + c.GuestNice\n\n\treturn total\n}\n\nfunc (c InfoStat) String() string {\n\ts, _ := json.Marshal(c)\n\treturn string(s)\n}\n\nfunc getAllBusy(t TimesStat) (float64, float64) {\n\ttot := t.Total()\n\tif runtime.GOOS == \"linux\" {\n\t\ttot -= t.Guest     // Linux 2.6.24+\n\t\ttot -= t.GuestNice // Linux 3.2.0+\n\t}\n\n\tbusy := tot - t.Idle - t.Iowait\n\n\treturn tot, busy\n}\n\nfunc calculateBusy(t1, t2 TimesStat) float64 {\n\tt1All, t1Busy := getAllBusy(t1)\n\tt2All, t2Busy := getAllBusy(t2)\n\n\tif t2Busy <= t1Busy {\n\t\treturn 0\n\t}\n\tif t2All <= t1All {\n\t\treturn 100\n\t}\n\treturn math.Min(100, math.Max(0, (t2Busy-t1Busy)/(t2All-t1All)*100))\n}\n\nfunc calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {\n\t// Make sure the CPU measurements have the same length.\n\tif len(t1) != len(t2) {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"received two CPU counts: %d != %d\",\n\t\t\tlen(t1), len(t2),\n\t\t)\n\t}\n\n\tret := make([]float64, len(t1))\n\tfor i, t := range t2 {\n\t\tret[i] = calculateBusy(t1[i], t)\n\t}\n\treturn ret, nil\n}\n\n// Percent calculates the percentage of cpu used either per CPU or combined.\n// If an interval of 0 is given it will compare the current cpu times against the last call.\n// Returns one value per cpu, or a single value if percpu is set to false.\nfunc Percent(interval time.Duration, percpu bool) ([]float64, error) {\n\treturn PercentWithContext(context.Background(), interval, percpu)\n}\n\nfunc PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {\n\tif interval <= 0 {\n\t\treturn percentUsedFromLastCallWithContext(ctx, percpu)\n\t}\n\n\t// Get CPU usage at the start of the interval.\n\tcpuTimes1, err := TimesWithContext(ctx, percpu)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := common.Sleep(ctx, interval); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// And at the end of the interval.\n\tcpuTimes2, err := TimesWithContext(ctx, percpu)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn calculateAllBusy(cpuTimes1, cpuTimes2)\n}\n\nfunc percentUsedFromLastCall(percpu bool) ([]float64, error) {\n\treturn percentUsedFromLastCallWithContext(context.Background(), percpu)\n}\n\nfunc percentUsedFromLastCallWithContext(ctx context.Context, percpu bool) ([]float64, error) {\n\tcpuTimes, err := TimesWithContext(ctx, percpu)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlastCPUPercent.Lock()\n\tdefer lastCPUPercent.Unlock()\n\tvar lastTimes []TimesStat\n\tif percpu {\n\t\tlastTimes = lastCPUPercent.lastPerCPUTimes\n\t\tlastCPUPercent.lastPerCPUTimes = cpuTimes\n\t} else {\n\t\tlastTimes = lastCPUPercent.lastCPUTimes\n\t\tlastCPUPercent.lastCPUTimes = cpuTimes\n\t}\n\n\tif lastTimes == nil {\n\t\treturn nil, errors.New(\"error getting times for cpu percent. lastTimes was nil\")\n\t}\n\treturn calculateAllBusy(lastTimes, cpuTimes)\n}\n"
  },
  {
    "path": "cpu/cpu_aix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage cpu\n\nimport (\n\t\"context\"\n)\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n"
  },
  {
    "path": "cpu/cpu_aix_cgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && cgo\n\npackage cpu\n\nimport (\n\t\"context\"\n\n\t\"github.com/power-devops/perfstat\"\n)\n\nfunc TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {\n\tvar ret []TimesStat\n\tif percpu {\n\t\tcpus, err := perfstat.CpuStat()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor _, c := range cpus {\n\t\t\tct := &TimesStat{\n\t\t\t\tCPU:    c.Name,\n\t\t\t\tIdle:   float64(c.Idle),\n\t\t\t\tUser:   float64(c.User),\n\t\t\t\tSystem: float64(c.Sys),\n\t\t\t\tIowait: float64(c.Wait),\n\t\t\t}\n\t\t\tret = append(ret, *ct)\n\t\t}\n\t} else {\n\t\tc, err := perfstat.CpuTotalStat()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tct := &TimesStat{\n\t\t\tCPU:    \"cpu-total\",\n\t\t\tIdle:   float64(c.Idle),\n\t\t\tUser:   float64(c.User),\n\t\t\tSystem: float64(c.Sys),\n\t\t\tIowait: float64(c.Wait),\n\t\t}\n\t\tret = append(ret, *ct)\n\t}\n\treturn ret, nil\n}\n\nfunc InfoWithContext(ctx context.Context) ([]InfoStat, error) {\n\tc, err := perfstat.CpuTotalStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tp, err := perfstat.LparInfo()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tinfo := InfoStat{\n\t\tCPU:       0,\n\t\tModelName: c.Description,\n\t\tMhz:       float64(c.ProcessorHz / 1000000),\n\t\tCores:     int32(p.OnlineVCpus),\n\t}\n\tresult := []InfoStat{info}\n\treturn result, nil\n}\n\nfunc CountsWithContext(ctx context.Context, logical bool) (int, error) {\n\tif logical {\n\t\tc, err := perfstat.CpuTotalStat()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\treturn c.NCpusCfg, nil\n\t}\n\t// For physical count, use the number of online virtual CPUs (before SMT multiplications).\n\tp, err := perfstat.LparInfo()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int(p.OnlineVCpus), nil\n}\n"
  },
  {
    "path": "cpu/cpu_aix_nocgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && !cgo\n\npackage cpu\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {\n\tvar ret []TimesStat\n\tif percpu {\n\t\tperOut, err := invoke.CommandWithContext(ctx, \"sar\", \"-u\", \"-P\", \"ALL\", \"10\", \"1\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tlines := strings.Split(string(perOut), \"\\n\")\n\t\tif len(lines) < 6 {\n\t\t\treturn []TimesStat{}, common.ErrNotImplementedError\n\t\t}\n\n\t\thp := strings.Fields(lines[5]) // headers\n\t\tfor l := 6; l < len(lines)-1; l++ {\n\t\t\tct := &TimesStat{}\n\t\t\tv := strings.Fields(lines[l]) // values\n\t\t\tfor i, header := range hp {\n\t\t\t\t// We're done in any of these use cases\n\t\t\t\tif i >= len(v) || v[0] == \"-\" {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// Position variable for v\n\t\t\t\tpos := i\n\t\t\t\t// There is a missing field at the beginning of all but the first line\n\t\t\t\t// so adjust the position\n\t\t\t\tif l > 6 {\n\t\t\t\t\tpos = i - 1\n\t\t\t\t}\n\t\t\t\t// We don't want invalid positions\n\t\t\t\tif pos < 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif t, err := strconv.ParseFloat(v[pos], 64); err == nil {\n\t\t\t\t\tswitch header {\n\t\t\t\t\tcase `cpu`:\n\t\t\t\t\t\tct.CPU = strconv.FormatFloat(t, 'f', -1, 64)\n\t\t\t\t\tcase `%usr`:\n\t\t\t\t\t\tct.User = t\n\t\t\t\t\tcase `%sys`:\n\t\t\t\t\t\tct.System = t\n\t\t\t\t\tcase `%wio`:\n\t\t\t\t\t\tct.Iowait = t\n\t\t\t\t\tcase `%idle`:\n\t\t\t\t\t\tct.Idle = t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Valid CPU data, so append it\n\t\t\tret = append(ret, *ct)\n\t\t}\n\t} else {\n\t\tout, err := invoke.CommandWithContext(ctx, \"sar\", \"-u\", \"10\", \"1\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tlines := strings.Split(string(out), \"\\n\")\n\t\tif len(lines) < 5 {\n\t\t\treturn []TimesStat{}, common.ErrNotImplementedError\n\t\t}\n\n\t\tct := &TimesStat{CPU: \"cpu-total\"}\n\t\th := strings.Fields(lines[len(lines)-3]) // headers\n\t\tv := strings.Fields(lines[len(lines)-2]) // values\n\t\tfor i, header := range h {\n\t\t\tif t, err := strconv.ParseFloat(v[i], 64); err == nil {\n\t\t\t\tswitch header {\n\t\t\t\tcase `%usr`:\n\t\t\t\t\tct.User = t\n\t\t\t\tcase `%sys`:\n\t\t\t\t\tct.System = t\n\t\t\t\tcase `%wio`:\n\t\t\t\t\tct.Iowait = t\n\t\t\t\tcase `%idle`:\n\t\t\t\t\tct.Idle = t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tret = append(ret, *ct)\n\t}\n\n\treturn ret, nil\n}\n\nfunc InfoWithContext(ctx context.Context) ([]InfoStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"prtconf\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := InfoStat{}\n\tfor _, line := range strings.Split(string(out), \"\\n\") {\n\t\tswitch {\n\t\tcase strings.HasPrefix(line, \"Number Of Processors:\"):\n\t\t\tp := strings.Fields(line)\n\t\t\tif len(p) > 3 {\n\t\t\t\tif t, err := strconv.ParseUint(p[3], 10, 64); err == nil {\n\t\t\t\t\tret.Cores = int32(t)\n\t\t\t\t}\n\t\t\t}\n\t\tcase strings.HasPrefix(line, \"Processor Clock Speed:\"):\n\t\t\tp := strings.Fields(line)\n\t\t\tif len(p) > 4 {\n\t\t\t\tif t, err := strconv.ParseFloat(p[3], 64); err == nil {\n\t\t\t\t\tswitch strings.ToUpper(p[4]) {\n\t\t\t\t\tcase \"MHZ\":\n\t\t\t\t\t\tret.Mhz = t\n\t\t\t\t\tcase \"GHZ\":\n\t\t\t\t\t\tret.Mhz = t * 1000.0\n\t\t\t\t\tcase \"KHZ\":\n\t\t\t\t\t\tret.Mhz = t / 1000.0\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tret.Mhz = t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tcase strings.HasPrefix(line, \"System Model:\"):\n\t\t\tp := strings.Split(string(line), \":\")\n\t\t\tif p != nil {\n\t\t\t\tret.VendorID = strings.TrimSpace(p[1])\n\t\t\t}\n\t\tcase strings.HasPrefix(line, \"Processor Type:\"):\n\t\t\tp := strings.Split(string(line), \":\")\n\t\t\tif p != nil {\n\t\t\t\tc := strings.Split(string(p[1]), \"_\")\n\t\t\t\tif c != nil {\n\t\t\t\t\tret.Family = strings.TrimSpace(c[0])\n\t\t\t\t\tret.Model = strings.TrimSpace(c[1])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn []InfoStat{ret}, nil\n}\n\nfunc CountsWithContext(ctx context.Context, _ bool) (int, error) {\n\tinfo, err := InfoWithContext(ctx)\n\tif err == nil {\n\t\treturn int(info[0].Cores), nil\n\t}\n\treturn 0, err\n}\n"
  },
  {
    "path": "cpu/cpu_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage cpu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"github.com/tklauser/go-sysconf\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// sys/resource.h\nconst (\n\tCPUser    = 0\n\tcpNice    = 1\n\tcpSys     = 2\n\tcpIntr    = 3\n\tcpIdle    = 4\n\tcpUStates = 5\n)\n\n// mach/machine.h\nconst (\n\tcpuStateUser   = 0\n\tcpuStateSystem = 1\n\tcpuStateIdle   = 2\n\tcpuStateNice   = 3\n\tcpuStateMax    = 4\n)\n\n// mach/processor_info.h\nconst (\n\tprocessorCpuLoadInfo = 2 //nolint:revive //FIXME\n)\n\ntype hostCpuLoadInfoData struct { //nolint:revive //FIXME\n\tcpuTicks [cpuStateMax]uint32\n}\n\n// default value. from time.h\nvar ClocksPerSec = float64(128)\n\nfunc init() {\n\tclkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)\n\t// ignore errors\n\tif err == nil {\n\t\tClocksPerSec = float64(clkTck)\n\t}\n}\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {\n\tsys, err := common.NewSystemLib()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer sys.Close()\n\n\tif percpu {\n\t\treturn perCPUTimes(sys)\n\t}\n\n\treturn allCPUTimes(sys)\n}\n\n// Returns only one CPUInfoStat on FreeBSD\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(_ context.Context) ([]InfoStat, error) {\n\tvar ret []InfoStat\n\n\tc := InfoStat{}\n\tc.ModelName, _ = unix.Sysctl(\"machdep.cpu.brand_string\")\n\tfamily, _ := unix.SysctlUint32(\"machdep.cpu.family\")\n\tc.Family = strconv.FormatUint(uint64(family), 10)\n\tmodel, _ := unix.SysctlUint32(\"machdep.cpu.model\")\n\tc.Model = strconv.FormatUint(uint64(model), 10)\n\tstepping, _ := unix.SysctlUint32(\"machdep.cpu.stepping\")\n\tc.Stepping = int32(stepping)\n\tfeatures, err := unix.Sysctl(\"machdep.cpu.features\")\n\tif err == nil {\n\t\tfor _, v := range strings.Fields(features) {\n\t\t\tc.Flags = append(c.Flags, strings.ToLower(v))\n\t\t}\n\t}\n\tleaf7Features, err := unix.Sysctl(\"machdep.cpu.leaf7_features\")\n\tif err == nil {\n\t\tfor _, v := range strings.Fields(leaf7Features) {\n\t\t\tc.Flags = append(c.Flags, strings.ToLower(v))\n\t\t}\n\t}\n\textfeatures, err := unix.Sysctl(\"machdep.cpu.extfeatures\")\n\tif err == nil {\n\t\tfor _, v := range strings.Fields(extfeatures) {\n\t\t\tc.Flags = append(c.Flags, strings.ToLower(v))\n\t\t}\n\t}\n\tcores, _ := unix.SysctlUint32(\"machdep.cpu.core_count\")\n\tc.Cores = int32(cores)\n\tcacheSize, _ := unix.SysctlUint32(\"machdep.cpu.cache.size\")\n\tc.CacheSize = int32(cacheSize)\n\tc.VendorID, _ = unix.Sysctl(\"machdep.cpu.vendor\")\n\n\tv, err := getFrequency()\n\tif err == nil {\n\t\tc.Mhz = v\n\t}\n\n\treturn append(ret, c), nil\n}\n\nfunc CountsWithContext(_ context.Context, logical bool) (int, error) {\n\tvar cpuArgument string\n\tif logical {\n\t\tcpuArgument = \"hw.logicalcpu\"\n\t} else {\n\t\tcpuArgument = \"hw.physicalcpu\"\n\t}\n\n\tcount, err := unix.SysctlUint32(cpuArgument)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn int(count), nil\n}\n\nfunc perCPUTimes(sys *common.SystemLib) ([]TimesStat, error) {\n\tvar count, ncpu uint32\n\tvar cpuload *hostCpuLoadInfoData\n\n\tstatus := sys.HostProcessorInfo(sys.MachHostSelf(), processorCpuLoadInfo,\n\t\t&ncpu, uintptr(unsafe.Pointer(&cpuload)), &count)\n\n\tif status != common.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"host_processor_info error=%d\", status)\n\t}\n\n\tif cpuload == nil {\n\t\treturn nil, errors.New(\"host_processor_info returned nil cpuload\")\n\t}\n\n\tdefer sys.VMDeallocate(sys.MachTaskSelf(), uintptr(unsafe.Pointer(cpuload)), uintptr(ncpu))\n\n\tret := []TimesStat{}\n\tloads := unsafe.Slice(cpuload, ncpu)\n\n\tfor i := 0; i < int(ncpu); i++ {\n\t\tc := TimesStat{\n\t\t\tCPU:    fmt.Sprintf(\"cpu%d\", i),\n\t\t\tUser:   float64(loads[i].cpuTicks[cpuStateUser]) / ClocksPerSec,\n\t\t\tSystem: float64(loads[i].cpuTicks[cpuStateSystem]) / ClocksPerSec,\n\t\t\tNice:   float64(loads[i].cpuTicks[cpuStateNice]) / ClocksPerSec,\n\t\t\tIdle:   float64(loads[i].cpuTicks[cpuStateIdle]) / ClocksPerSec,\n\t\t}\n\t\tret = append(ret, c)\n\t}\n\n\treturn ret, nil\n}\n\nfunc allCPUTimes(sys *common.SystemLib) ([]TimesStat, error) {\n\tvar cpuload hostCpuLoadInfoData\n\tcount := uint32(cpuStateMax)\n\n\tstatus := sys.HostStatistics(sys.MachHostSelf(), common.HOST_CPU_LOAD_INFO,\n\t\tuintptr(unsafe.Pointer(&cpuload)), &count)\n\n\tif status != common.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"host_statistics error=%d\", status)\n\t}\n\n\tc := TimesStat{\n\t\tCPU:    \"cpu-total\",\n\t\tUser:   float64(cpuload.cpuTicks[cpuStateUser]) / ClocksPerSec,\n\t\tSystem: float64(cpuload.cpuTicks[cpuStateSystem]) / ClocksPerSec,\n\t\tNice:   float64(cpuload.cpuTicks[cpuStateNice]) / ClocksPerSec,\n\t\tIdle:   float64(cpuload.cpuTicks[cpuStateIdle]) / ClocksPerSec,\n\t}\n\n\treturn []TimesStat{c}, nil\n}\n"
  },
  {
    "path": "cpu/cpu_darwin_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin && arm64\n\npackage cpu\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"unsafe\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// https://github.com/shoenig/go-m1cpu/blob/v0.1.6/cpu.go\nfunc getFrequency() (float64, error) {\n\tiokit, err := common.NewIOKitLib()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer iokit.Close()\n\n\tcorefoundation, err := common.NewCoreFoundationLib()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer corefoundation.Close()\n\n\tmatching := iokit.IOServiceMatching(\"AppleARMIODevice\")\n\n\tvar iterator uint32\n\tif status := iokit.IOServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(matching), &iterator); status != common.KERN_SUCCESS {\n\t\treturn 0.0, fmt.Errorf(\"IOServiceGetMatchingServices error=%d\", status)\n\t}\n\tdefer iokit.IOObjectRelease(iterator)\n\n\tpCorekey := corefoundation.CFStringCreateWithCString(common.KCFAllocatorDefault, \"voltage-states5-sram\", common.KCFStringEncodingUTF8)\n\tdefer corefoundation.CFRelease(uintptr(pCorekey))\n\n\tvar pCoreHz uint32\n\tfor {\n\t\tservice := iokit.IOIteratorNext(iterator)\n\t\tif service <= 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tbuf := common.NewCStr(512)\n\t\tiokit.IORegistryEntryGetName(service, buf)\n\n\t\tif buf.GoString() == \"pmgr\" {\n\t\t\tpCoreRef := iokit.IORegistryEntryCreateCFProperty(service, uintptr(pCorekey), common.KCFAllocatorDefault, common.KNilOptions)\n\t\t\tlength := corefoundation.CFDataGetLength(uintptr(pCoreRef))\n\t\t\tdata := corefoundation.CFDataGetBytePtr(uintptr(pCoreRef))\n\n\t\t\t// composite uint32 from the byte array\n\t\t\tbuf := unsafe.Slice((*byte)(data), length)\n\n\t\t\t// combine the bytes into a uint32 value\n\t\t\tb := buf[length-8 : length-4]\n\t\t\tpCoreHz = binary.LittleEndian.Uint32(b)\n\t\t\tcorefoundation.CFRelease(uintptr(pCoreRef))\n\t\t\tiokit.IOObjectRelease(service)\n\t\t\tbreak\n\t\t}\n\n\t\tiokit.IOObjectRelease(service)\n\t}\n\n\treturn float64(pCoreHz / 1_000_000), nil\n}\n"
  },
  {
    "path": "cpu/cpu_darwin_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin && !arm64\n\npackage cpu\n\nimport \"golang.org/x/sys/unix\"\n\nfunc getFrequency() (float64, error) {\n\t// Use the rated frequency of the CPU. This is a static value and does not\n\t// account for low power or Turbo Boost modes.\n\tcpuFrequency, err := unix.SysctlUint64(\"hw.cpufrequency\")\n\treturn float64(cpuFrequency) / 1000000.0, err\n}\n"
  },
  {
    "path": "cpu/cpu_darwin_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage cpu\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestInfo_AppleSilicon(t *testing.T) {\n\tif runtime.GOARCH != \"arm64\" {\n\t\tt.Skip(\"wrong cpu type\")\n\t}\n\n\tv, err := Info()\n\trequire.NoErrorf(t, err, \"cpu info should be implemented on darwin systems\")\n\n\tfor _, vv := range v {\n\t\tassert.NotEmptyf(t, vv.ModelName, \"could not get CPU info: %v\", vv)\n\t\tif vv.Mhz <= 0 && os.Getenv(\"CI\") != \"true\" {\n\t\t\tt.Errorf(\"could not get frequency of: %s\", vv.ModelName)\n\t\t}\n\t\tassert.LessOrEqualf(t, vv.Mhz, float64(6000), \"cpu frequency is absurdly high value: %f MHz\", vv.Mhz)\n\t}\n}\n"
  },
  {
    "path": "cpu/cpu_dragonfly.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"github.com/tklauser/go-sysconf\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar (\n\tClocksPerSec   = float64(128)\n\tcpuMatch       = regexp.MustCompile(`^CPU:`)\n\toriginMatch    = regexp.MustCompile(`Origin\\s*=\\s*\"(.+)\"\\s+Id\\s*=\\s*(.+)\\s+Stepping\\s*=\\s*(.+)`)\n\tfeaturesMatch  = regexp.MustCompile(`Features=.+<(.+)>`)\n\tfeaturesMatch2 = regexp.MustCompile(`Features2=[a-f\\dx]+<(.+)>`)\n\tcpuEnd         = regexp.MustCompile(`^Trying to mount root`)\n\tcpuTimesSize   int\n\temptyTimes     cpuTimes\n)\n\nfunc init() {\n\tclkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)\n\t// ignore errors\n\tif err == nil {\n\t\tClocksPerSec = float64(clkTck)\n\t}\n}\n\nfunc timeStat(name string, t *cpuTimes) *TimesStat {\n\treturn &TimesStat{\n\t\tUser:   float64(t.User) / ClocksPerSec,\n\t\tNice:   float64(t.Nice) / ClocksPerSec,\n\t\tSystem: float64(t.Sys) / ClocksPerSec,\n\t\tIdle:   float64(t.Idle) / ClocksPerSec,\n\t\tIrq:    float64(t.Intr) / ClocksPerSec,\n\t\tCPU:    name,\n\t}\n}\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {\n\tif percpu {\n\t\tbuf, err := unix.SysctlRaw(\"kern.cp_times\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// We can't do this in init due to the conflict with cpu.init()\n\t\tif cpuTimesSize == 0 {\n\t\t\tcpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())\n\t\t}\n\n\t\tncpus := len(buf) / cpuTimesSize\n\t\tret := make([]TimesStat, 0, ncpus)\n\t\tfor i := 0; i < ncpus; i++ {\n\t\t\ttimes := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))\n\t\t\tif *times == emptyTimes {\n\t\t\t\t// CPU not present\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret = append(ret, *timeStat(fmt.Sprintf(\"cpu%d\", len(ret)), times))\n\t\t}\n\t\treturn ret, nil\n\t}\n\n\tbuf, err := unix.SysctlRaw(\"kern.cp_time\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttimes := (*cpuTimes)(unsafe.Pointer(&buf[0]))\n\treturn []TimesStat{*timeStat(\"cpu-total\", times)}, nil\n}\n\n// Returns only one InfoStat on DragonflyBSD.  The information regarding core\n// count, however is accurate and it is assumed that all InfoStat attributes\n// are the same across CPUs.\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(_ context.Context) ([]InfoStat, error) {\n\tconst dmesgBoot = \"/var/run/dmesg.boot\"\n\n\tc, err := parseDmesgBoot(dmesgBoot)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar u32 uint32\n\tif u32, err = unix.SysctlUint32(\"hw.clockrate\"); err != nil {\n\t\treturn nil, err\n\t}\n\tc.Mhz = float64(u32)\n\n\tvar num int\n\tvar buf string\n\tif buf, err = unix.Sysctl(\"hw.cpu_topology.tree\"); err != nil {\n\t\treturn nil, err\n\t}\n\tnum = strings.Count(buf, \"CHIP\")\n\tc.Cores = int32(strings.Count(string(buf), \"CORE\") / num)\n\n\tif c.ModelName, err = unix.Sysctl(\"hw.model\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := make([]InfoStat, num)\n\tfor i := 0; i < num; i++ {\n\t\tret[i] = c\n\t}\n\n\treturn ret, nil\n}\n\nfunc parseDmesgBoot(fileName string) (InfoStat, error) {\n\tc := InfoStat{}\n\tlines, err := common.ReadLines(fileName)\n\tif err != nil {\n\t\treturn c, fmt.Errorf(\"could not read %s: %w\", fileName, err)\n\t}\n\n\tfor _, line := range lines {\n\t\tif matches := cpuEnd.FindStringSubmatch(line); matches != nil {\n\t\t\tbreak\n\t\t} else if matches := originMatch.FindStringSubmatch(line); matches != nil {\n\t\t\tc.VendorID = matches[1]\n\t\t\tt, err := strconv.ParseInt(matches[2], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn c, fmt.Errorf(\"unable to parse DragonflyBSD CPU stepping information from %q: %w\", line, err)\n\t\t\t}\n\t\t\tc.Stepping = int32(t)\n\t\t} else if matches := featuresMatch.FindStringSubmatch(line); matches != nil {\n\t\t\tfor _, v := range strings.Split(matches[1], \",\") {\n\t\t\t\tc.Flags = append(c.Flags, strings.ToLower(v))\n\t\t\t}\n\t\t} else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil {\n\t\t\tfor _, v := range strings.Split(matches[1], \",\") {\n\t\t\t\tc.Flags = append(c.Flags, strings.ToLower(v))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn c, nil\n}\n\nfunc CountsWithContext(_ context.Context, _ bool) (int, error) {\n\treturn runtime.NumCPU(), nil\n}\n"
  },
  {
    "path": "cpu/cpu_dragonfly_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tIntr uint64\n\tIdle uint64\n}\n"
  },
  {
    "path": "cpu/cpu_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows && !dragonfly && !plan9 && !aix\n\npackage cpu\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {\n\treturn []TimesStat{}, common.ErrNotImplementedError\n}\n\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(ctx context.Context) ([]InfoStat, error) {\n\treturn []InfoStat{}, common.ErrNotImplementedError\n}\n\nfunc CountsWithContext(ctx context.Context, logical bool) (int, error) {\n\treturn runtime.NumCPU(), nil\n}\n"
  },
  {
    "path": "cpu/cpu_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"github.com/tklauser/go-sysconf\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar (\n\tClocksPerSec   = float64(128)\n\tcpuMatch       = regexp.MustCompile(`^CPU:`)\n\toriginMatch    = regexp.MustCompile(`Origin\\s*=\\s*\"(.+)\"\\s+Id\\s*=\\s*(.+)\\s+Family\\s*=\\s*(.+)\\s+Model\\s*=\\s*(.+)\\s+Stepping\\s*=\\s*(.+)`)\n\tfeaturesMatch  = regexp.MustCompile(`Features=.+<(.+)>`)\n\tfeaturesMatch2 = regexp.MustCompile(`Features2=[a-f\\dx]+<(.+)>`)\n\tcpuEnd         = regexp.MustCompile(`^Trying to mount root`)\n\tcpuCores       = regexp.MustCompile(`FreeBSD/SMP: (\\d*) package\\(s\\) x (\\d*) core\\(s\\)`)\n\tcpuTimesSize   int\n\temptyTimes     cpuTimes\n)\n\nfunc init() {\n\tclkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)\n\t// ignore errors\n\tif err == nil {\n\t\tClocksPerSec = float64(clkTck)\n\t}\n}\n\nfunc timeStat(name string, t *cpuTimes) *TimesStat {\n\treturn &TimesStat{\n\t\tUser:   float64(t.User) / ClocksPerSec,\n\t\tNice:   float64(t.Nice) / ClocksPerSec,\n\t\tSystem: float64(t.Sys) / ClocksPerSec,\n\t\tIdle:   float64(t.Idle) / ClocksPerSec,\n\t\tIrq:    float64(t.Intr) / ClocksPerSec,\n\t\tCPU:    name,\n\t}\n}\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {\n\tif percpu {\n\t\tbuf, err := unix.SysctlRaw(\"kern.cp_times\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// We can't do this in init due to the conflict with cpu.init()\n\t\tif cpuTimesSize == 0 {\n\t\t\tcpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())\n\t\t}\n\n\t\tncpus := len(buf) / cpuTimesSize\n\t\tret := make([]TimesStat, 0, ncpus)\n\t\tfor i := 0; i < ncpus; i++ {\n\t\t\ttimes := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))\n\t\t\tif *times == emptyTimes {\n\t\t\t\t// CPU not present\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret = append(ret, *timeStat(fmt.Sprintf(\"cpu%d\", len(ret)), times))\n\t\t}\n\t\treturn ret, nil\n\t}\n\n\tbuf, err := unix.SysctlRaw(\"kern.cp_time\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttimes := (*cpuTimes)(unsafe.Pointer(&buf[0]))\n\treturn []TimesStat{*timeStat(\"cpu-total\", times)}, nil\n}\n\n// Returns only one InfoStat on FreeBSD.  The information regarding core\n// count, however is accurate and it is assumed that all InfoStat attributes\n// are the same across CPUs.\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(_ context.Context) ([]InfoStat, error) {\n\tconst dmesgBoot = \"/var/run/dmesg.boot\"\n\n\tc, num, err := parseDmesgBoot(dmesgBoot)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar u32 uint32\n\tif u32, err = unix.SysctlUint32(\"hw.clockrate\"); err != nil {\n\t\treturn nil, err\n\t}\n\tc.Mhz = float64(u32)\n\n\tif u32, err = unix.SysctlUint32(\"hw.ncpu\"); err != nil {\n\t\treturn nil, err\n\t}\n\tc.Cores = int32(u32)\n\n\tif c.ModelName, err = unix.Sysctl(\"hw.model\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := make([]InfoStat, num)\n\tfor i := 0; i < num; i++ {\n\t\tret[i] = c\n\t}\n\n\treturn ret, nil\n}\n\nfunc parseDmesgBoot(fileName string) (InfoStat, int, error) {\n\tc := InfoStat{}\n\tlines, err := common.ReadLines(fileName)\n\tif err != nil {\n\t\treturn c, 0, fmt.Errorf(\"could not read %s: %w\", fileName, err)\n\t}\n\n\tcpuNum := 1 // default cpu num is 1\n\tfor _, line := range lines {\n\t\tif matches := cpuEnd.FindStringSubmatch(line); matches != nil {\n\t\t\tbreak\n\t\t} else if matches := originMatch.FindStringSubmatch(line); matches != nil {\n\t\t\tc.VendorID = matches[1]\n\t\t\tc.Family = matches[3]\n\t\t\tc.Model = matches[4]\n\t\t\tt, err := strconv.ParseInt(matches[5], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn c, 0, fmt.Errorf(\"unable to parse FreeBSD CPU stepping information from %q: %w\", line, err)\n\t\t\t}\n\t\t\tc.Stepping = int32(t)\n\t\t} else if matches := featuresMatch.FindStringSubmatch(line); matches != nil {\n\t\t\tfor _, v := range strings.Split(matches[1], \",\") {\n\t\t\t\tc.Flags = append(c.Flags, strings.ToLower(v))\n\t\t\t}\n\t\t} else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil {\n\t\t\tfor _, v := range strings.Split(matches[1], \",\") {\n\t\t\t\tc.Flags = append(c.Flags, strings.ToLower(v))\n\t\t\t}\n\t\t} else if matches := cpuCores.FindStringSubmatch(line); matches != nil {\n\t\t\tt, err := strconv.ParseInt(matches[1], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn c, 0, fmt.Errorf(\"unable to parse FreeBSD CPU Nums from %q: %w\", line, err)\n\t\t\t}\n\t\t\tcpuNum = int(t)\n\t\t\tt2, err := strconv.ParseInt(matches[2], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn c, 0, fmt.Errorf(\"unable to parse FreeBSD CPU cores from %q: %w\", line, err)\n\t\t\t}\n\t\t\tc.Cores = int32(t2)\n\t\t}\n\t}\n\n\treturn c, cpuNum, nil\n}\n\nfunc CountsWithContext(_ context.Context, _ bool) (int, error) {\n\treturn runtime.NumCPU(), nil\n}\n"
  },
  {
    "path": "cpu/cpu_freebsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint32\n\tNice uint32\n\tSys  uint32\n\tIntr uint32\n\tIdle uint32\n}\n"
  },
  {
    "path": "cpu/cpu_freebsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tIntr uint64\n\tIdle uint64\n}\n"
  },
  {
    "path": "cpu/cpu_freebsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint32\n\tNice uint32\n\tSys  uint32\n\tIntr uint32\n\tIdle uint32\n}\n"
  },
  {
    "path": "cpu/cpu_freebsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tIntr uint64\n\tIdle uint64\n}\n"
  },
  {
    "path": "cpu/cpu_freebsd_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\nimport (\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestParseDmesgBoot(t *testing.T) {\n\tif runtime.GOOS != \"freebsd\" {\n\t\tt.SkipNow()\n\t}\n\n\tcpuTests := []struct {\n\t\tfile   string\n\t\tcpuNum int\n\t\tcores  int32\n\t}{\n\t\t{\"1cpu_2core.txt\", 1, 2},\n\t\t{\"1cpu_4core.txt\", 1, 4},\n\t\t{\"2cpu_4core.txt\", 2, 4},\n\t}\n\tfor _, tt := range cpuTests {\n\t\tv, num, err := parseDmesgBoot(filepath.Join(\"testdata\", \"freebsd\", tt.file))\n\t\trequire.NoErrorf(t, err, \"parseDmesgBoot failed(%s), %v\", tt.file, err)\n\t\tassert.Equalf(t, num, tt.cpuNum, \"parseDmesgBoot wrong length(%s), %v\", tt.file, err)\n\t\tassert.Equalf(t, v.Cores, tt.cores, \"parseDmesgBoot wrong core(%s), %v\", tt.file, err)\n\t\tassert.Truef(t, common.StringsContains(v.Flags, \"fpu\"), \"parseDmesgBoot fail to parse features(%s), %v\", tt.file, err)\n\t}\n}\n"
  },
  {
    "path": "cpu/cpu_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage cpu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/tklauser/go-sysconf\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar ClocksPerSec = float64(100)\n\nvar armModelToModelName = map[uint64]string{\n\t0x810: \"ARM810\",\n\t0x920: \"ARM920\",\n\t0x922: \"ARM922\",\n\t0x926: \"ARM926\",\n\t0x940: \"ARM940\",\n\t0x946: \"ARM946\",\n\t0x966: \"ARM966\",\n\t0xa20: \"ARM1020\",\n\t0xa22: \"ARM1022\",\n\t0xa26: \"ARM1026\",\n\t0xb02: \"ARM11 MPCore\",\n\t0xb36: \"ARM1136\",\n\t0xb56: \"ARM1156\",\n\t0xb76: \"ARM1176\",\n\t0xc05: \"Cortex-A5\",\n\t0xc07: \"Cortex-A7\",\n\t0xc08: \"Cortex-A8\",\n\t0xc09: \"Cortex-A9\",\n\t0xc0d: \"Cortex-A17\",\n\t0xc0f: \"Cortex-A15\",\n\t0xc0e: \"Cortex-A17\",\n\t0xc14: \"Cortex-R4\",\n\t0xc15: \"Cortex-R5\",\n\t0xc17: \"Cortex-R7\",\n\t0xc18: \"Cortex-R8\",\n\t0xc20: \"Cortex-M0\",\n\t0xc21: \"Cortex-M1\",\n\t0xc23: \"Cortex-M3\",\n\t0xc24: \"Cortex-M4\",\n\t0xc27: \"Cortex-M7\",\n\t0xc60: \"Cortex-M0+\",\n\t0xd01: \"Cortex-A32\",\n\t0xd02: \"Cortex-A34\",\n\t0xd03: \"Cortex-A53\",\n\t0xd04: \"Cortex-A35\",\n\t0xd05: \"Cortex-A55\",\n\t0xd06: \"Cortex-A65\",\n\t0xd07: \"Cortex-A57\",\n\t0xd08: \"Cortex-A72\",\n\t0xd09: \"Cortex-A73\",\n\t0xd0a: \"Cortex-A75\",\n\t0xd0b: \"Cortex-A76\",\n\t0xd0c: \"Neoverse-N1\",\n\t0xd0d: \"Cortex-A77\",\n\t0xd0e: \"Cortex-A76AE\",\n\t0xd13: \"Cortex-R52\",\n\t0xd20: \"Cortex-M23\",\n\t0xd21: \"Cortex-M33\",\n\t0xd40: \"Neoverse-V1\",\n\t0xd41: \"Cortex-A78\",\n\t0xd42: \"Cortex-A78AE\",\n\t0xd43: \"Cortex-A65AE\",\n\t0xd44: \"Cortex-X1\",\n\t0xd46: \"Cortex-A510\",\n\t0xd47: \"Cortex-A710\",\n\t0xd48: \"Cortex-X2\",\n\t0xd49: \"Neoverse-N2\",\n\t0xd4a: \"Neoverse-E1\",\n\t0xd4b: \"Cortex-A78C\",\n\t0xd4c: \"Cortex-X1C\",\n\t0xd4d: \"Cortex-A715\",\n\t0xd4e: \"Cortex-X3\",\n\t0xd4f: \"Neoverse-V2\",\n\t0xd81: \"Cortex-A720\",\n\t0xd82: \"Cortex-X4\",\n\t0xd84: \"Neoverse-V3\",\n\t0xd85: \"Cortex-X925\",\n\t0xd87: \"Cortex-A725\",\n\t0xd8e: \"Neoverse-N3\",\n}\n\nfunc init() {\n\tclkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)\n\t// ignore errors\n\tif err == nil {\n\t\tClocksPerSec = float64(clkTck)\n\t}\n}\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {\n\tfilename := common.HostProcWithContext(ctx, \"stat\")\n\tlines := []string{}\n\tvar err error\n\tif percpu {\n\t\tstatlines, err := common.ReadLines(filename)\n\t\tif err != nil || len(statlines) < 2 {\n\t\t\treturn []TimesStat{}, nil\n\t\t}\n\t\tfor _, line := range statlines[1:] {\n\t\t\tif !strings.HasPrefix(line, \"cpu\") {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tlines = append(lines, line)\n\t\t}\n\t} else {\n\t\tlines, err = common.ReadLinesOffsetN(filename, 0, 1)\n\t\tif err != nil || len(lines) == 0 {\n\t\t\treturn []TimesStat{}, nil\n\t\t}\n\t}\n\n\tret := make([]TimesStat, 0, len(lines))\n\n\tfor _, line := range lines {\n\t\tct, err := parseStatLine(line)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, *ct)\n\n\t}\n\treturn ret, nil\n}\n\nfunc sysCPUPath(ctx context.Context, cpu int32, relPath string) string {\n\treturn common.HostSysWithContext(ctx, fmt.Sprintf(\"devices/system/cpu/cpu%d\", cpu), relPath)\n}\n\nfunc finishCPUInfo(ctx context.Context, c *InfoStat) {\n\tvar lines []string\n\tvar err error\n\tvar value float64\n\n\tif c.CoreID == \"\" {\n\t\tlines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, \"topology/core_id\"))\n\t\tif err == nil {\n\t\t\tc.CoreID = lines[0]\n\t\t}\n\t}\n\n\t// override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless\n\t// of the value from /proc/cpuinfo because we want to report the maximum\n\t// clock-speed of the CPU for c.Mhz, matching the behaviour of Windows\n\tlines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, \"cpufreq/cpuinfo_max_freq\"))\n\t// if we encounter errors below such as there are no cpuinfo_max_freq file,\n\t// we just ignore. so let Mhz is 0.\n\tif err != nil || len(lines) == 0 {\n\t\treturn\n\t}\n\tvalue, err = strconv.ParseFloat(lines[0], 64)\n\tif err != nil {\n\t\treturn\n\t}\n\tc.Mhz = value / 1000.0 // value is in kHz\n\tif c.Mhz > 9999 {\n\t\tc.Mhz /= 1000.0 // value in Hz\n\t}\n}\n\n// CPUInfo on linux will return 1 item per physical thread.\n//\n// CPUs have three levels of counting: sockets, cores, threads.\n// Cores with HyperThreading count as having 2 threads per core.\n// Sockets often come with many physical CPU cores.\n// For example a single socket board with two cores each with HT will\n// return 4 CPUInfoStat structs on Linux and the \"Cores\" field set to 1.\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(ctx context.Context) ([]InfoStat, error) {\n\tfilename := common.HostProcWithContext(ctx, \"cpuinfo\")\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not read %s: %w\", filename, err)\n\t}\n\n\tvar ret []InfoStat\n\tvar processorName string\n\n\tc := InfoStat{CPU: -1, Cores: 1}\n\tfor _, line := range lines {\n\t\tfields := strings.SplitN(line, \":\", 2)\n\t\tif len(fields) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tkey := strings.TrimSpace(fields[0])\n\t\tvalue := strings.TrimSpace(fields[1])\n\n\t\tswitch key {\n\t\tcase \"Processor\":\n\t\t\tprocessorName = value\n\t\tcase \"processor\", \"cpu number\":\n\t\t\tif c.CPU >= 0 {\n\t\t\t\tfinishCPUInfo(ctx, &c)\n\t\t\t\tret = append(ret, c)\n\t\t\t}\n\t\t\tc = InfoStat{Cores: 1, ModelName: processorName}\n\t\t\tt, err := strconv.ParseInt(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, err\n\t\t\t}\n\t\t\tc.CPU = int32(t)\n\t\tcase \"vendorId\", \"vendor_id\":\n\t\t\tc.VendorID = value\n\t\t\tif strings.Contains(value, \"S390\") {\n\t\t\t\tprocessorName = \"S390\"\n\t\t\t}\n\t\tcase \"mvendorid\":\n\t\t\tif !strings.HasPrefix(value, \"0x\") {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif v, err := strconv.ParseUint(value[2:], 16, 32); err == nil {\n\t\t\t\tswitch v {\n\t\t\t\tcase 0x31e:\n\t\t\t\t\tc.VendorID = \"Andes\"\n\t\t\t\tcase 0x029:\n\t\t\t\t\tc.VendorID = \"Microchip\"\n\t\t\t\tcase 0x127:\n\t\t\t\t\tc.VendorID = \"MIPS\"\n\t\t\t\tcase 0x489:\n\t\t\t\t\tc.VendorID = \"SiFive\"\n\t\t\t\tcase 0x5b7:\n\t\t\t\t\tc.VendorID = \"T-Head\"\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"CPU implementer\":\n\t\t\tif v, err := strconv.ParseUint(value, 0, 8); err == nil {\n\t\t\t\tswitch v {\n\t\t\t\tcase 0x41:\n\t\t\t\t\tc.VendorID = \"ARM\"\n\t\t\t\tcase 0x42:\n\t\t\t\t\tc.VendorID = \"Broadcom\"\n\t\t\t\tcase 0x43:\n\t\t\t\t\tc.VendorID = \"Cavium\"\n\t\t\t\tcase 0x44:\n\t\t\t\t\tc.VendorID = \"DEC\"\n\t\t\t\tcase 0x46:\n\t\t\t\t\tc.VendorID = \"Fujitsu\"\n\t\t\t\tcase 0x48:\n\t\t\t\t\tc.VendorID = \"HiSilicon\"\n\t\t\t\tcase 0x49:\n\t\t\t\t\tc.VendorID = \"Infineon\"\n\t\t\t\tcase 0x4d:\n\t\t\t\t\tc.VendorID = \"Motorola/Freescale\"\n\t\t\t\tcase 0x4e:\n\t\t\t\t\tc.VendorID = \"NVIDIA\"\n\t\t\t\tcase 0x50:\n\t\t\t\t\tc.VendorID = \"APM\"\n\t\t\t\tcase 0x51:\n\t\t\t\t\tc.VendorID = \"Qualcomm\"\n\t\t\t\tcase 0x56:\n\t\t\t\t\tc.VendorID = \"Marvell\"\n\t\t\t\tcase 0x61:\n\t\t\t\t\tc.VendorID = \"Apple\"\n\t\t\t\tcase 0x69:\n\t\t\t\t\tc.VendorID = \"Intel\"\n\t\t\t\tcase 0xc0:\n\t\t\t\t\tc.VendorID = \"Ampere\"\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"cpu family\", \"marchid\":\n\t\t\tc.Family = value\n\t\tcase \"model\", \"CPU part\", \"mimpid\":\n\t\t\tc.Model = value\n\t\t\t// if CPU is arm based, model name is found via model number. refer to: arch/arm64/kernel/cpuinfo.c\n\t\t\tif c.VendorID == \"ARM\" {\n\t\t\t\tif v, err := strconv.ParseUint(c.Model, 0, 16); err == nil {\n\t\t\t\t\tmodelName, exist := armModelToModelName[v]\n\t\t\t\t\tif exist {\n\t\t\t\t\t\tc.ModelName = modelName\n\t\t\t\t\t} else {\n\t\t\t\t\t\tc.ModelName = \"Undefined\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"Model Name\", \"model name\", \"cpu\", \"uarch\":\n\t\t\tc.ModelName = value\n\t\t\tif strings.Contains(value, \"POWER\") {\n\t\t\t\tc.Model = strings.Split(value, \" \")[0]\n\t\t\t\tc.Family = \"POWER\"\n\t\t\t\tc.VendorID = \"IBM\"\n\t\t\t}\n\t\tcase \"stepping\", \"revision\", \"CPU revision\":\n\t\t\tval := value\n\n\t\t\tif key == \"revision\" {\n\t\t\t\tval = strings.Split(value, \".\")[0]\n\t\t\t}\n\n\t\t\tif strings.EqualFold(val, \"unknown\") {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tt, err := strconv.ParseInt(val, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, err\n\t\t\t}\n\t\t\tc.Stepping = int32(t)\n\t\tcase \"cpu MHz\", \"clock\", \"cpu MHz dynamic\":\n\t\t\t// treat this as the fallback value, thus we ignore error\n\t\t\tif t, err := strconv.ParseFloat(strings.Replace(value, \"MHz\", \"\", 1), 64); err == nil {\n\t\t\t\tc.Mhz = t\n\t\t\t}\n\t\tcase \"cache size\":\n\t\t\tt, err := strconv.ParseInt(strings.Replace(value, \" KB\", \"\", 1), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, err\n\t\t\t}\n\t\t\tc.CacheSize = int32(t)\n\t\tcase \"physical id\", \"hart\":\n\t\t\tc.PhysicalID = value\n\t\tcase \"core id\":\n\t\t\tc.CoreID = value\n\t\tcase \"flags\", \"Features\":\n\t\t\tc.Flags = strings.FieldsFunc(value, func(r rune) bool {\n\t\t\t\treturn r == ',' || r == ' '\n\t\t\t})\n\t\tcase \"isa\", \"hart isa\":\n\t\t\tif len(c.Flags) != 0 || !strings.HasPrefix(value, \"rv64\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tc.Flags = riscvISAParse(value)\n\t\tcase \"microcode\":\n\t\t\tc.Microcode = value\n\t\t}\n\t}\n\tif c.CPU >= 0 {\n\t\tfinishCPUInfo(ctx, &c)\n\t\tret = append(ret, c)\n\t}\n\treturn ret, nil\n}\n\nfunc parseStatLine(line string) (*TimesStat, error) {\n\tfields := strings.Fields(line)\n\n\tif len(fields) < 8 {\n\t\treturn nil, errors.New(\"stat does not contain cpu info\")\n\t}\n\n\tif !strings.HasPrefix(fields[0], \"cpu\") {\n\t\treturn nil, errors.New(\"not contain cpu\")\n\t}\n\n\tcpu := fields[0]\n\tif cpu == \"cpu\" {\n\t\tcpu = \"cpu-total\"\n\t}\n\tuser, err := strconv.ParseFloat(fields[1], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnice, err := strconv.ParseFloat(fields[2], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsystem, err := strconv.ParseFloat(fields[3], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tidle, err := strconv.ParseFloat(fields[4], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tiowait, err := strconv.ParseFloat(fields[5], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tirq, err := strconv.ParseFloat(fields[6], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsoftirq, err := strconv.ParseFloat(fields[7], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tct := &TimesStat{\n\t\tCPU:     cpu,\n\t\tUser:    user / ClocksPerSec,\n\t\tNice:    nice / ClocksPerSec,\n\t\tSystem:  system / ClocksPerSec,\n\t\tIdle:    idle / ClocksPerSec,\n\t\tIowait:  iowait / ClocksPerSec,\n\t\tIrq:     irq / ClocksPerSec,\n\t\tSoftirq: softirq / ClocksPerSec,\n\t}\n\tif len(fields) > 8 { // Linux >= 2.6.11\n\t\tsteal, err := strconv.ParseFloat(fields[8], 64)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tct.Steal = steal / ClocksPerSec\n\t}\n\tif len(fields) > 9 { // Linux >= 2.6.24\n\t\tguest, err := strconv.ParseFloat(fields[9], 64)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tct.Guest = guest / ClocksPerSec\n\t}\n\tif len(fields) > 10 { // Linux >= 3.2.0\n\t\tguestNice, err := strconv.ParseFloat(fields[10], 64)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tct.GuestNice = guestNice / ClocksPerSec\n\t}\n\n\treturn ct, nil\n}\n\nfunc CountsWithContext(ctx context.Context, logical bool) (int, error) {\n\tif logical {\n\t\tret := 0\n\t\t// https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_pslinux.py#L599\n\t\tprocCpuinfo := common.HostProcWithContext(ctx, \"cpuinfo\")\n\t\tlines, err := common.ReadLines(procCpuinfo)\n\t\tif err == nil {\n\t\t\tfor _, line := range lines {\n\t\t\t\tline = strings.ToLower(line)\n\t\t\t\tif strings.HasPrefix(line, \"processor\") {\n\t\t\t\t\t_, err = strconv.ParseInt(strings.TrimSpace(line[strings.IndexByte(line, ':')+1:]), 10, 32)\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tret++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif ret == 0 {\n\t\t\tprocStat := common.HostProcWithContext(ctx, \"stat\")\n\t\t\tlines, err = common.ReadLines(procStat)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tfor _, line := range lines {\n\t\t\t\tif len(line) >= 4 && strings.HasPrefix(line, \"cpu\") && '0' <= line[3] && line[3] <= '9' { // `^cpu\\d` regexp matching\n\t\t\t\t\tret++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn ret, nil\n\t}\n\t// physical cores\n\t// https://github.com/giampaolo/psutil/blob/8415355c8badc9c94418b19bdf26e622f06f0cce/psutil/_pslinux.py#L615-L628\n\tthreadSiblingsLists := make(map[string]bool)\n\t// These 2 files are the same but */core_cpus_list is newer while */thread_siblings_list is deprecated and may disappear in the future.\n\t// https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst\n\t// https://github.com/giampaolo/psutil/pull/1727#issuecomment-707624964\n\t// https://lkml.org/lkml/2019/2/26/41\n\tfor _, glob := range []string{\"devices/system/cpu/cpu[0-9]*/topology/core_cpus_list\", \"devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list\"} {\n\t\tif files, err := filepath.Glob(common.HostSysWithContext(ctx, glob)); err == nil {\n\t\t\tfor _, file := range files {\n\t\t\t\tlines, err := common.ReadLines(file)\n\t\t\t\tif err != nil || len(lines) != 1 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tthreadSiblingsLists[lines[0]] = true\n\t\t\t}\n\t\t\tret := len(threadSiblingsLists)\n\t\t\tif ret != 0 {\n\t\t\t\treturn ret, nil\n\t\t\t}\n\t\t}\n\t}\n\t// https://github.com/giampaolo/psutil/blob/122174a10b75c9beebe15f6c07dcf3afbe3b120d/psutil/_pslinux.py#L631-L652\n\tfilename := common.HostProcWithContext(ctx, \"cpuinfo\")\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tmapping := make(map[int]int)\n\tcurrentInfo := make(map[string]int)\n\tfor _, line := range lines {\n\t\tline = strings.ToLower(strings.TrimSpace(line))\n\t\tif line == \"\" {\n\t\t\t// new section\n\t\t\tid, okID := currentInfo[\"physical id\"]\n\t\t\tcores, okCores := currentInfo[\"cpu cores\"]\n\t\t\tif okID && okCores {\n\t\t\t\tmapping[id] = cores\n\t\t\t}\n\t\t\tcurrentInfo = make(map[string]int)\n\t\t\tcontinue\n\t\t}\n\t\tfields := strings.SplitN(line, \":\", 2)\n\t\tif len(fields) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tfields[0] = strings.TrimSpace(fields[0])\n\t\tif fields[0] == \"physical id\" || fields[0] == \"cpu cores\" {\n\t\t\tval, err := strconv.ParseInt(strings.TrimSpace(fields[1]), 10, 32)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcurrentInfo[fields[0]] = int(val)\n\t\t}\n\t}\n\tret := 0\n\tfor _, v := range mapping {\n\t\tret += v\n\t}\n\treturn ret, nil\n}\n\nfunc riscvISAParse(s string) []string {\n\text := strings.Split(s, \"_\")\n\tif len(ext[0]) <= 4 {\n\t\treturn nil\n\t}\n\t// the base extensions must \"rv64\" prefix\n\tbase := strings.Split(ext[0][4:], \"\")\n\treturn append(base, ext[1:]...)\n}\n"
  },
  {
    "path": "cpu/cpu_linux_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestTimesEmpty(t *testing.T) {\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux/times_empty\")\n\t_, err := Times(true)\n\trequire.NoErrorf(t, err, \"Times(true) failed\")\n\t_, err = Times(false)\n\tassert.NoErrorf(t, err, \"Times(false) failed\")\n}\n\nfunc TestParseStatLine_424(t *testing.T) {\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux/424/proc\")\n\t{\n\t\tl, err := Times(true)\n\t\tif err != nil || len(l) == 0 {\n\t\t\tt.Error(\"Times(true) failed\")\n\t\t}\n\t\tt.Logf(\"Times(true): %#v\", l)\n\t}\n\t{\n\t\tl, err := Times(false)\n\t\tif err != nil || len(l) == 0 {\n\t\t\tt.Error(\"Times(false) failed\")\n\t\t}\n\t\tt.Logf(\"Times(false): %#v\", l)\n\t}\n}\n\nfunc TestCountsAgainstLscpu(t *testing.T) {\n\tcmd := exec.CommandContext(context.Background(), \"lscpu\")\n\tcmd.Env = []string{\"LC_ALL=C\"}\n\tout, err := cmd.Output()\n\tif err != nil {\n\t\tif errors.Is(err, exec.ErrNotFound) {\n\t\t\tt.Skip(\"no lscpu to compare with\")\n\t\t}\n\t\tt.Errorf(\"error executing lscpu: %v\", err)\n\t}\n\tvar threadsPerCore, coresPerSocket, sockets, books, drawers int\n\tbooks = 1\n\tdrawers = 1\n\tlines := strings.Split(string(out), \"\\n\")\n\tfor _, line := range lines {\n\t\tfields := strings.Split(line, \":\")\n\t\tif len(fields) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tswitch fields[0] {\n\t\tcase \"Thread(s) per core\":\n\t\t\tthreadsPerCore, _ = strconv.Atoi(strings.TrimSpace(fields[1]))\n\t\tcase \"Core(s) per socket\":\n\t\t\tcoresPerSocket, _ = strconv.Atoi(strings.TrimSpace(fields[1]))\n\t\tcase \"Socket(s)\", \"Socket(s) per book\":\n\t\t\tsockets, _ = strconv.Atoi(strings.TrimSpace(fields[1]))\n\t\tcase \"Book(s) per drawer\":\n\t\t\tbooks, _ = strconv.Atoi(strings.TrimSpace(fields[1]))\n\t\tcase \"Drawer(s)\":\n\t\t\tdrawers, _ = strconv.Atoi(strings.TrimSpace(fields[1]))\n\t\t}\n\t}\n\tif threadsPerCore == 0 || coresPerSocket == 0 || sockets == 0 {\n\t\tt.Errorf(\"missing info from lscpu: threadsPerCore=%d coresPerSocket=%d sockets=%d\", threadsPerCore, coresPerSocket, sockets)\n\t}\n\texpectedPhysical := coresPerSocket * sockets * books * drawers\n\texpectedLogical := expectedPhysical * threadsPerCore\n\tphysical, err := Counts(false)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tlogical, err := Counts(true)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.Equalf(t, expectedPhysical, physical, \"expected %v, got %v\", expectedPhysical, physical)\n\tassert.Equalf(t, expectedLogical, logical, \"expected %v, got %v\", expectedLogical, logical)\n}\n\nfunc TestCountsLogicalAndroid_1037(t *testing.T) { // https://github.com/shirou/gopsutil/issues/1037\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux/1037/proc\")\n\n\tcount, err := Counts(true)\n\trequire.NoError(t, err)\n\texpected := 8\n\tassert.Equalf(t, expected, count, \"expected %v, got %v\", expected, count)\n}\n\nfunc TestCPUInfoModelNameWithColon_1958(t *testing.T) { // https://github.com/shirou/gopsutil/issues/1958\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux/1958/proc\")\n\n\tinfo, err := Info()\n\trequire.NoError(t, err)\n\trequire.Len(t, info, 1)\n\n\texpected := \"Hygon C86-4G (OPN:5435)\"\n\tassert.Equalf(t, expected, info[0].ModelName, \"expected %v, got %v\", expected, info[0].ModelName)\n}\n"
  },
  {
    "path": "cpu/cpu_netbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build netbsd\n\npackage cpu\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"unsafe\"\n\n\t\"github.com/tklauser/go-sysconf\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst (\n\t// sys/sysctl.h\n\tctlKern    = 1  // \"high kernel\": proc, limits\n\tctlHw      = 6  // CTL_HW\n\tkernCpTime = 51 // KERN_CPTIME\n)\n\nvar ClocksPerSec = float64(100)\n\nfunc init() {\n\tclkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)\n\t// ignore errors\n\tif err == nil {\n\t\tClocksPerSec = float64(clkTck)\n\t}\n}\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {\n\tret := make([]TimesStat, 0)\n\tif !percpu {\n\t\tmib := []int32{ctlKern, kernCpTime}\n\t\tbuf, _, err := common.CallSyscall(mib)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\ttimes := (*cpuTimes)(unsafe.Pointer(&buf[0]))\n\t\tret = append(ret, TimesStat{\n\t\t\tCPU:    \"cpu-total\",\n\t\t\tUser:   float64(times.User),\n\t\t\tNice:   float64(times.Nice),\n\t\t\tSystem: float64(times.Sys),\n\t\t\tIdle:   float64(times.Idle),\n\t\t\tIrq:    float64(times.Intr),\n\t\t})\n\t\treturn ret, nil\n\t}\n\n\tncpu, err := unix.SysctlUint32(\"hw.ncpu\")\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tvar i uint32\n\tfor i = 0; i < ncpu; i++ {\n\t\tmib := []int32{ctlKern, kernCpTime, int32(i)}\n\t\tbuf, _, err := common.CallSyscall(mib)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\n\t\tstats := (*cpuTimes)(unsafe.Pointer(&buf[0]))\n\t\tret = append(ret, TimesStat{\n\t\t\tCPU:    fmt.Sprintf(\"cpu%d\", i),\n\t\t\tUser:   float64(stats.User),\n\t\t\tNice:   float64(stats.Nice),\n\t\t\tSystem: float64(stats.Sys),\n\t\t\tIdle:   float64(stats.Idle),\n\t\t\tIrq:    float64(stats.Intr),\n\t\t})\n\t}\n\n\treturn ret, nil\n}\n\n// Returns only one (minimal) CPUInfoStat on NetBSD\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(_ context.Context) ([]InfoStat, error) {\n\tvar ret []InfoStat\n\tvar err error\n\n\tc := InfoStat{}\n\n\tmhz, err := unix.Sysctl(\"machdep.dmi.processor-frequency\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t_, err = fmt.Sscanf(mhz, \"%f\", &c.Mhz)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tncpu, err := unix.SysctlUint32(\"hw.ncpuonline\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.Cores = int32(ncpu)\n\n\tif c.ModelName, err = unix.Sysctl(\"machdep.dmi.processor-version\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn append(ret, c), nil\n}\n\nfunc CountsWithContext(_ context.Context, _ bool) (int, error) {\n\treturn runtime.NumCPU(), nil\n}\n"
  },
  {
    "path": "cpu/cpu_netbsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tIntr uint64\n\tIdle uint64\n}\n"
  },
  {
    "path": "cpu/cpu_netbsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint32\n\tNice uint32\n\tSys  uint32\n\tIntr uint32\n\tIdle uint32\n}\n"
  },
  {
    "path": "cpu/cpu_netbsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tIntr uint64\n\tIdle uint64\n}\n"
  },
  {
    "path": "cpu/cpu_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage cpu\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"unsafe\"\n\n\t\"github.com/tklauser/go-sysconf\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst (\n\t// sys/sched.h\n\tcpuOnline = 0x0001 // CPUSTATS_ONLINE\n\n\t// sys/sysctl.h\n\tctlKern      = 1  // \"high kernel\": proc, limits\n\tctlHw        = 6  // CTL_HW\n\tsmt          = 24 // HW_SMT\n\tkernCpTime   = 40 // KERN_CPTIME\n\tkernCPUStats = 85 // KERN_CPUSTATS\n)\n\nvar ClocksPerSec = float64(128)\n\ntype cpuStats struct {\n\t// cs_time[CPUSTATES]\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tSpin uint64\n\tIntr uint64\n\tIdle uint64\n\n\t// cs_flags\n\tFlags uint64\n}\n\nfunc init() {\n\tclkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)\n\t// ignore errors\n\tif err == nil {\n\t\tClocksPerSec = float64(clkTck)\n\t}\n}\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {\n\tret := make([]TimesStat, 0)\n\tif !percpu {\n\t\tmib := []int32{ctlKern, kernCpTime}\n\t\tbuf, _, err := common.CallSyscall(mib)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\ttimes := (*cpuTimes)(unsafe.Pointer(&buf[0]))\n\t\tret = append(ret, TimesStat{\n\t\t\tCPU:    \"cpu-total\",\n\t\t\tUser:   float64(times.User) / ClocksPerSec,\n\t\t\tNice:   float64(times.Nice) / ClocksPerSec,\n\t\t\tSystem: float64(times.Sys) / ClocksPerSec,\n\t\t\tIdle:   float64(times.Idle) / ClocksPerSec,\n\t\t\tIrq:    float64(times.Intr) / ClocksPerSec,\n\t\t})\n\t\treturn ret, nil\n\t}\n\n\tncpu, err := unix.SysctlUint32(\"hw.ncpu\")\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tvar i uint32\n\tfor i = 0; i < ncpu; i++ {\n\t\tmib := []int32{ctlKern, kernCPUStats, int32(i)}\n\t\tbuf, _, err := common.CallSyscall(mib)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\n\t\tstats := (*cpuStats)(unsafe.Pointer(&buf[0]))\n\t\tif (stats.Flags & cpuOnline) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, TimesStat{\n\t\t\tCPU:    fmt.Sprintf(\"cpu%d\", i),\n\t\t\tUser:   float64(stats.User) / ClocksPerSec,\n\t\t\tNice:   float64(stats.Nice) / ClocksPerSec,\n\t\t\tSystem: float64(stats.Sys) / ClocksPerSec,\n\t\t\tIdle:   float64(stats.Idle) / ClocksPerSec,\n\t\t\tIrq:    float64(stats.Intr) / ClocksPerSec,\n\t\t})\n\t}\n\n\treturn ret, nil\n}\n\n// Returns only one (minimal) CPUInfoStat on OpenBSD\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(_ context.Context) ([]InfoStat, error) {\n\tvar ret []InfoStat\n\tvar err error\n\n\tc := InfoStat{}\n\n\tmhz, err := unix.SysctlUint32(\"hw.cpuspeed\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.Mhz = float64(mhz)\n\n\tncpu, err := unix.SysctlUint32(\"hw.ncpuonline\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.Cores = int32(ncpu)\n\n\tif c.ModelName, err = unix.Sysctl(\"hw.model\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn append(ret, c), nil\n}\n\nfunc CountsWithContext(_ context.Context, _ bool) (int, error) {\n\treturn runtime.NumCPU(), nil\n}\n"
  },
  {
    "path": "cpu/cpu_openbsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint32\n\tNice uint32\n\tSys  uint32\n\tSpin uint32\n\tIntr uint32\n\tIdle uint32\n}\n"
  },
  {
    "path": "cpu/cpu_openbsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tSpin uint64\n\tIntr uint64\n\tIdle uint64\n}\n"
  },
  {
    "path": "cpu/cpu_openbsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint32\n\tNice uint32\n\tSys  uint32\n\tSpin uint32\n\tIntr uint32\n\tIdle uint32\n}\n"
  },
  {
    "path": "cpu/cpu_openbsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tSpin uint64\n\tIntr uint64\n\tIdle uint64\n}\n"
  },
  {
    "path": "cpu/cpu_openbsd_riscv64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\ntype cpuTimes struct {\n\tUser uint64\n\tNice uint64\n\tSys  uint64\n\tSpin uint64\n\tIntr uint64\n\tIdle uint64\n}\n"
  },
  {
    "path": "cpu/cpu_plan9.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build plan9\n\npackage cpu\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"runtime\"\n\n\tstats \"github.com/lufia/plan9stats\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(ctx context.Context, _ bool) ([]TimesStat, error) {\n\t// BUG: percpu flag is not supported yet.\n\troot := os.Getenv(\"HOST_ROOT\")\n\tc, err := stats.ReadCPUType(ctx, stats.WithRootDir(root))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ts, err := stats.ReadCPUStats(ctx, stats.WithRootDir(root))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []TimesStat{\n\t\t{\n\t\t\tCPU:    c.Name,\n\t\t\tUser:   s.User.Seconds(),\n\t\t\tSystem: s.Sys.Seconds(),\n\t\t\tIdle:   s.Idle.Seconds(),\n\t\t},\n\t}, nil\n}\n\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(_ context.Context) ([]InfoStat, error) {\n\treturn []InfoStat{}, common.ErrNotImplementedError\n}\n\nfunc CountsWithContext(_ context.Context, _ bool) (int, error) {\n\treturn runtime.NumCPU(), nil\n}\n"
  },
  {
    "path": "cpu/cpu_plan9_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build plan9\n\npackage cpu\n\nimport (\n\t\"errors\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/google/go-cmp/cmp/cmpopts\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar timesTests = []struct {\n\tmockedRootFS string\n\tstats        []TimesStat\n}{\n\t{\n\t\t\"2cores\",\n\t\t[]TimesStat{\n\t\t\t{\n\t\t\t\tCPU:    \"Core i7/Xeon\",\n\t\t\t\tUser:   2780.0 / 1000.0,\n\t\t\t\tSystem: 30020.0 / 1000.0,\n\t\t\t\tIdle:   (1412961713341830*2)/1000000000.0 - 2.78 - 30.02,\n\t\t\t},\n\t\t},\n\t},\n}\n\nfunc TestTimesPlan9(t *testing.T) {\n\tfor _, tt := range timesTests {\n\t\tt.Run(tt.mockedRootFS, func(t *testing.T) {\n\t\t\tt.Setenv(\"HOST_ROOT\", filepath.Join(\"testdata\", \"plan9\", tt.mockedRootFS))\n\t\t\tstats, err := Times(false)\n\t\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\t\tt.Skip(\"not implemented\")\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\teps := cmpopts.EquateApprox(0, 0.00000001)\n\t\t\tassert.Truef(t, cmp.Equal(stats, tt.stats, eps), \"got: %+v\\nwant: %+v\", stats, tt.stats)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "cpu/cpu_solaris.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/tklauser/go-sysconf\"\n)\n\nvar ClocksPerSec = float64(128)\n\nfunc init() {\n\tclkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)\n\t// ignore errors\n\tif err == nil {\n\t\tClocksPerSec = float64(clkTck)\n\t}\n}\n\n// sum all values in a float64 map with float64 keys\nfunc msum(x map[float64]float64) float64 {\n\ttotal := 0.0\n\tfor _, y := range x {\n\t\ttotal += y\n\t}\n\treturn total\n}\n\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nvar kstatSplit = regexp.MustCompile(`[:\\s]+`)\n\nfunc TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {\n\tkstatSysOut, err := invoke.CommandWithContext(ctx, \"kstat\", \"-p\", \"cpu_stat:*:*:/^idle$|^user$|^kernel$|^iowait$|^swap$/\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot execute kstat: %w\", err)\n\t}\n\tcpu := make(map[float64]float64)\n\tidle := make(map[float64]float64)\n\tuser := make(map[float64]float64)\n\tkern := make(map[float64]float64)\n\tiowt := make(map[float64]float64)\n\t// swap := make(map[float64]float64)\n\tfor _, line := range strings.Split(string(kstatSysOut), \"\\n\") {\n\t\tfields := kstatSplit.Split(line, -1)\n\t\tif fields[0] != \"cpu_stat\" {\n\t\t\tcontinue\n\t\t}\n\t\tcpuNumber, err := strconv.ParseFloat(fields[1], 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"cannot parse cpu number: %w\", err)\n\t\t}\n\t\tcpu[cpuNumber] = cpuNumber\n\t\tswitch fields[3] {\n\t\tcase \"idle\":\n\t\t\tidle[cpuNumber], err = strconv.ParseFloat(fields[4], 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse idle: %w\", err)\n\t\t\t}\n\t\tcase \"user\":\n\t\t\tuser[cpuNumber], err = strconv.ParseFloat(fields[4], 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse user: %w\", err)\n\t\t\t}\n\t\tcase \"kernel\":\n\t\t\tkern[cpuNumber], err = strconv.ParseFloat(fields[4], 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse kernel: %w\", err)\n\t\t\t}\n\t\tcase \"iowait\":\n\t\t\tiowt[cpuNumber], err = strconv.ParseFloat(fields[4], 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse iowait: %w\", err)\n\t\t\t}\n\t\t\t// not sure how this translates, don't report, add to kernel, something else?\n\t\t\t/*case \"swap\":\n\t\t\tswap[cpuNumber], err = strconv.ParseFloat(fields[4], 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse swap: %s\", err)\n\t\t\t} */\n\t\t}\n\t}\n\tret := make([]TimesStat, 0, len(cpu))\n\tif percpu {\n\t\tfor _, c := range cpu {\n\t\t\tct := &TimesStat{\n\t\t\t\tCPU:    fmt.Sprintf(\"cpu%d\", int(cpu[c])),\n\t\t\t\tIdle:   idle[c] / ClocksPerSec,\n\t\t\t\tUser:   user[c] / ClocksPerSec,\n\t\t\t\tSystem: kern[c] / ClocksPerSec,\n\t\t\t\tIowait: iowt[c] / ClocksPerSec,\n\t\t\t}\n\t\t\tret = append(ret, *ct)\n\t\t}\n\t} else {\n\t\tct := &TimesStat{\n\t\t\tCPU:    \"cpu-total\",\n\t\t\tIdle:   msum(idle) / ClocksPerSec,\n\t\t\tUser:   msum(user) / ClocksPerSec,\n\t\t\tSystem: msum(kern) / ClocksPerSec,\n\t\t\tIowait: msum(iowt) / ClocksPerSec,\n\t\t}\n\t\tret = append(ret, *ct)\n\t}\n\treturn ret, nil\n}\n\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(ctx context.Context) ([]InfoStat, error) {\n\tpsrInfoOut, err := invoke.CommandWithContext(ctx, \"psrinfo\", \"-p\", \"-v\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot execute psrinfo: %w\", err)\n\t}\n\n\tprocs, err := parseProcessorInfo(string(psrInfoOut))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing psrinfo output: %w\", err)\n\t}\n\n\tisaInfoOut, err := invoke.CommandWithContext(ctx, \"isainfo\", \"-b\", \"-v\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot execute isainfo: %w\", err)\n\t}\n\n\tflags, err := parseISAInfo(string(isaInfoOut))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing isainfo output: %w\", err)\n\t}\n\n\tresult := make([]InfoStat, 0, len(flags))\n\tfor i := range procs {\n\t\tprocWithFlags := procs[i]\n\t\tprocWithFlags.Flags = flags\n\t\tresult = append(result, procWithFlags)\n\t}\n\n\treturn result, nil\n}\n\nvar flagsMatch = regexp.MustCompile(`[\\w.]+`)\n\nfunc parseISAInfo(cmdOutput string) ([]string, error) {\n\twords := flagsMatch.FindAllString(cmdOutput, -1)\n\n\t// Sanity check the output\n\tif len(words) < 4 || words[1] != \"bit\" || words[3] != \"applications\" {\n\t\treturn nil, errors.New(\"attempted to parse invalid isainfo output\")\n\t}\n\n\tflags := words[4:]\n\tsort.Strings(flags)\n\n\treturn flags, nil\n}\n\nvar 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]*(.*)`)\n\nconst (\n\tpsrNumCoresOffset   = 1\n\tpsrNumCoresHTOffset = 3\n\tpsrNumHTOffset      = 4\n\tpsrVendorIDOffset   = 5\n\tpsrFamilyOffset     = 7\n\tpsrModelOffset      = 8\n\tpsrStepOffset       = 9\n\tpsrClockOffset      = 10\n\tpsrModelNameOffset  = 11\n)\n\nfunc parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {\n\tmatches := psrInfoMatch.FindAllStringSubmatch(cmdOutput, -1)\n\n\tvar infoStatCount int32\n\tresult := make([]InfoStat, 0, len(matches))\n\tfor physicalIndex, physicalCPU := range matches {\n\t\tvar step int32\n\t\tvar clock float64\n\n\t\tif physicalCPU[psrStepOffset] != \"\" {\n\t\t\tstepParsed, err := strconv.ParseInt(physicalCPU[psrStepOffset], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse value %q for step as 32-bit integer: %w\", physicalCPU[9], err)\n\t\t\t}\n\t\t\tstep = int32(stepParsed)\n\t\t}\n\n\t\tif physicalCPU[psrClockOffset] != \"\" {\n\t\t\tclockParsed, err := strconv.ParseInt(physicalCPU[psrClockOffset], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse value %q for clock as 32-bit integer: %w\", physicalCPU[10], err)\n\t\t\t}\n\t\t\tclock = float64(clockParsed)\n\t\t}\n\n\t\tvar err error\n\t\tvar numCores int64\n\t\tvar numHT int64\n\t\tswitch {\n\t\tcase physicalCPU[psrNumCoresOffset] != \"\":\n\t\t\tnumCores, err = strconv.ParseInt(physicalCPU[psrNumCoresOffset], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse value %q for core count as 32-bit integer: %w\", physicalCPU[1], err)\n\t\t\t}\n\n\t\t\tfor i := 0; i < int(numCores); i++ {\n\t\t\t\tresult = append(result, InfoStat{\n\t\t\t\t\tCPU:        infoStatCount,\n\t\t\t\t\tPhysicalID: strconv.Itoa(physicalIndex),\n\t\t\t\t\tCoreID:     strconv.Itoa(i),\n\t\t\t\t\tCores:      1,\n\t\t\t\t\tVendorID:   physicalCPU[psrVendorIDOffset],\n\t\t\t\t\tModelName:  physicalCPU[psrModelNameOffset],\n\t\t\t\t\tFamily:     physicalCPU[psrFamilyOffset],\n\t\t\t\t\tModel:      physicalCPU[psrModelOffset],\n\t\t\t\t\tStepping:   step,\n\t\t\t\t\tMhz:        clock,\n\t\t\t\t})\n\t\t\t\tinfoStatCount++\n\t\t\t}\n\t\tcase physicalCPU[psrNumCoresHTOffset] != \"\":\n\t\t\tnumCores, err = strconv.ParseInt(physicalCPU[psrNumCoresHTOffset], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse value %q for core count as 32-bit integer: %w\", physicalCPU[3], err)\n\t\t\t}\n\n\t\t\tnumHT, err = strconv.ParseInt(physicalCPU[psrNumHTOffset], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse value %q for hyperthread count as 32-bit integer: %w\", physicalCPU[4], err)\n\t\t\t}\n\n\t\t\tfor i := 0; i < int(numCores); i++ {\n\t\t\t\tresult = append(result, InfoStat{\n\t\t\t\t\tCPU:        infoStatCount,\n\t\t\t\t\tPhysicalID: strconv.Itoa(physicalIndex),\n\t\t\t\t\tCoreID:     strconv.Itoa(i),\n\t\t\t\t\tCores:      int32(numHT) / int32(numCores),\n\t\t\t\t\tVendorID:   physicalCPU[psrVendorIDOffset],\n\t\t\t\t\tModelName:  physicalCPU[psrModelNameOffset],\n\t\t\t\t\tFamily:     physicalCPU[psrFamilyOffset],\n\t\t\t\t\tModel:      physicalCPU[psrModelOffset],\n\t\t\t\t\tStepping:   step,\n\t\t\t\t\tMhz:        clock,\n\t\t\t\t})\n\t\t\t\tinfoStatCount++\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, errors.New(\"values for cores with and without hyperthreading are both set\")\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc CountsWithContext(_ context.Context, _ bool) (int, error) {\n\treturn runtime.NumCPU(), nil\n}\n"
  },
  {
    "path": "cpu/cpu_solaris_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"sort\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestParseISAInfo(t *testing.T) {\n\tcases := []struct {\n\t\tfilename string\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\t\"1cpu_1core_isainfo.txt\",\n\t\t\t[]string{\n\t\t\t\t\"rdseed\", \"adx\", \"avx2\", \"fma\", \"bmi2\", \"bmi1\", \"rdrand\", \"f16c\", \"vmx\",\n\t\t\t\t\"avx\", \"xsave\", \"pclmulqdq\", \"aes\", \"movbe\", \"sse4.2\", \"sse4.1\", \"ssse3\", \"popcnt\",\n\t\t\t\t\"tscp\", \"cx16\", \"sse3\", \"sse2\", \"sse\", \"fxsr\", \"mmx\", \"cmov\", \"amd_sysc\", \"cx8\",\n\t\t\t\t\"tsc\", \"fpu\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"2cpu_1core_isainfo.txt\",\n\t\t\t[]string{\n\t\t\t\t\"rdseed\", \"adx\", \"avx2\", \"fma\", \"bmi2\", \"bmi1\", \"rdrand\", \"f16c\", \"vmx\",\n\t\t\t\t\"avx\", \"xsave\", \"pclmulqdq\", \"aes\", \"movbe\", \"sse4.2\", \"sse4.1\", \"ssse3\", \"popcnt\",\n\t\t\t\t\"tscp\", \"cx16\", \"sse3\", \"sse2\", \"sse\", \"fxsr\", \"mmx\", \"cmov\", \"amd_sysc\", \"cx8\",\n\t\t\t\t\"tsc\", \"fpu\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"2cpu_8core_isainfo.txt\",\n\t\t\t[]string{\n\t\t\t\t\"vmx\", \"avx\", \"xsave\", \"pclmulqdq\", \"aes\", \"sse4.2\", \"sse4.1\", \"ssse3\", \"popcnt\",\n\t\t\t\t\"tscp\", \"cx16\", \"sse3\", \"sse2\", \"sse\", \"fxsr\", \"mmx\", \"cmov\", \"amd_sysc\", \"cx8\",\n\t\t\t\t\"tsc\", \"fpu\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"2cpu_12core_isainfo.txt\",\n\t\t\t[]string{\n\t\t\t\t\"amd_svm\", \"amd_lzcnt\", \"popcnt\", \"amd_sse4a\", \"tscp\", \"ahf\", \"cx16\", \"sse3\", \"sse2\",\n\t\t\t\t\"sse\", \"fxsr\", \"amd_3dnowx\", \"amd_3dnow\", \"amd_mmx\", \"mmx\", \"cmov\", \"amd_sysc\", \"cx8\", \"tsc\", \"fpu\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tcontent, err := os.ReadFile(filepath.Join(\"testdata\", \"solaris\", tc.filename))\n\t\trequire.NoErrorf(t, err, \"cannot read test case: %s\", err)\n\n\t\tsort.Strings(tc.expected)\n\n\t\tflags, err := parseISAInfo(string(content))\n\t\trequire.NoErrorf(t, err, \"parseISAInfo: %s\", err)\n\n\t\trequire.Truef(t, reflect.DeepEqual(tc.expected, flags), \"Bad flags\\nExpected: %v\\n   Actual: %v\", tc.expected, flags)\n\t}\n}\n\nfunc TestParseProcessorInfo(t *testing.T) {\n\tcases := []struct {\n\t\tfilename string\n\t\texpected []InfoStat\n\t}{\n\t\t{\n\t\t\t\"1cpu_1core_psrinfo.txt\",\n\t\t\t[]InfoStat{\n\t\t\t\t{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},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"2cpu_1core_psrinfo.txt\",\n\t\t\t[]InfoStat{\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"2cpu_8core_psrinfo.txt\",\n\t\t\t[]InfoStat{\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"2cpu_12core_psrinfo.txt\",\n\t\t\t[]InfoStat{\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t\t{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},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tcontent, err := os.ReadFile(filepath.Join(\"testdata\", \"solaris\", tc.filename))\n\t\trequire.NoErrorf(t, err, \"cannot read test case: %s\", err)\n\n\t\tcpus, err := parseProcessorInfo(string(content))\n\t\trequire.NoErrorf(t, err, \"cannot parse processor info: %s\", err)\n\n\t\trequire.Truef(t, reflect.DeepEqual(tc.expected, cpus), \"Bad Processor Info\\nExpected: %v\\n   Actual: %v\", tc.expected, cpus)\n\t}\n}\n"
  },
  {
    "path": "cpu/cpu_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage cpu\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestTimes(t *testing.T) {\n\tv, err := Times(false)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, v, \"could not get CPUs: %s\", err)\n\tempty := TimesStat{}\n\tfor _, vv := range v {\n\t\tassert.NotEqualf(t, vv, empty, \"could not get CPU User: %v\", vv)\n\t}\n\n\t// test sum of per cpu stats is within margin of error for cpu total stats\n\tcpuTotal, err := Times(false)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, cpuTotal, \"could not get CPUs: %s\", err)\n\tperCPU, err := Times(true)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, perCPU, \"could not get CPUs: %s\", err)\n\tvar perCPUUserTimeSum float64\n\tvar perCPUSystemTimeSum float64\n\tvar perCPUIdleTimeSum float64\n\tfor _, pc := range perCPU {\n\t\tperCPUUserTimeSum += pc.User\n\t\tperCPUSystemTimeSum += pc.System\n\t\tperCPUIdleTimeSum += pc.Idle\n\t}\n\tmargin := 2.0\n\tt.Log(cpuTotal[0])\n\n\tif cpuTotal[0].User == 0 && cpuTotal[0].System == 0 && cpuTotal[0].Idle == 0 {\n\t\tt.Error(\"could not get cpu values\")\n\t}\n\tif cpuTotal[0].User != 0 {\n\t\tassert.InEpsilon(t, cpuTotal[0].User, perCPUUserTimeSum, margin)\n\t}\n\tif cpuTotal[0].System != 0 {\n\t\tassert.InEpsilon(t, cpuTotal[0].System, perCPUSystemTimeSum, margin)\n\t}\n\tif cpuTotal[0].Idle != 0 {\n\t\tassert.InEpsilon(t, cpuTotal[0].Idle, perCPUIdleTimeSum, margin)\n\t}\n}\n\nfunc TestCounts(t *testing.T) {\n\tlogicalCount, err := Counts(true)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotZerof(t, logicalCount, \"could not get logical CPU counts: %v\", logicalCount)\n\tt.Logf(\"logical cores: %d\", logicalCount)\n\tphysicalCount, err := Counts(false)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotZerof(t, physicalCount, \"could not get physical CPU counts: %v\", physicalCount)\n\tt.Logf(\"physical cores: %d\", physicalCount)\n\tassert.GreaterOrEqualf(t, logicalCount, physicalCount, \"logical CPU count should be greater than or equal to physical CPU count: %v >= %v\", logicalCount, physicalCount)\n}\n\nfunc TestTimeStat_String(t *testing.T) {\n\tv := TimesStat{\n\t\tCPU:    \"cpu0\",\n\t\tUser:   100.1,\n\t\tSystem: 200.1,\n\t\tIdle:   300.1,\n\t}\n\te := `{\"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}`\n\tassert.JSONEqf(t, e, v.String(), \"CPUTimesStat string is invalid: %v\", v)\n}\n\nfunc TestInfo(t *testing.T) {\n\tv, err := Info()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, v, \"could not get CPU Info\")\n\tfor _, vv := range v {\n\t\tassert.NotEmptyf(t, vv.ModelName, \"could not get CPU Info: %v\", vv)\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\tassert.NotEmptyf(t, vv.VendorID, \"could not get Vendor ID: %v\", vv)\n\t\t\tassert.NotEmptyf(t, vv.Family, \"could not get CPU Family: %v\", vv)\n\t\t\tassert.Positivef(t, vv.Mhz, \"could not get CPU Mhz: %v\", vv)\n\t\t\tassert.Positivef(t, vv.Cores, \"could not get CPU Cores: %v\", vv)\n\t\t}\n\t}\n\tt.Log(v)\n}\n\nfunc testPercent(t *testing.T, percpu bool) {\n\tt.Helper()\n\tnumcpu := runtime.NumCPU()\n\ttestCount := 3\n\n\tif runtime.GOOS != \"windows\" {\n\t\ttestCount = 100\n\t\tv, err := Percent(time.Millisecond, percpu)\n\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\tt.Skip(\"not implemented\")\n\t\t}\n\t\trequire.NoError(t, err)\n\t\t// Skip CI which CPU num is different\n\t\tif os.Getenv(\"CI\") != \"true\" {\n\t\t\tif (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) {\n\t\t\t\tt.Fatalf(\"wrong number of entries from CPUPercent: %v\", v)\n\t\t\t}\n\t\t}\n\t}\n\tfor i := 0; i < testCount; i++ {\n\t\tduration := time.Duration(10) * time.Microsecond\n\t\tv, err := Percent(duration, percpu)\n\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\tt.Skip(\"not implemented\")\n\t\t}\n\t\trequire.NoError(t, err)\n\t\tfor _, percent := range v {\n\t\t\t// Check for slightly greater then 100% to account for any rounding issues.\n\t\t\tif percent < 0.0 || percent > 100.0001*float64(numcpu) {\n\t\t\t\tt.Fatalf(\"CPUPercent value is invalid: %f\", percent)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc testPercentLastUsed(t *testing.T, percpu bool) {\n\tt.Helper()\n\tnumcpu := runtime.NumCPU()\n\ttestCount := 10\n\n\tif runtime.GOOS != \"windows\" {\n\t\ttestCount = 2\n\t\tv, err := Percent(time.Millisecond, percpu)\n\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\tt.Skip(\"not implemented\")\n\t\t}\n\t\trequire.NoError(t, err)\n\t\t// Skip CI which CPU num is different\n\t\tif os.Getenv(\"CI\") != \"true\" {\n\t\t\tif (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) {\n\t\t\t\tt.Fatalf(\"wrong number of entries from CPUPercent: %v\", v)\n\t\t\t}\n\t\t}\n\t}\n\tfor i := 0; i < testCount; i++ {\n\t\tv, err := Percent(0, percpu)\n\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\tt.Skip(\"not implemented\")\n\t\t}\n\t\trequire.NoError(t, err)\n\t\ttime.Sleep(1 * time.Millisecond)\n\t\tfor _, percent := range v {\n\t\t\t// Check for slightly greater then 100% to account for any rounding issues.\n\t\t\tif percent < 0.0 || percent > 100.0001*float64(numcpu) {\n\t\t\t\tt.Fatalf(\"CPUPercent value is invalid: %f\", percent)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestPercent(t *testing.T) {\n\ttestPercent(t, false)\n}\n\nfunc TestPercentPerCpu(t *testing.T) {\n\ttestPercent(t, true)\n}\n\nfunc TestPercentIntervalZero(t *testing.T) {\n\ttestPercentLastUsed(t, false)\n}\n\nfunc TestPercentIntervalZeroPerCPU(t *testing.T) {\n\ttestPercentLastUsed(t, true)\n}\n"
  },
  {
    "path": "cpu/cpu_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage cpu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/bits\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\t\"golang.org/x/sys/windows/registry\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar (\n\tprocGetNativeSystemInfo              = common.Modkernel32.NewProc(\"GetNativeSystemInfo\")\n\tprocGetLogicalProcessorInformationEx = common.Modkernel32.NewProc(\"GetLogicalProcessorInformationEx\")\n\tprocGetSystemFirmwareTable           = common.Modkernel32.NewProc(\"GetSystemFirmwareTable\")\n\tprocCallNtPowerInformation           = common.ModPowrProf.NewProc(\"CallNtPowerInformation\")\n)\n\ntype win32_Processor struct { //nolint:revive //FIXME\n\tFamily                    uint16\n\tManufacturer              string\n\tName                      string\n\tNumberOfLogicalProcessors uint32\n\tNumberOfCores             uint32\n\tProcessorID               *string\n\tStepping                  *string\n\tMaxClockSpeed             uint32\n}\n\n// SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n// defined in windows api doc with the following\n// https://docs.microsoft.com/en-us/windows/desktop/api/winternl/nf-winternl-ntquerysysteminformation#system_processor_performance_information\n// additional fields documented here\n// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/processor_performance.htm\ntype win32_SystemProcessorPerformanceInformation struct { //nolint:revive //FIXME\n\tIdleTime       int64  // idle time in 100ns (this is not a filetime).\n\tKernelTime     int64  // kernel time in 100ns.  kernel time includes idle time. (this is not a filetime).\n\tUserTime       int64  // usertime in 100ns (this is not a filetime).\n\tDpcTime        int64  // dpc time in 100ns (this is not a filetime).\n\tInterruptTime  int64  // interrupt time in 100ns\n\tInterruptCount uint64 // ULONG needs to be uint64\n}\n\n// https://learn.microsoft.com/en-us/windows/win32/power/processor-power-information-str\ntype processorPowerInformation struct {\n\tnumber           uint32 // http://download.microsoft.com/download/a/d/f/adf1347d-08dc-41a4-9084-623b1194d4b2/MoreThan64proc.docx\n\tmaxMhz           uint32\n\tcurrentMhz       uint32\n\tmhzLimit         uint32\n\tmaxIdleState     uint32\n\tcurrentIdleState uint32\n}\n\nconst (\n\tClocksPerSec = 10000000.0\n\n\t// systemProcessorPerformanceInformationClass information class to query with NTQuerySystemInformation\n\t// https://processhacker.sourceforge.io/doc/ntexapi_8h.html#ad5d815b48e8f4da1ef2eb7a2f18a54e0\n\twin32_SystemProcessorPerformanceInformationClass = 8 //nolint:revive //FIXME\n\n\t// size of systemProcessorPerformanceInfoSize in memory\n\twin32_SystemProcessorPerformanceInfoSize = uint32(unsafe.Sizeof(win32_SystemProcessorPerformanceInformation{})) //nolint:revive //FIXME\n\n\tfirmwareTableProviderSignatureRSMB = 0x52534d42 // \"RSMB\"  https://gitlab.winehq.org/dreamer/wine/-/blame/wine-7.0-rc6/dlls/ntdll/unix/system.c#L230\n\tsmBiosHeaderSize                   = 8          // SMBIOS header size\n\tsmbiosEndOfTable                   = 127        // Minimum length for processor structure\n\tsmbiosTypeProcessor                = 4          // SMBIOS Type 4: Processor Information\n\tsmbiosProcessorMinLength           = 0x18       // Minimum length for processor structure\n\n\tcentralProcessorRegistryKey = `HARDWARE\\DESCRIPTION\\System\\CentralProcessor`\n)\n\ntype relationship uint32\n\n// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex\nconst (\n\trelationProcessorCore    = relationship(0)\n\trelationProcessorPackage = relationship(3)\n)\n\nconst (\n\tkAffinitySize = unsafe.Sizeof(int(0))\n\t// https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/interrupt-affinity-and-priority\n\tmaxLogicalProcessorsPerGroup = uint32(unsafe.Sizeof(kAffinitySize * 8))\n\t// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-power_information_level\n\tprocessorInformation = 11\n)\n\n// Times returns times stat per cpu and combined for all CPUs\nfunc Times(percpu bool) ([]TimesStat, error) {\n\treturn TimesWithContext(context.Background(), percpu)\n}\n\nfunc TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {\n\tif percpu {\n\t\treturn perCPUTimes()\n\t}\n\n\tvar ret []TimesStat\n\tvar lpIdleTime common.FILETIME\n\tvar lpKernelTime common.FILETIME\n\tvar lpUserTime common.FILETIME\n\t// GetSystemTimes returns 0 for error, in which case we check err,\n\t// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call\n\tr, _, err := common.ProcGetSystemTimes.Call(\n\t\tuintptr(unsafe.Pointer(&lpIdleTime)),\n\t\tuintptr(unsafe.Pointer(&lpKernelTime)),\n\t\tuintptr(unsafe.Pointer(&lpUserTime)))\n\tif r == 0 {\n\t\treturn nil, err\n\t}\n\n\tLOT := float64(0.0000001)\n\tHIT := (LOT * 4294967296.0)\n\tidle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime)))\n\tuser := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime)))\n\tkernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime)))\n\tsystem := (kernel - idle)\n\n\tret = append(ret, TimesStat{\n\t\tCPU:    \"cpu-total\",\n\t\tIdle:   float64(idle),\n\t\tUser:   float64(user),\n\t\tSystem: float64(system),\n\t})\n\treturn ret, nil\n}\n\nfunc Info() ([]InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\n// this function iterates over each set bit in the package affinity mask, each bit represent a logical processor in a group (assuming you are iteriang over a package mask)\n// the function is used also to compute the global logical processor number\n// https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups\n// see https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_affinity\n// and https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship\n// and https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex\nfunc forEachSetBit64(mask uint64, fn func(bit int)) {\n\tm := mask\n\tfor m != 0 {\n\t\tb := bits.TrailingZeros64(m)\n\t\tfn(b)\n\t\tm &= m - 1\n\t}\n}\n\nfunc getProcessorPowerInformation(ctx context.Context) ([]processorPowerInformation, error) {\n\tnumLP, countErr := CountsWithContext(ctx, true)\n\tif countErr != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get logical processor count: %w\", countErr)\n\t}\n\tif numLP <= 0 {\n\t\treturn nil, fmt.Errorf(\"invalid logical processor count: %d\", numLP)\n\t}\n\n\tppiSize := uintptr(numLP) * unsafe.Sizeof(processorPowerInformation{})\n\tbuf := make([]byte, ppiSize)\n\tppi, _, err := procCallNtPowerInformation.Call(\n\t\tuintptr(processorInformation),\n\t\t0,\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\tuintptr(ppiSize),\n\t)\n\tif ppi != 0 {\n\t\treturn nil, fmt.Errorf(\"CallNtPowerInformation failed with code %d: %w\", ppi, err)\n\t}\n\tppis := unsafe.Slice((*processorPowerInformation)(unsafe.Pointer(&buf[0])), numLP)\n\treturn ppis, nil\n}\n\nfunc InfoWithContext(ctx context.Context) ([]InfoStat, error) {\n\tvar ret []InfoStat\n\tprocessorPackages, err := getSystemLogicalProcessorInformationEx(relationProcessorPackage)\n\tif err != nil {\n\t\treturn ret, fmt.Errorf(\"failed to get processor package information: %w\", err)\n\t}\n\n\tppis, powerInformationErr := getProcessorPowerInformation(ctx)\n\tif powerInformationErr != nil {\n\t\treturn ret, fmt.Errorf(\"failed to get processor power information: %w\", powerInformationErr)\n\t}\n\n\tfamily, processorId, smBIOSErr := getSMBIOSProcessorInfo()\n\tif smBIOSErr != nil {\n\t\treturn ret, smBIOSErr\n\t}\n\n\tfor i, pkg := range processorPackages {\n\t\tlogicalCount := 0\n\t\tmaxMhz := 0\n\t\tmodel := \"\"\n\t\tvendorId := \"\"\n\t\t// iterate over each set bit in the package affinity mask\n\t\tfor _, ga := range pkg.processor.groupMask {\n\t\t\tg := int(ga.group)\n\t\t\tforEachSetBit64(uint64(ga.mask), func(bit int) {\n\t\t\t\t// the global logical processor label\n\t\t\t\tglobalLpl := g*int(maxLogicalProcessorsPerGroup) + bit\n\t\t\t\tif globalLpl >= 0 && globalLpl < len(ppis) {\n\t\t\t\t\tlogicalCount++\n\t\t\t\t\tm := int(ppis[globalLpl].maxMhz)\n\t\t\t\t\tif m > maxMhz {\n\t\t\t\t\t\tmaxMhz = m\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tregistryKeyPath := filepath.Join(centralProcessorRegistryKey, strconv.Itoa(globalLpl))\n\t\t\t\tkey, err := registry.OpenKey(registry.LOCAL_MACHINE, registryKeyPath, registry.QUERY_VALUE|registry.READ)\n\t\t\t\tif err == nil {\n\t\t\t\t\tmodel = getRegistryStringValueIfUnset(key, \"ProcessorNameString\", model)\n\t\t\t\t\tvendorId = getRegistryStringValueIfUnset(key, \"VendorIdentifier\", vendorId)\n\t\t\t\t\t_ = key.Close()\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tret = append(ret, InfoStat{\n\t\t\tCPU:        int32(i),\n\t\t\tFamily:     strconv.FormatUint(uint64(family), 10),\n\t\t\tVendorID:   vendorId,\n\t\t\tModelName:  model,\n\t\t\tCores:      int32(logicalCount),\n\t\t\tPhysicalID: processorId,\n\t\t\tMhz:        float64(maxMhz),\n\t\t\tFlags:      []string{},\n\t\t})\n\t}\n\n\treturn ret, nil\n}\n\n// perCPUTimes returns times stat per cpu, per core and overall for all CPUs\nfunc perCPUTimes() ([]TimesStat, error) {\n\tvar ret []TimesStat\n\tstats, err := perfInfo()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor core, v := range stats {\n\t\tc := TimesStat{\n\t\t\tCPU:    fmt.Sprintf(\"cpu%d\", core),\n\t\t\tUser:   float64(v.UserTime) / ClocksPerSec,\n\t\t\tSystem: float64(v.KernelTime-v.IdleTime) / ClocksPerSec,\n\t\t\tIdle:   float64(v.IdleTime) / ClocksPerSec,\n\t\t\tIrq:    float64(v.InterruptTime) / ClocksPerSec,\n\t\t}\n\t\tret = append(ret, c)\n\t}\n\treturn ret, nil\n}\n\n// makes call to Windows API function to retrieve performance information for each core\nfunc perfInfo() ([]win32_SystemProcessorPerformanceInformation, error) {\n\t// Make maxResults large for safety.\n\t// We can't invoke the api call with a results array that's too small.\n\t// If we have more than 2056 cores on a single host, then it's probably the future.\n\tmaxBuffer := 2056\n\t// buffer for results from the windows proc\n\tresultBuffer := make([]win32_SystemProcessorPerformanceInformation, maxBuffer)\n\t// size of the buffer in memory\n\tbufferSize := uintptr(win32_SystemProcessorPerformanceInfoSize) * uintptr(maxBuffer)\n\t// size of the returned response\n\tvar retSize uint32\n\n\t// Invoke windows api proc.\n\t// The returned err from the windows dll proc will always be non-nil even when successful.\n\t// See https://godoc.org/golang.org/x/sys/windows#LazyProc.Call for more information\n\tretCode, _, err := common.ProcNtQuerySystemInformation.Call(\n\t\twin32_SystemProcessorPerformanceInformationClass, // System Information Class -> SystemProcessorPerformanceInformation\n\t\tuintptr(unsafe.Pointer(&resultBuffer[0])),        // pointer to first element in result buffer\n\t\tbufferSize,                        // size of the buffer in memory\n\t\tuintptr(unsafe.Pointer(&retSize)), // pointer to the size of the returned results the windows proc will set this\n\t)\n\n\t// check return code for errors\n\tif retCode != 0 {\n\t\treturn nil, fmt.Errorf(\"call to NtQuerySystemInformation returned %d. err: %s\", retCode, err.Error())\n\t}\n\n\t// calculate the number of returned elements based on the returned size\n\tnumReturnedElements := retSize / win32_SystemProcessorPerformanceInfoSize\n\n\t// trim results to the number of returned elements\n\tresultBuffer = resultBuffer[:numReturnedElements]\n\n\treturn resultBuffer, nil\n}\n\n// SystemInfo is an equivalent representation of SYSTEM_INFO in the Windows API.\n// https://msdn.microsoft.com/en-us/library/ms724958%28VS.85%29.aspx?f=255&MSPPError=-2147217396\n// https://github.com/elastic/go-windows/blob/bb1581babc04d5cb29a2bfa7a9ac6781c730c8dd/kernel32.go#L43\ntype systemInfo struct {\n\twProcessorArchitecture      uint16\n\twReserved                   uint16\n\tdwPageSize                  uint32\n\tlpMinimumApplicationAddress uintptr\n\tlpMaximumApplicationAddress uintptr\n\tdwActiveProcessorMask       uintptr\n\tdwNumberOfProcessors        uint32\n\tdwProcessorType             uint32\n\tdwAllocationGranularity     uint32\n\twProcessorLevel             uint16\n\twProcessorRevision          uint16\n}\n\ntype groupAffinity struct {\n\tmask     uintptr // https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/interrupt-affinity-and-priority#about-kaffinity\n\tgroup    uint16\n\treserved [3]uint16\n}\n\n// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship\ntype processorRelationship struct {\n\tflags          byte\n\tefficientClass byte\n\treserved       [20]byte\n\tgroupCount     uint16\n\tgroupMask      [1]groupAffinity\n}\n\n// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex\ntype systemLogicalProcessorInformationEx struct {\n\trelationship uint32\n\tsize         uint32\n\tprocessor    processorRelationship\n}\n\n// getSMBIOSProcessorInfo reads the SMBIOS Type 4 (Processor Information) structure and returns the Processor Family and ProcessorId fields.\n// If not found, returns 0 and an empty string.\nfunc getSMBIOSProcessorInfo() (family uint8, processorId string, err error) {\n\t// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable\n\tsize, _, err := procGetSystemFirmwareTable.Call(\n\t\tuintptr(firmwareTableProviderSignatureRSMB),\n\t\t0,\n\t\t0,\n\t\t0,\n\t)\n\tif size == 0 {\n\t\treturn 0, \"\", fmt.Errorf(\"failed to get SMBIOS table size: %w\", err)\n\t}\n\tbuf := make([]byte, size)\n\tret, _, err := procGetSystemFirmwareTable.Call(\n\t\tuintptr(firmwareTableProviderSignatureRSMB),\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\tuintptr(size),\n\t)\n\tif ret == 0 {\n\t\treturn 0, \"\", fmt.Errorf(\"failed to read SMBIOS table: %w\", err)\n\t}\n\t// https://wiki.osdev.org/System_Management_BIOS\n\ti := smBiosHeaderSize // skip SMBIOS header (first 8 bytes)\n\tmaxIterations := len(buf) * 2\n\titerations := 0\n\tfor i < len(buf) && iterations < maxIterations {\n\t\titerations++\n\t\tif i+4 > len(buf) {\n\t\t\tbreak\n\t\t}\n\t\ttyp := buf[i]\n\t\tlength := buf[i+1]\n\t\tif typ == smbiosEndOfTable {\n\t\t\tbreak\n\t\t}\n\t\tif typ == smbiosTypeProcessor && length >= smbiosProcessorMinLength && i+int(length) <= len(buf) {\n\t\t\t// Ensure we have enough bytes for procIdBytes\n\t\t\tif i+16 > len(buf) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// Get the processor family from byte at offset 6\n\t\t\tfamily = buf[i+6]\n\t\t\t// Extract processor ID bytes (8 bytes total) from offsets 8-15\n\t\t\tprocIdBytes := buf[i+8 : i+16]\n\t\t\t// Convert first 4 bytes to 32-bit EAX register value (little endian)\n\t\t\teax := uint32(procIdBytes[0]) | uint32(procIdBytes[1])<<8 | uint32(procIdBytes[2])<<16 | uint32(procIdBytes[3])<<24\n\t\t\t// Convert last 4 bytes to 32-bit EDX register value (little endian)\n\t\t\tedx := uint32(procIdBytes[4]) | uint32(procIdBytes[5])<<8 | uint32(procIdBytes[6])<<16 | uint32(procIdBytes[7])<<24\n\t\t\t// Format processor ID as 16 character hex string (EDX+EAX)\n\t\t\tprocId := fmt.Sprintf(\"%08X%08X\", edx, eax)\n\t\t\treturn family, procId, nil\n\t\t}\n\t\t// skip to next structure\n\t\tj := i + int(length)\n\t\tinnerIterations := 0\n\t\tmaxInner := len(buf) // failsafe for inner loop\n\t\tfor j+1 < len(buf) && innerIterations < maxInner {\n\t\t\tinnerIterations++\n\t\t\tif buf[j] == 0 && buf[j+1] == 0 {\n\t\t\t\tj += 2\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t\tif innerIterations >= maxInner {\n\t\t\tbreak // malformed buffer, avoid infinite loop\n\t\t}\n\t\ti = j\n\t}\n\treturn 0, \"\", fmt.Errorf(\"SMBIOS processor information not found: %w\", syscall.ERROR_NOT_FOUND)\n}\n\nfunc getSystemLogicalProcessorInformationEx(relationship relationship) ([]systemLogicalProcessorInformationEx, error) {\n\tvar length uint32\n\t// First call to determine the required buffer size\n\t_, _, err := procGetLogicalProcessorInformationEx.Call(uintptr(relationship), 0, uintptr(unsafe.Pointer(&length)))\n\tif err != nil && !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {\n\t\treturn nil, fmt.Errorf(\"failed to get buffer size: %w\", err)\n\t}\n\n\t// Allocate the buffer\n\tbuffer := make([]byte, length)\n\n\t// Second call to retrieve the processor information\n\t_, _, err = procGetLogicalProcessorInformationEx.Call(uintptr(relationship), uintptr(unsafe.Pointer(&buffer[0])), uintptr(unsafe.Pointer(&length)))\n\tif err != nil && !errors.Is(err, windows.NTE_OP_OK) {\n\t\treturn nil, fmt.Errorf(\"failed to get logical processor information: %w\", err)\n\t}\n\n\t// Convert the byte slice into a slice of systemLogicalProcessorInformationEx structs\n\toffset := uintptr(0)\n\tvar infos []systemLogicalProcessorInformationEx\n\tfor offset < uintptr(length) {\n\t\tinfo := (*systemLogicalProcessorInformationEx)(unsafe.Pointer(uintptr(unsafe.Pointer(&buffer[0])) + offset))\n\t\tinfos = append(infos, *info)\n\t\toffset += uintptr(info.size)\n\t}\n\n\treturn infos, nil\n}\n\nfunc getPhysicalCoreCount() (int, error) {\n\tinfos, err := getSystemLogicalProcessorInformationEx(relationProcessorCore)\n\treturn len(infos), err\n}\n\nfunc getRegistryStringValueIfUnset(key registry.Key, keyName, value string) string {\n\tif value != \"\" {\n\t\treturn value\n\t}\n\tval, _, err := key.GetStringValue(keyName)\n\tif err == nil {\n\t\treturn strings.TrimSpace(val)\n\t}\n\treturn \"\"\n}\n\nfunc CountsWithContext(_ context.Context, logical bool) (int, error) {\n\tif logical {\n\t\t// Get logical processor count https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L97\n\t\tret := windows.GetActiveProcessorCount(windows.ALL_PROCESSOR_GROUPS)\n\t\tif ret != 0 {\n\t\t\treturn int(ret), nil\n\t\t}\n\n\t\tvar sInfo systemInfo\n\t\t_, _, err := procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sInfo)))\n\t\tif sInfo.dwNumberOfProcessors == 0 {\n\t\t\treturn 0, err\n\t\t}\n\t\treturn int(sInfo.dwNumberOfProcessors), nil\n\t}\n\n\t// Get physical core count https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L499\n\treturn getPhysicalCoreCount()\n}\n"
  },
  {
    "path": "cpu/testdata/aix/prtconf",
    "content": "System Model: IBM pSeries (emulated by qemu)\nMachine Serial Number: Not Available\nProcessor Type: PowerPC_POWER8\nProcessor Implementation Mode: POWER 8\nProcessor Version: PV_8_Compat\nNumber Of Processors: 4\nProcessor Clock Speed: 1000 MHz\nCPU Type: 64-bit\nKernel Type: 64-bit\nLPAR Info: 0 aix_7200-04-02-2027\nMemory Size: 4096 MB\nGood Memory Size: 4096 MB\nPlatform Firmware level: Not Available\nFirmware Version: SLOF,HEAD\nConsole Login: enable\nAuto Restart: true\nFull Core: false\nNX Crypto Acceleration: Not Capable\nIn-Core Crypto Acceleration: Capable, but not Enabled\n \nen0\nNetwork Information\n\tHost Name: aix72-dylan\n\tIP Address: 192.168.124.53\n\tSub Netmask: \n\tGateway: 192.168.124.1\n\tName Server: \n\tDomain Name: \n \nPaging Space Information\n\tTotal Paging Space: 512MB\n\tPercent Used: 1%\n \nVolume Groups Information\n============================================================================== \nActive VGs\n============================================================================== \nrootvg:\nPV_NAME           PV STATE          TOTAL PPs   FREE PPs    FREE DISTRIBUTION\nhdisk0            active            999         809         199..193..17..200..200\n============================================================================== \n \nINSTALLED RESOURCE LIST\n\nThe following resources are installed on the machine.\n+/- = Added or deleted from Resource List.\n*   = Diagnostic support not available.\n\t\n  Model Architecture: chrp\n  Model Implementation: Uni-Processor, PCI bus\n\t\n+ sys0                                                     System Object\n+ sysplanar0                                               System Planar\n* vio0                                                     Virtual I/O Bus\n* ent0                                                     Virtual I/O Ethernet Adapter (l-lan)\n* vscsi0                                                   Virtual SCSI Client Adapter\n* cd0                                                      Virtual SCSI Optical Served by VIO Server\n* vsa0                                                     LPAR Virtual Serial Adapter\n* vty0                                                     Asynchronous Terminal\n* pci0                                                     PCI Bus\n* scsi0            qemu_virtio-scsi-pci:0000:00:02.0       Virtio SCSI Client Adapter (f41a0800)\n* hdisk0           qemu_virtio-scsi-pci:0000:00:02.0-LW_0  MPIO Other Virtio SCSI Disk Drive\n+ L2cache0                                                 L2 Cache\n+ mem0                                                     Memory\n+ proc0                                                    Processor\n+ proc1                                                    Processor\n+ proc2                                                    Processor\n+ proc3                                                    Processor\n"
  },
  {
    "path": "cpu/testdata/aix/sar-u-PALL101",
    "content": "\nAIX aix72-dylan 2 7 000000000000    05/15/24\n\nSystem configuration: lcpu=4 ent=4.00 mode=Capped \n\n11:19:03 cpu    %usr    %sys    %wio   %idle   physc   %entc\n11:19:13  0        1      11       0      88    1.00    25.0\n          1        0       0       0     100    1.00    25.0\n          2        0       0       0     100    1.00    25.0\n          3        0       0       0     100    1.00    25.0\n          -        0       3       0      97    4.00   100.0\n"
  },
  {
    "path": "cpu/testdata/aix/sar-u101",
    "content": "\nAIX aix72-dylan 2 7 000000000000    05/15/24\n\nSystem configuration: lcpu=4 ent=4.00 mode=Capped \n\n11:19:44    %usr    %sys    %wio   %idle   physc   %entc\n11:19:54       0       3       0      96    4.00   100.0\n"
  },
  {
    "path": "cpu/testdata/freebsd/1cpu_2core.txt",
    "content": "Copyright (c) 1992-2016 The FreeBSD Project.\nCopyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994\n        The Regents of the University of California. All rights reserved.\nFreeBSD is a registered trademark of The FreeBSD Foundation.\nFreeBSD 11.0-RELEASE-p2 #0: Mon Oct 24 06:55:27 UTC 2016\n    root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64\nFreeBSD clang version 3.8.0 (tags/RELEASE_380/final 262564) (based on LLVM 3.8.0)\nVT(vga): resolution 640x480\nCPU: Intel(R) Core(TM) i3 CPU         550  @ 3.20GHz (3192.07-MHz K8-class CPU)\n  Origin=\"GenuineIntel\"  Id=0x20655  Family=0x6  Model=0x25  Stepping=5\n  Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE>\n  Features2=0x9ae3bd<SSE3,DTES64,MON,DS_CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,POPCNT>\n  AMD Features=0x28100800<SYSCALL,NX,RDTSCP,LM>\n  AMD Features2=0x1<LAHF>\n  VT-x: PAT,HLT,MTF,PAUSE,EPT,UG,VPID\n  TSC: P-state invariant, performance statistics\nreal memory  = 8589934592 (8192 MB)\navail memory = 8046452736 (7673 MB)\nEvent timer \"LAPIC\" quality 600\nACPI APIC Table: <INTEL  DH55HC  >\nFreeBSD/SMP: Multiprocessor System Detected: 4 CPUs\nFreeBSD/SMP: 1 package(s) x 2 core(s) x 2 hardware threads\nrandom: unblocking device.\nioapic0 <Version 2.0> irqs 0-23 on motherboard\nrandom: entropy device external interface\nkbd1 at kbdmux0\nnetmap: loaded module\nmodule_register_init: MOD_LOAD (vesa, 0xffffffff8101c970, 0) error 19\nvtvga0: <VT VGA driver> on motherboard\ncryptosoft0: <software crypto> on motherboard\naesni0: No AESNI support.\nacpi0: <INTEL DH55HC> on motherboard\nacpi0: Power Button (fixed)\ncpu0: <ACPI CPU> on acpi0\nACPI BIOS Warning (bug): Incorrect checksum in table [SSDT] - 0x3F, should be 0x1F (20160527/tbprint-229)\ncpu1: <ACPI CPU> on acpi0\ncpu2: <ACPI CPU> on acpi0\ncpu3: <ACPI CPU> on acpi0\nattimer0: <AT timer> port 0x40-0x43 irq 0 on acpi0\nTimecounter \"i8254\" frequency 1193182 Hz quality 0\nEvent timer \"i8254\" frequency 1193182 Hz quality 100\natrtc0: <AT realtime clock> port 0x70-0x71 irq 8 on acpi0\nEvent timer \"RTC\" frequency 32768 Hz quality 0"
  },
  {
    "path": "cpu/testdata/freebsd/1cpu_4core.txt",
    "content": "Copyright (c) 1992-2016 The FreeBSD Project.\nCopyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994\n        The Regents of the University of California. All rights reserved.\nFreeBSD is a registered trademark of The FreeBSD Foundation.\nFreeBSD 10.3-RELEASE-p4 #0: Sat May 28 12:23:44 UTC 2016\n    root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64\nFreeBSD clang version 3.4.1 (tags/RELEASE_34/dot1-final 208032) 20140512\nCPU: Intel(R) Xeon(R) CPU E5-1620 v2 @ 3.70GHz (3700.09-MHz K8-class CPU)\n  Origin=\"GenuineIntel\"  Id=0x306e4  Family=0x6  Model=0x3e  Stepping=4\n  Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE>\n  Features2=0x7fbee3ff<SSE3,PCLMULQDQ,DTES64,MON,DS_CPL,VMX,SMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,DCA,SSE4.1,SSE4.2,x2APIC,POPCNT,TSCDLT,AESNI,XSAVE,OSXSAVE,AVX,F16C,RDRAND>\n  AMD Features=0x2c100800<SYSCALL,NX,Page1GB,RDTSCP,LM>\n  AMD Features2=0x1<LAHF>\n  Structured Extended Features=0x281<FSGSBASE,SMEP,ERMS>\n  XSAVE Features=0x1<XSAVEOPT>\n  VT-x: PAT,HLT,MTF,PAUSE,EPT,UG,VPID,VID,PostIntr\n  TSC: P-state invariant, performance statistics\nreal memory  = 34368126976 (32776 MB)\navail memory = 33228333056 (31689 MB)\nEvent timer \"LAPIC\" quality 600\nACPI APIC Table: < >\nFreeBSD/SMP: Multiprocessor System Detected: 8 CPUs\nFreeBSD/SMP: 1 package(s) x 4 core(s) x 2 SMT threads\n cpu0 (BSP): APIC ID:  0\n cpu1 (AP): APIC ID:  1\n cpu2 (AP): APIC ID:  2\n cpu3 (AP): APIC ID:  3\n cpu4 (AP): APIC ID:  4\n cpu5 (AP): APIC ID:  5\n cpu6 (AP): APIC ID:  6\n cpu7 (AP): APIC ID:  7\nrandom: <Software, Yarrow> initialized\nioapic0 <Version 2.0> irqs 0-23 on motherboard\nioapic1 <Version 2.0> irqs 24-47 on motherboard\nkbd1 at kbdmux0\ncryptosoft0: <software crypto> on motherboard\naesni0: <AES-CBC,AES-XTS> on motherboard\nacpi0: <SUPERM SMCI--MB> on motherboard"
  },
  {
    "path": "cpu/testdata/freebsd/2cpu_4core.txt",
    "content": "Copyright (c) 1992-2011 The FreeBSD Project.\nCopyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994\n        The Regents of the University of California. All rights reserved.\nFreeBSD is a registered trademark of The FreeBSD Foundation.\nFreeBSD 8.2-RELEASE #1: Sat Mar  5 23:03:14 CET 2011\n    root@host1:/usr/obj/usr/src/sys/MYKERNEL amd64\nTimecounter \"i8254\" frequency 1193182 Hz quality 0\nCPU: Intel(R) Xeon(R) CPU           E5420  @ 2.50GHz (2500.11-MHz K8-class CPU)\n  Origin = \"GenuineIntel\"  Id = 0x10676  Family = 6  Model = 17  Stepping = 6\n  Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE>\n  Features2=0xce3bd<SSE3,DTES64,MON,DS_CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,DCA,SSE4.1>\n  AMD Features=0x20100800<SYSCALL,NX,LM>\n  AMD Features2=0x1<LAHF>\n  TSC: P-state invariant\nreal memory  = 17179869184 (16384 MB)\navail memory = 16531587072 (15765 MB)\nACPI APIC Table: <PTLTD          APIC  >\nFreeBSD/SMP: Multiprocessor System Detected: 8 CPUs\nFreeBSD/SMP: 2 package(s) x 4 core(s)\n cpu0 (BSP): APIC ID:  0\n cpu1 (AP): APIC ID:  1\n cpu2 (AP): APIC ID:  2\n cpu3 (AP): APIC ID:  3\n cpu4 (AP): APIC ID:  4\n cpu5 (AP): APIC ID:  5\n cpu6 (AP): APIC ID:  6\n cpu7 (AP): APIC ID:  7\nioapic0 <Version 2.0> irqs 0-23 on motherboard\nioapic1 <Version 2.0> irqs 24-47 on motherboard\nkbd1 at kbdmux0\nacpi0: <PTLTD    XSDT> on motherboard\nacpi0: [ITHREAD]\nacpi0: Power Button (fixed)\nunknown: I/O range not supported\nTimecounter \"ACPI-fast\" frequency 3579545 Hz quality 1000\nacpi_timer0: <24-bit timer at 3.579545MHz> port 0x1008-0x100b on acpi0\ncpu0: <ACPI CPU> on acpi0\ncpu1: <ACPI CPU> on acpi0\ncpu2: <ACPI CPU> on acpi0\ncpu3: <ACPI CPU> on acpi0\ncpu4: <ACPI CPU> on acpi0\ncpu5: <ACPI CPU> on acpi0\ncpu6: <ACPI CPU> on acpi0\ncpu7: <ACPI CPU> on acpi0\npcib0: <ACPI Host-PCI bridge> port 0xcf8-0xcff on acpi0"
  },
  {
    "path": "cpu/testdata/linux/1037/proc/cpuinfo",
    "content": "processor\t: 0\nProcessor\t: ARMv7 Processor rev 4 (v7l)\nmodel name\t: ARMv7 Processor rev 4 (v7l)\nBogoMIPS\t: 42.43\nFeatures\t: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 \nCPU implementer\t: 0x41\nCPU architecture: 7\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nprocessor\t: 1\nProcessor\t: ARMv7 Processor rev 4 (v7l)\nmodel name\t: ARMv7 Processor rev 4 (v7l)\nBogoMIPS\t: 42.43\nFeatures\t: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 \nCPU implementer\t: 0x41\nCPU architecture: 7\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nprocessor\t: 2\nProcessor\t: ARMv7 Processor rev 4 (v7l)\nmodel name\t: ARMv7 Processor rev 4 (v7l)\nBogoMIPS\t: 42.43\nFeatures\t: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 \nCPU implementer\t: 0x41\nCPU architecture: 7\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nprocessor\t: 3\nProcessor\t: ARMv7 Processor rev 4 (v7l)\nmodel name\t: ARMv7 Processor rev 4 (v7l)\nBogoMIPS\t: 42.43\nFeatures\t: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 \nCPU implementer\t: 0x41\nCPU architecture: 7\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nprocessor\t: 4\nProcessor\t: ARMv7 Processor rev 2 (v7l)\nmodel name\t: ARMv7 Processor rev 2 (v7l)\nBogoMIPS\t: 29.52\nFeatures\t: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 \nCPU implementer\t: 0x41\nCPU architecture: 7\nCPU variant\t: 0x0\nCPU part\t: 0xd09\nCPU revision\t: 2\n\nprocessor\t: 5\nProcessor\t: ARMv7 Processor rev 2 (v7l)\nmodel name\t: ARMv7 Processor rev 2 (v7l)\nBogoMIPS\t: 29.52\nFeatures\t: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 \nCPU implementer\t: 0x41\nCPU architecture: 7\nCPU variant\t: 0x0\nCPU part\t: 0xd09\nCPU revision\t: 2\n\nprocessor\t: 6\nProcessor\t: ARMv7 Processor rev 2 (v7l)\nmodel name\t: ARMv7 Processor rev 2 (v7l)\nBogoMIPS\t: 29.52\nFeatures\t: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 \nCPU implementer\t: 0x41\nCPU architecture: 7\nCPU variant\t: 0x0\nCPU part\t: 0xd09\nCPU revision\t: 2\n\nprocessor\t: 7\nProcessor\t: ARMv7 Processor rev 2 (v7l)\nmodel name\t: ARMv7 Processor rev 2 (v7l)\nBogoMIPS\t: 29.52\nFeatures\t: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 \nCPU implementer\t: 0x41\nCPU architecture: 7\nCPU variant\t: 0x0\nCPU part\t: 0xd09\nCPU revision\t: 2\n\nHardware\t: MT8183\nRevision\t: 0000\nSerial\t\t: 29aa1cf5ba0159c3\n"
  },
  {
    "path": "cpu/testdata/linux/1958/proc/cpuinfo",
    "content": "processor\t: 0\nvendor_id\t: HygonGenuine\ncpu family\t: 24\nmodel\t\t: 6\nmodel name\t: Hygon C86-4G (OPN:5435)\nstepping\t: 1\nmicrocode\t: 0x90610009\ncpu MHz\t\t: 2799.751\ncache size\t: 512 KB\nphysical id\t: 0\nsiblings\t: 32\ncore id\t\t: 0\ncpu cores\t: 16\napicid\t\t: 0\ninitial apicid\t: 0\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 16\nwp\t\t: yes\nflags\t\t: fpu vme de pse\nbogomips\t: 5599.50\n"
  },
  {
    "path": "cpu/testdata/linux/424/proc/stat",
    "content": "cpu  23644 6695 4764 134931750 22115 0 473 5892 0 0\ncpu0 6418 888 1230 33730755 5043 0 4 1046 0 0\ncpu1 6858 4870 1632 33716510 12327 0 235 1765 0 0\ncpu2 4859 622 915 33742072 2312 0 25 1546 0 0\ncpu3 5507 314 986 33742411 2432 0 208 1534 0 0\nintr 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\nctxt 41317767\nbtime 1505515383\nprocesses 41562\nprocs_running 1\nprocs_blocked 0\nsoftirq 5433315 0 1644387 67542 1428221 0 0 12270 1573783 0 707112"
  },
  {
    "path": "cpu/testdata/linux/times_empty/proc/stat",
    "content": ""
  },
  {
    "path": "cpu/testdata/plan9/2cores/dev/cputype",
    "content": "Core i7/Xeon 2403\n"
  },
  {
    "path": "cpu/testdata/plan9/2cores/dev/sysstat",
    "content": "          0    59251106    37524162     1208203       65907           0           0           7         100           0 \n          1   219155408    28582838     5017097     1002072           0           0           0          98           1 \n"
  },
  {
    "path": "cpu/testdata/plan9/2cores/dev/time",
    "content": " 1633882064   1633882064926300833      2825920097745864            1999997644 "
  },
  {
    "path": "cpu/testdata/plan9/2cores/proc/1/status",
    "content": "init                        bootes                      Await                10          20  1404307210         110          20           0         116          10          10 "
  },
  {
    "path": "cpu/testdata/plan9/2cores/proc/331/.gitkeep",
    "content": ""
  },
  {
    "path": "cpu/testdata/plan9/2cores/proc/54384/status",
    "content": "rc                          lufia                       Await                 0           0      589160        8770        3260           0         248          10          10 "
  },
  {
    "path": "cpu/testdata/plan9/2cores/proc/54412/status",
    "content": "git-remote-https            lufia                       Semacquire          390         310      370670           0           0           0       98368          10          10 "
  },
  {
    "path": "cpu/testdata/plan9/2cores/proc/72/status",
    "content": "httpd                       none                        Open               2380       29690  1404804330           0           0           0       23616          10          10 "
  },
  {
    "path": "cpu/testdata/solaris/1cpu_1core_isainfo.txt",
    "content": "64-bit amd64 applications\n        rdseed adx avx2 fma bmi2 bmi1 rdrand f16c vmx avx xsave pclmulqdq\n        aes movbe sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr\n        mmx cmov amd_sysc cx8 tsc fpu"
  },
  {
    "path": "cpu/testdata/solaris/1cpu_1core_psrinfo.txt",
    "content": "The physical processor has 1 virtual processor (0)\n  x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz)\n        Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz"
  },
  {
    "path": "cpu/testdata/solaris/2cpu_12core_isainfo.txt",
    "content": "64-bit amd64 applications\n\tamd_svm amd_lzcnt popcnt amd_sse4a tscp ahf cx16 sse3 sse2 sse fxsr\n\tamd_3dnowx amd_3dnow amd_mmx mmx cmov amd_sysc cx8 tsc fpu\n"
  },
  {
    "path": "cpu/testdata/solaris/2cpu_12core_psrinfo.txt",
    "content": "The physical processor has 12 virtual processors (0-11)\n  x86 (AuthenticAMD 100F91 family 16 model 9 step 1 clock 2300 MHz)\n\tAMD Opteron(tm) Processor 6176\t[ Socket: G34 ]\nThe physical processor has 12 virtual processors (12-23)\n  x86 (AuthenticAMD 100F91 family 16 model 9 step 1 clock 2300 MHz)\n\tAMD Opteron(tm) Processor 6176\t[ Socket: G34 ]\n"
  },
  {
    "path": "cpu/testdata/solaris/2cpu_1core_isainfo.txt",
    "content": "64-bit amd64 applications\n        rdseed adx avx2 fma bmi2 bmi1 rdrand f16c vmx avx xsave pclmulqdq\n        aes movbe sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr\n        mmx cmov amd_sysc cx8 tsc fpu"
  },
  {
    "path": "cpu/testdata/solaris/2cpu_1core_psrinfo.txt",
    "content": "The physical processor has 1 virtual processor (0)\n  x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz)\n        Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz\nThe physical processor has 1 virtual processor (1)\n  x86 (GenuineIntel 406E3 family 6 model 78 step 3 clock 3312 MHz)\n        Intel(r) Core(tm) i7-6567U CPU @ 3.30GHz"
  },
  {
    "path": "cpu/testdata/solaris/2cpu_8core_isainfo.txt",
    "content": "64-bit amd64 applications\n        vmx avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp cx16\n        sse3 sse2 sse fxsr mmx cmov amd_sysc cx8 tsc fpu"
  },
  {
    "path": "cpu/testdata/solaris/2cpu_8core_psrinfo.txt",
    "content": "The physical processor has 8 cores and 16 virtual processors (0-7 16-23)\n  The core has 2 virtual processors (0 16)\n  The core has 2 virtual processors (1 17)\n  The core has 2 virtual processors (2 18)\n  The core has 2 virtual processors (3 19)\n  The core has 2 virtual processors (4 20)\n  The core has 2 virtual processors (5 21)\n  The core has 2 virtual processors (6 22)\n  The core has 2 virtual processors (7 23)\n    x86 (GenuineIntel 206D7 family 6 model 45 step 7 clock 2600 MHz)\n      Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz\nThe physical processor has 8 cores and 16 virtual processors (8-15 24-31)\n  The core has 2 virtual processors (8 24)\n  The core has 2 virtual processors (9 25)\n  The core has 2 virtual processors (10 26)\n  The core has 2 virtual processors (11 27)\n  The core has 2 virtual processors (12 28)\n  The core has 2 virtual processors (13 29)\n  The core has 2 virtual processors (14 30)\n  The core has 2 virtual processors (15 31)\n    x86 (GenuineIntel 206D7 family 6 model 45 step 7 clock 2600 MHz)\n      Intel(r) Xeon(r) CPU E5-2670 0 @ 2.60GHz"
  },
  {
    "path": "disk/disk.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage disk\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar invoke common.Invoker = common.Invoke{}\n\ntype Warnings = common.Warnings\n\ntype UsageStat struct {\n\tPath              string  `json:\"path\"`\n\tFstype            string  `json:\"fstype\"`\n\tTotal             uint64  `json:\"total\"`\n\tFree              uint64  `json:\"free\"`\n\tUsed              uint64  `json:\"used\"`\n\tUsedPercent       float64 `json:\"usedPercent\"`\n\tInodesTotal       uint64  `json:\"inodesTotal\"`\n\tInodesUsed        uint64  `json:\"inodesUsed\"`\n\tInodesFree        uint64  `json:\"inodesFree\"`\n\tInodesUsedPercent float64 `json:\"inodesUsedPercent\"`\n}\n\ntype PartitionStat struct {\n\tDevice     string   `json:\"device\"`\n\tMountpoint string   `json:\"mountpoint\"`\n\tFstype     string   `json:\"fstype\"`\n\tOpts       []string `json:\"opts\"`\n}\n\ntype IOCountersStat struct {\n\tReadCount        uint64 `json:\"readCount\"`\n\tMergedReadCount  uint64 `json:\"mergedReadCount\"`\n\tWriteCount       uint64 `json:\"writeCount\"`\n\tMergedWriteCount uint64 `json:\"mergedWriteCount\"`\n\tReadBytes        uint64 `json:\"readBytes\"`\n\tWriteBytes       uint64 `json:\"writeBytes\"`\n\tReadTime         uint64 `json:\"readTime\"`\n\tWriteTime        uint64 `json:\"writeTime\"`\n\tIopsInProgress   uint64 `json:\"iopsInProgress\"`\n\tIoTime           uint64 `json:\"ioTime\"`\n\tWeightedIO       uint64 `json:\"weightedIO\"`\n\tName             string `json:\"name\"`\n\tSerialNumber     string `json:\"serialNumber\"`\n\tLabel            string `json:\"label\"`\n}\n\nfunc (d UsageStat) String() string {\n\ts, _ := json.Marshal(d)\n\treturn string(s)\n}\n\nfunc (d PartitionStat) String() string {\n\ts, _ := json.Marshal(d)\n\treturn string(s)\n}\n\nfunc (d IOCountersStat) String() string {\n\ts, _ := json.Marshal(d)\n\treturn string(s)\n}\n\n// Usage returns a file system usage. path is a filesystem path such\n// as \"/\", not device file path like \"/dev/vda1\".  If you want to use\n// a return value of disk.Partitions, use \"Mountpoint\" not \"Device\".\nfunc Usage(path string) (*UsageStat, error) {\n\treturn UsageWithContext(context.Background(), path)\n}\n\n// Partitions returns disk partitions. If all is false, returns\n// physical devices only (e.g. hard disks, cd-rom drives, USB keys)\n// and ignore all others (e.g. memory partitions such as /dev/shm)\n//\n// 'all' argument is ignored for BSD, see: https://github.com/giampaolo/psutil/issues/906\nfunc Partitions(all bool) ([]PartitionStat, error) {\n\treturn PartitionsWithContext(context.Background(), all)\n}\n\nfunc IOCounters(names ...string) (map[string]IOCountersStat, error) {\n\treturn IOCountersWithContext(context.Background(), names...)\n}\n\n// SerialNumber returns Serial Number of given device or empty string\n// on error. Name of device is expected, eg. /dev/sda\nfunc SerialNumber(name string) (string, error) {\n\treturn SerialNumberWithContext(context.Background(), name)\n}\n\n// Label returns label of given device or empty string on error.\n// Name of device is expected, eg. /dev/sda\n// Supports label based on devicemapper name\n// See https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm\nfunc Label(name string) (string, error) {\n\treturn LabelWithContext(context.Background(), name)\n}\n"
  },
  {
    "path": "disk/disk_aix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage disk\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc LabelWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\n// Using lscfg and a device name, we can get the device information\n// This is a pure go implementation, and should be moved to disk_aix_nocgo.go\n// if a more efficient CGO method is introduced in disk_aix_cgo.go\nfunc SerialNumberWithContext(ctx context.Context, name string) (string, error) {\n\t// This isn't linux, these aren't actual disk devices\n\tif strings.HasPrefix(name, \"/dev/\") {\n\t\treturn \"\", errors.New(\"devices on /dev are not physical disks on aix\")\n\t}\n\tout, err := invoke.CommandWithContext(ctx, \"lscfg\", \"-vl\", name)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tret := \"\"\n\t// Kind of inefficient, but it works\n\tlines := strings.Split(string(out), \"\\n\")\n\tfor line := 1; line < len(lines); line++ {\n\t\tv := strings.TrimSpace(lines[line])\n\t\tif strings.HasPrefix(v, \"Serial Number...............\") {\n\t\t\tret = strings.TrimPrefix(v, \"Serial Number...............\")\n\t\t\tif ret == \"\" {\n\t\t\t\treturn \"\", errors.New(\"empty serial for disk\")\n\t\t\t}\n\t\t\treturn ret, nil\n\t\t}\n\t}\n\n\treturn ret, errors.New(\"serial entry not found for disk\")\n}\n"
  },
  {
    "path": "disk/disk_aix_cgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && cgo\n\npackage disk\n\n/*\n#include <unistd.h>\n*/\nimport \"C\"\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/power-devops/perfstat\"\n)\n\nfunc IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCountersStat, error) {\n\tdisks, err := perfstat.DiskStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnameSet := make(map[string]bool, len(names))\n\tfor _, n := range names {\n\t\tnameSet[n] = true\n\t}\n\n\tclkTck := uint64(C.sysconf(C._SC_CLK_TCK))\n\n\tret := make(map[string]IOCountersStat, len(disks))\n\tfor _, d := range disks {\n\t\tif len(nameSet) > 0 && !nameSet[d.Name] {\n\t\t\tcontinue\n\t\t}\n\n\t\tret[d.Name] = IOCountersStat{\n\t\t\tName:       d.Name,\n\t\t\tReadCount:  uint64(d.XRate),\n\t\t\tWriteCount: uint64(d.Xfers - d.XRate),\n\t\t\tReadBytes:  uint64(d.Rblks) * uint64(d.BSize),\n\t\t\tWriteBytes: uint64(d.Wblks) * uint64(d.BSize),\n\t\t\t// perfstat Rserv, Wserv, and WqTime are in nanoseconds;\n\t\t\t// IOCountersStat expects milliseconds.\n\t\t\tReadTime:       uint64(d.Rserv) / 1_000_000,\n\t\t\tWriteTime:      uint64(d.Wserv) / 1_000_000,\n\t\t\tIoTime:         uint64(d.Time) * 1000 / clkTck, // d.Time is in kernel ticks; convert to ms\n\t\t\tWeightedIO:     uint64(d.WqTime) / 1_000_000,\n\t\t\tIopsInProgress: uint64(d.QDepth),\n\t\t}\n\t}\n\treturn ret, nil\n}\n\nvar FSType map[int]string\n\nfunc init() {\n\tFSType = map[int]string{\n\t\t0: \"jfs2\", 1: \"namefs\", 2: \"nfs\", 3: \"jfs\", 5: \"cdrom\", 6: \"proc\",\n\t\t16: \"special-fs\", 17: \"cache-fs\", 18: \"nfs3\", 19: \"automount-fs\", 20: \"pool-fs\", 32: \"vxfs\",\n\t\t33: \"veritas-fs\", 34: \"udfs\", 35: \"nfs4\", 36: \"nfs4-pseudo\", 37: \"smbfs\", 38: \"mcr-pseudofs\",\n\t\t39: \"ahafs\", 40: \"sterm-nfs\", 41: \"asmfs\",\n\t}\n}\n\nfunc PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {\n\tf, err := perfstat.FileSystemStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := make([]PartitionStat, 0, len(f))\n\n\tfor _, fs := range f {\n\t\tfstyp, exists := FSType[fs.FSType]\n\t\tif !exists {\n\t\t\tfstyp = \"unknown\"\n\t\t}\n\t\tinfo := PartitionStat{\n\t\t\tDevice:     fs.Device,\n\t\t\tMountpoint: fs.MountPoint,\n\t\t\tFstype:     fstyp,\n\t\t}\n\t\tret = append(ret, info)\n\t}\n\n\treturn ret, err\n}\n\nfunc UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {\n\tf, err := perfstat.FileSystemStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tblocksize := uint64(512)\n\tfor _, fs := range f {\n\t\tif path == fs.MountPoint {\n\t\t\tfstyp, exists := FSType[fs.FSType]\n\t\t\tif !exists {\n\t\t\t\tfstyp = \"unknown\"\n\t\t\t}\n\t\t\tinfo := UsageStat{\n\t\t\t\tPath:        path,\n\t\t\t\tFstype:      fstyp,\n\t\t\t\tTotal:       uint64(fs.TotalBlocks) * blocksize,\n\t\t\t\tFree:        uint64(fs.FreeBlocks) * blocksize,\n\t\t\t\tUsed:        uint64(fs.TotalBlocks-fs.FreeBlocks) * blocksize,\n\t\t\t\tInodesTotal: uint64(fs.TotalInodes),\n\t\t\t\tInodesFree:  uint64(fs.FreeInodes),\n\t\t\t\tInodesUsed:  uint64(fs.TotalInodes - fs.FreeInodes),\n\t\t\t}\n\t\t\tinfo.UsedPercent = (float64(info.Used) / float64(info.Total)) * 100.0\n\t\t\tinfo.InodesUsedPercent = (float64(info.InodesUsed) / float64(info.InodesTotal)) * 100.0\n\t\t\treturn &info, nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"mountpoint %s not found\", path)\n}\n"
  },
  {
    "path": "disk/disk_aix_nocgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && !cgo\n\npackage disk\n\nimport (\n\t\"context\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar startBlank = regexp.MustCompile(`^\\s+`)\n\nvar (\n\tignoreFSType = map[string]bool{\"procfs\": true}\n\tFSType       = map[int]string{\n\t\t0: \"jfs2\", 1: \"namefs\", 2: \"nfs\", 3: \"jfs\", 5: \"cdrom\", 6: \"proc\",\n\t\t16: \"special-fs\", 17: \"cache-fs\", 18: \"nfs3\", 19: \"automount-fs\", 20: \"pool-fs\", 32: \"vxfs\",\n\t\t33: \"veritas-fs\", 34: \"udfs\", 35: \"nfs4\", 36: \"nfs4-pseudo\", 37: \"smbfs\", 38: \"mcr-pseudofs\",\n\t\t39: \"ahafs\", 40: \"sterm-nfs\", 41: \"asmfs\",\n\t}\n)\n\nfunc IOCountersWithContext(_ context.Context, _ ...string) (map[string]IOCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc PartitionsWithContext(ctx context.Context, _ bool) ([]PartitionStat, error) {\n\tvar ret []PartitionStat\n\n\tout, err := invoke.CommandWithContext(ctx, \"mount\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// parse head lines for column names\n\tcolidx := make(map[string]int)\n\tlines := strings.Split(string(out), \"\\n\")\n\tif len(lines) < 3 {\n\t\treturn nil, common.ErrNotImplementedError\n\t}\n\n\tidx := 0\n\tstart := 0\n\tfinished := false\n\tfor pos, ch := range lines[1] {\n\t\tif ch == ' ' && !finished {\n\t\t\tname := strings.TrimSpace(lines[0][start:pos])\n\t\t\tcolidx[name] = idx\n\t\t\tfinished = true\n\t\t} else if ch == '-' && finished {\n\t\t\tidx++\n\t\t\tstart = pos\n\t\t\tfinished = false\n\t\t}\n\t}\n\tname := strings.TrimSpace(lines[0][start:len(lines[1])])\n\tcolidx[name] = idx\n\n\tfor idx := 2; idx < len(lines); idx++ {\n\t\tline := lines[idx]\n\t\tif startBlank.MatchString(line) {\n\t\t\tline = \"localhost\" + line\n\t\t}\n\t\tp := strings.Fields(line)\n\t\tif len(p) < 5 || ignoreFSType[p[colidx[\"vfs\"]]] {\n\t\t\tcontinue\n\t\t}\n\t\td := PartitionStat{\n\t\t\tDevice:     p[colidx[\"mounted\"]],\n\t\t\tMountpoint: p[colidx[\"mounted over\"]],\n\t\t\tFstype:     p[colidx[\"vfs\"]],\n\t\t\tOpts:       strings.Split(p[colidx[\"options\"]], \",\"),\n\t\t}\n\n\t\tret = append(ret, d)\n\t}\n\n\treturn ret, nil\n}\n\nfunc getFsType(stat unix.Statfs_t) string {\n\treturn FSType[int(stat.Vfstype)]\n}\n\nfunc UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"df\", \"-v\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := &UsageStat{}\n\n\tblocksize := uint64(512)\n\tlines := strings.Split(string(out), \"\\n\")\n\tif len(lines) < 2 {\n\t\treturn &UsageStat{}, common.ErrNotImplementedError\n\t}\n\n\thf := strings.Fields(strings.ReplaceAll(lines[0], \"Mounted on\", \"Path\")) // headers\n\tfor line := 1; line < len(lines); line++ {\n\t\tfs := strings.Fields(lines[line]) // values\n\t\tfor i, header := range hf {\n\t\t\t// We're done in any of these use cases\n\t\t\tif i >= len(fs) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tswitch header {\n\t\t\tcase `Filesystem`:\n\t\t\t\t// This is not a valid fs for us to parse\n\t\t\t\tif fs[i] == \"/proc\" || fs[i] == \"/ahafs\" || fs[i] != path {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tret.Fstype, err = GetMountFSTypeWithContext(ctx, fs[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\tcase `Path`:\n\t\t\t\tret.Path = fs[i]\n\t\t\tcase `512-blocks`:\n\t\t\t\ttotal, err := strconv.ParseUint(fs[i], 10, 64)\n\t\t\t\tret.Total = total * blocksize\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\tcase `Used`:\n\t\t\t\tret.Used, err = strconv.ParseUint(fs[i], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\tcase `Free`:\n\t\t\t\tret.Free, err = strconv.ParseUint(fs[i], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\tcase `%Used`:\n\t\t\t\tval, err := strconv.ParseInt(strings.ReplaceAll(fs[i], \"%\", \"\"), 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tret.UsedPercent = float64(val) / float64(100)\n\t\t\tcase `Ifree`:\n\t\t\t\tret.InodesFree, err = strconv.ParseUint(fs[i], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\tcase `Iused`:\n\t\t\t\tret.InodesUsed, err = strconv.ParseUint(fs[i], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\tcase `%Iused`:\n\t\t\t\tval, err := strconv.ParseInt(strings.ReplaceAll(fs[i], \"%\", \"\"), 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tret.InodesUsedPercent = float64(val) / float64(100)\n\t\t\t}\n\t\t}\n\n\t\t// Calculated value, since it isn't returned by the command\n\t\tret.InodesTotal = ret.InodesUsed + ret.InodesFree\n\n\t\t// Valid Usage data, so append it\n\t\treturn ret, nil\n\t}\n\n\treturn ret, nil\n}\n\nfunc GetMountFSTypeWithContext(ctx context.Context, mp string) (string, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"mount\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Kind of inefficient, but it works\n\tlines := strings.Split(string(out), \"\\n\")\n\tfor line := 1; line < len(lines); line++ {\n\t\tfields := strings.Fields(lines[line])\n\t\tif strings.TrimSpace(fields[0]) == mp {\n\t\t\treturn fields[2], nil\n\t\t}\n\t}\n\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "disk/disk_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage disk\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// PartitionsWithContext returns disk partition.\n// 'all' argument is ignored, see: https://github.com/giampaolo/psutil/issues/906\nfunc PartitionsWithContext(_ context.Context, _ bool) ([]PartitionStat, error) {\n\tvar ret []PartitionStat\n\n\tcount, err := unix.Getfsstat(nil, unix.MNT_WAIT)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tfs := make([]unix.Statfs_t, count)\n\tcount, err = unix.Getfsstat(fs, unix.MNT_WAIT)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\t// On 10.14, and possibly other OS versions, the actual count may\n\t// be less than from the first call. Truncate to the returned count\n\t// to prevent accessing uninitialized entries.\n\t// https://github.com/shirou/gopsutil/issues/1390\n\tfs = fs[:count]\n\tfor i := range fs {\n\t\tstat := &fs[i]\n\t\topts := []string{\"rw\"}\n\t\tif stat.Flags&unix.MNT_RDONLY != 0 {\n\t\t\topts = []string{\"ro\"}\n\t\t}\n\t\tif stat.Flags&unix.MNT_SYNCHRONOUS != 0 {\n\t\t\topts = append(opts, \"sync\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOEXEC != 0 {\n\t\t\topts = append(opts, \"noexec\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOSUID != 0 {\n\t\t\topts = append(opts, \"nosuid\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_UNION != 0 {\n\t\t\topts = append(opts, \"union\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_ASYNC != 0 {\n\t\t\topts = append(opts, \"async\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_DONTBROWSE != 0 {\n\t\t\topts = append(opts, \"nobrowse\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_AUTOMOUNTED != 0 {\n\t\t\topts = append(opts, \"automounted\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_JOURNALED != 0 {\n\t\t\topts = append(opts, \"journaled\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_MULTILABEL != 0 {\n\t\t\topts = append(opts, \"multilabel\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOATIME != 0 {\n\t\t\topts = append(opts, \"noatime\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NODEV != 0 {\n\t\t\topts = append(opts, \"nodev\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_LOCAL != 0 {\n\t\t\topts = append(opts, \"local\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_CPROTECT != 0 {\n\t\t\topts = append(opts, \"protect\")\n\t\t}\n\t\td := PartitionStat{\n\t\t\tDevice:     common.ByteToString(stat.Mntfromname[:]),\n\t\t\tMountpoint: common.ByteToString(stat.Mntonname[:]),\n\t\t\tFstype:     common.ByteToString(stat.Fstypename[:]),\n\t\t\tOpts:       opts,\n\t\t}\n\n\t\tret = append(ret, d)\n\t}\n\n\treturn ret, nil\n}\n\nfunc getFsType(stat unix.Statfs_t) string {\n\treturn common.ByteToString(stat.Fstypename[:])\n}\n\ntype spnvmeDataTypeItem struct {\n\tName              string `json:\"_name\"`\n\tBsdName           string `json:\"bsd_name\"`\n\tDetachableDrive   string `json:\"detachable_drive\"`\n\tDeviceModel       string `json:\"device_model\"`\n\tDeviceRevision    string `json:\"device_revision\"`\n\tDeviceSerial      string `json:\"device_serial\"`\n\tPartitionMapType  string `json:\"partition_map_type\"`\n\tRemovableMedia    string `json:\"removable_media\"`\n\tSize              string `json:\"size\"`\n\tSizeInBytes       int64  `json:\"size_in_bytes\"`\n\tSmartStatus       string `json:\"smart_status\"`\n\tSpnvmeTrimSupport string `json:\"spnvme_trim_support\"`\n\tVolumes           []struct {\n\t\tName        string `json:\"_name\"`\n\t\tBsdName     string `json:\"bsd_name\"`\n\t\tIocontent   string `json:\"iocontent\"`\n\t\tSize        string `json:\"size\"`\n\t\tSizeInBytes int    `json:\"size_in_bytes\"`\n\t} `json:\"volumes\"`\n}\n\ntype spnvmeDataWrapper struct {\n\tSPNVMeDataType []struct {\n\t\tItems []spnvmeDataTypeItem `json:\"_items\"`\n\t} `json:\"SPNVMeDataType\"`\n}\n\nfunc SerialNumberWithContext(ctx context.Context, _ string) (string, error) {\n\toutput, err := invoke.CommandWithContext(ctx, \"system_profiler\", \"SPNVMeDataType\", \"-json\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvar data spnvmeDataWrapper\n\tif err := json.Unmarshal(output, &data); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to unmarshal JSON: %w\", err)\n\t}\n\n\t// Extract all serial numbers into a single string\n\tvar serialNumbers []string\n\tfor i := range data.SPNVMeDataType {\n\t\tspnvmeData := &data.SPNVMeDataType[i]\n\t\tfor j := range spnvmeData.Items {\n\t\t\titem := &spnvmeData.Items[j]\n\t\t\tserialNumbers = append(serialNumbers, item.DeviceSerial)\n\t\t}\n\t}\n\n\tif len(serialNumbers) == 0 {\n\t\treturn \"\", errors.New(\"no serial numbers found\")\n\t}\n\n\treturn strings.Join(serialNumbers, \", \"), nil\n}\n\nfunc LabelWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCountersStat, error) {\n\tiokit, err := common.NewIOKitLib()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer iokit.Close()\n\n\tcorefoundation, err := common.NewCoreFoundationLib()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer corefoundation.Close()\n\n\tmatch := iokit.IOServiceMatching(\"IOMedia\")\n\n\tkey := corefoundation.CFStringCreateWithCString(common.KCFAllocatorDefault, common.KIOMediaWholeKey, common.KCFStringEncodingUTF8)\n\tdefer corefoundation.CFRelease(uintptr(key))\n\n\tkCFBooleanTruePtr, _ := corefoundation.Dlsym(\"kCFBooleanTrue\")\n\tkCFBooleanTrue := **(**uintptr)(unsafe.Pointer(&kCFBooleanTruePtr))\n\tcorefoundation.CFDictionaryAddValue(uintptr(match), uintptr(key), kCFBooleanTrue)\n\n\tvar drives uint32\n\tif status := iokit.IOServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(match), &drives); status != common.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"IOServiceGetMatchingServices error=%d\", status)\n\t}\n\tdefer iokit.IOObjectRelease(drives)\n\n\tic := &ioCounters{\n\t\tiokit:          iokit,\n\t\tcorefoundation: corefoundation,\n\t}\n\n\tstats := make([]IOCountersStat, 0, 16)\n\tfor {\n\t\td := iokit.IOIteratorNext(drives)\n\t\tif d <= 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tstat, err := ic.getDriveStat(d)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif stat != nil {\n\t\t\tstats = append(stats, *stat)\n\t\t}\n\n\t\tiokit.IOObjectRelease(d)\n\t}\n\n\tret := make(map[string]IOCountersStat, 0)\n\tfor i := 0; i < len(stats); i++ {\n\t\tif len(names) > 0 && !common.StringsHas(names, stats[i].Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tstats[i].ReadTime = stats[i].ReadTime / 1000 / 1000 // note: read/write time are in ns, but we want ms.\n\t\tstats[i].WriteTime = stats[i].WriteTime / 1000 / 1000\n\t\tstats[i].IoTime = stats[i].ReadTime + stats[i].WriteTime\n\n\t\tret[stats[i].Name] = stats[i]\n\t}\n\n\treturn ret, nil\n}\n\nconst (\n\tkIOBSDNameKey = \"BSD Name\"\n\t// kIOMediaSizeKey               = \"Size\"\n\t// kIOMediaPreferredBlockSizeKey = \"Preferred Block Size\"\n\n\tkIOBlockStorageDriverStatisticsKey               = \"Statistics\"\n\tkIOBlockStorageDriverStatisticsBytesReadKey      = \"Bytes (Read)\"\n\tkIOBlockStorageDriverStatisticsBytesWrittenKey   = \"Bytes (Write)\"\n\tkIOBlockStorageDriverStatisticsReadsKey          = \"Operations (Read)\"\n\tkIOBlockStorageDriverStatisticsWritesKey         = \"Operations (Write)\"\n\tkIOBlockStorageDriverStatisticsTotalReadTimeKey  = \"Total Time (Read)\"\n\tkIOBlockStorageDriverStatisticsTotalWriteTimeKey = \"Total Time (Write)\"\n)\n\ntype ioCounters struct {\n\tiokit          *common.IOKitLib\n\tcorefoundation *common.CoreFoundationLib\n}\n\nfunc (i *ioCounters) getDriveStat(d uint32) (*IOCountersStat, error) {\n\tvar parent uint32\n\tif status := i.iokit.IORegistryEntryGetParentEntry(d, common.KIOServicePlane, &parent); status != common.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"IORegistryEntryGetParentEntry error=%d\", status)\n\t}\n\tdefer i.iokit.IOObjectRelease(parent)\n\n\tif !i.iokit.IOObjectConformsTo(parent, \"IOBlockStorageDriver\") {\n\t\t// return nil, fmt.Errorf(\"ERROR: the object is not of the IOBlockStorageDriver class\")\n\t\treturn nil, nil\n\t}\n\n\tvar props unsafe.Pointer\n\tif status := i.iokit.IORegistryEntryCreateCFProperties(d, unsafe.Pointer(&props), common.KCFAllocatorDefault, common.KNilOptions); status != common.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"IORegistryEntryCreateCFProperties error=%d\", status)\n\t}\n\tdefer i.corefoundation.CFRelease(uintptr(props))\n\n\tkey := i.cfStr(kIOBSDNameKey)\n\tdefer i.corefoundation.CFRelease(uintptr(key))\n\tname := i.corefoundation.CFDictionaryGetValue(uintptr(props), uintptr(key))\n\n\tbuf := common.NewCStr(common.GetCFStringBufLengthForUTF8(i.corefoundation.CFStringGetLength(uintptr(name))))\n\ti.corefoundation.CFStringGetCString(uintptr(name), buf, buf.Length(), common.KCFStringEncodingUTF8)\n\n\tstat, err := i.fillStat(parent)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif stat != nil {\n\t\tstat.Name = buf.GoString()\n\t\treturn stat, nil\n\t}\n\treturn nil, nil\n}\n\nfunc (i *ioCounters) fillStat(d uint32) (*IOCountersStat, error) {\n\tvar props unsafe.Pointer\n\tstatus := i.iokit.IORegistryEntryCreateCFProperties(d, unsafe.Pointer(&props), common.KCFAllocatorDefault, common.KNilOptions)\n\tif status != common.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"IORegistryEntryCreateCFProperties error=%d\", status)\n\t}\n\tif props == nil {\n\t\treturn nil, nil\n\t}\n\tdefer i.corefoundation.CFRelease(uintptr(props))\n\n\tkey := i.cfStr(kIOBlockStorageDriverStatisticsKey)\n\tdefer i.corefoundation.CFRelease(uintptr(key))\n\n\tv := i.corefoundation.CFDictionaryGetValue(uintptr(props), uintptr(key))\n\tif v == nil {\n\t\treturn nil, errors.New(\"CFDictionaryGetValue failed\")\n\t}\n\n\tvar stat IOCountersStat\n\tstatstab := map[string]uintptr{\n\t\tkIOBlockStorageDriverStatisticsBytesReadKey:      unsafe.Offsetof(stat.ReadBytes),\n\t\tkIOBlockStorageDriverStatisticsBytesWrittenKey:   unsafe.Offsetof(stat.WriteBytes),\n\t\tkIOBlockStorageDriverStatisticsReadsKey:          unsafe.Offsetof(stat.ReadCount),\n\t\tkIOBlockStorageDriverStatisticsWritesKey:         unsafe.Offsetof(stat.WriteCount),\n\t\tkIOBlockStorageDriverStatisticsTotalReadTimeKey:  unsafe.Offsetof(stat.ReadTime),\n\t\tkIOBlockStorageDriverStatisticsTotalWriteTimeKey: unsafe.Offsetof(stat.WriteTime),\n\t}\n\n\tfor key, off := range statstab {\n\t\ts := i.cfStr(key)\n\t\tif num := i.corefoundation.CFDictionaryGetValue(uintptr(v), uintptr(s)); num != nil {\n\t\t\ti.corefoundation.CFNumberGetValue(uintptr(num), common.KCFNumberSInt64Type, uintptr(unsafe.Add(unsafe.Pointer(&stat), off)))\n\t\t}\n\t\ti.corefoundation.CFRelease(uintptr(s))\n\t}\n\n\treturn &stat, nil\n}\n\nfunc (i *ioCounters) cfStr(str string) unsafe.Pointer {\n\treturn i.corefoundation.CFStringCreateWithCString(common.KCFAllocatorDefault, str, common.KCFStringEncodingUTF8)\n}\n"
  },
  {
    "path": "disk/disk_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !windows && !solaris && !aix\n\npackage disk\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc IOCountersWithContext(_ context.Context, _ ...string) (map[string]IOCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc PartitionsWithContext(_ context.Context, _ bool) ([]PartitionStat, error) {\n\treturn []PartitionStat{}, common.ErrNotImplementedError\n}\n\nfunc UsageWithContext(_ context.Context, _ string) (*UsageStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc SerialNumberWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc LabelWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "disk/disk_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd\n\npackage disk\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// PartitionsWithContext returns disk partition.\n// 'all' argument is ignored, see: https://github.com/giampaolo/psutil/issues/906\nfunc PartitionsWithContext(_ context.Context, _ bool) ([]PartitionStat, error) {\n\tvar ret []PartitionStat\n\n\t// get length\n\tcount, err := unix.Getfsstat(nil, unix.MNT_WAIT)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tfs := make([]unix.Statfs_t, count)\n\tif _, err = unix.Getfsstat(fs, unix.MNT_WAIT); err != nil {\n\t\treturn ret, err\n\t}\n\n\tfor i := range fs {\n\t\tstat := &fs[i]\n\t\topts := []string{\"rw\"}\n\t\tif stat.Flags&unix.MNT_RDONLY != 0 {\n\t\t\topts = []string{\"ro\"}\n\t\t}\n\t\tif stat.Flags&unix.MNT_SYNCHRONOUS != 0 {\n\t\t\topts = append(opts, \"sync\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOEXEC != 0 {\n\t\t\topts = append(opts, \"noexec\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOSUID != 0 {\n\t\t\topts = append(opts, \"nosuid\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_UNION != 0 {\n\t\t\topts = append(opts, \"union\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_ASYNC != 0 {\n\t\t\topts = append(opts, \"async\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_SUIDDIR != 0 {\n\t\t\topts = append(opts, \"suiddir\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_SOFTDEP != 0 {\n\t\t\topts = append(opts, \"softdep\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOSYMFOLLOW != 0 {\n\t\t\topts = append(opts, \"nosymfollow\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_GJOURNAL != 0 {\n\t\t\topts = append(opts, \"gjournal\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_MULTILABEL != 0 {\n\t\t\topts = append(opts, \"multilabel\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_ACLS != 0 {\n\t\t\topts = append(opts, \"acls\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOATIME != 0 {\n\t\t\topts = append(opts, \"noatime\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOCLUSTERR != 0 {\n\t\t\topts = append(opts, \"noclusterr\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NOCLUSTERW != 0 {\n\t\t\topts = append(opts, \"noclusterw\")\n\t\t}\n\t\tif stat.Flags&unix.MNT_NFS4ACLS != 0 {\n\t\t\topts = append(opts, \"nfsv4acls\")\n\t\t}\n\n\t\td := PartitionStat{\n\t\t\tDevice:     common.ByteToString(stat.Mntfromname[:]),\n\t\t\tMountpoint: common.ByteToString(stat.Mntonname[:]),\n\t\t\tFstype:     common.ByteToString(stat.Fstypename[:]),\n\t\t\tOpts:       opts,\n\t\t}\n\n\t\tret = append(ret, d)\n\t}\n\n\treturn ret, nil\n}\n\nfunc IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {\n\t// statinfo->devinfo->devstat\n\t// /usr/include/devinfo.h\n\tret := make(map[string]IOCountersStat)\n\n\tr, err := unix.Sysctl(\"kern.devstat.all\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuf := []byte(r)\n\tlength := len(buf)\n\n\tcount := int(uint64(length) / uint64(sizeOfdevstat))\n\n\tbuf = buf[8:] // devstat.all has version in the head.\n\t// parse buf to devstat\n\tfor i := 0; i < count; i++ {\n\t\tb := buf[i*sizeOfdevstat : i*sizeOfdevstat+sizeOfdevstat]\n\t\td, err := parsedevstat(b)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tun := strconv.Itoa(int(d.Unit_number))\n\t\tname := common.IntToString(d.Device_name[:]) + un\n\n\t\tif len(names) > 0 && !common.StringsHas(names, name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tds := IOCountersStat{\n\t\t\tReadCount:  d.Operations[devstat_READ],\n\t\t\tWriteCount: d.Operations[devstat_WRITE],\n\t\t\tReadBytes:  d.Bytes[devstat_READ],\n\t\t\tWriteBytes: d.Bytes[devstat_WRITE],\n\t\t\tReadTime:   uint64(d.Duration[devstat_READ].Compute() * 1000),\n\t\t\tWriteTime:  uint64(d.Duration[devstat_WRITE].Compute() * 1000),\n\t\t\tIoTime:     uint64(d.Busy_time.Compute() * 1000),\n\t\t\tName:       name,\n\t\t}\n\t\tds.SerialNumber, _ = SerialNumberWithContext(ctx, name)\n\t\tret[name] = ds\n\t}\n\n\treturn ret, nil\n}\n\nfunc (b bintime) Compute() float64 {\n\tbintimeScale := 5.42101086242752217003726400434970855712890625e-20\n\treturn float64(b.Sec) + float64(b.Frac)*bintimeScale\n}\n\n// BT2LD(time)     ((long double)(time).sec + (time).frac * BINTIME_SCALE)\n\nfunc parsedevstat(buf []byte) (devstat, error) {\n\tvar ds devstat\n\tbr := bytes.NewReader(buf)\n\tif err := binary.Read(br, binary.LittleEndian, &ds); err != nil {\n\t\treturn ds, err\n\t}\n\n\treturn ds, nil\n}\n\nfunc getFsType(stat unix.Statfs_t) string {\n\treturn common.ByteToString(stat.Fstypename[:])\n}\n\nfunc SerialNumberWithContext(ctx context.Context, name string) (string, error) {\n\tgeomOut, err := invoke.CommandWithContext(ctx, \"geom\", \"disk\", \"list\", name)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"exec geom: %w\", err)\n\t}\n\ts := bufio.NewScanner(bytes.NewReader(geomOut))\n\tserial := \"\"\n\tfor s.Scan() {\n\t\tflds := strings.Fields(s.Text())\n\t\tif len(flds) == 2 && flds[0] == \"ident:\" {\n\t\t\tif flds[1] != \"(null)\" {\n\t\t\t\tserial = flds[1]\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\terr = s.Err()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn serial, nil\n}\n\nfunc LabelWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "disk/disk_freebsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_freebsd.go\n\npackage disk\n\nconst (\n\tsizeofPtr        = 0x4\n\tsizeofShort      = 0x2\n\tsizeofInt        = 0x4\n\tsizeofLong       = 0x4\n\tsizeofLongLong   = 0x8\n\tsizeofLongDouble = 0x8\n\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfdevstat = 0xf0\n)\n\ntype (\n\t_C_short       int16\n\t_C_int         int32\n\t_C_long        int32\n\t_C_long_long   int64\n\t_C_long_double int64\n)\n\ntype devstat struct {\n\tSequence0     uint32\n\tAllocated     int32\n\tStart_count   uint32\n\tEnd_count     uint32\n\tBusy_from     bintime\n\tDev_links     _Ctype_struct___0\n\tDevice_number uint32\n\tDevice_name   [16]int8\n\tUnit_number   int32\n\tBytes         [4]uint64\n\tOperations    [4]uint64\n\tDuration      [4]bintime\n\tBusy_time     bintime\n\tCreation_time bintime\n\tBlock_size    uint32\n\tTag_types     [3]uint64\n\tFlags         uint32\n\tDevice_type   uint32\n\tPriority      uint32\n\tId            [sizeofPtr]byte\n\tSequence1     uint32\n}\n\ntype bintime struct {\n\tSec  int32\n\tFrac uint64\n}\n\ntype _Ctype_struct___0 struct {\n\tEmpty uint32\n}\n"
  },
  {
    "path": "disk/disk_freebsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_freebsd.go\n\npackage disk\n\nconst (\n\tsizeofPtr        = 0x8\n\tsizeofShort      = 0x2\n\tsizeofInt        = 0x4\n\tsizeofLong       = 0x8\n\tsizeofLongLong   = 0x8\n\tsizeofLongDouble = 0x8\n\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfdevstat = 0x120\n)\n\ntype (\n\t_C_short       int16\n\t_C_int         int32\n\t_C_long        int64\n\t_C_long_long   int64\n\t_C_long_double int64\n)\n\ntype devstat struct {\n\tSequence0     uint32\n\tAllocated     int32\n\tStart_count   uint32\n\tEnd_count     uint32\n\tBusy_from     bintime\n\tDev_links     _Ctype_struct___0\n\tDevice_number uint32\n\tDevice_name   [16]int8\n\tUnit_number   int32\n\tBytes         [4]uint64\n\tOperations    [4]uint64\n\tDuration      [4]bintime\n\tBusy_time     bintime\n\tCreation_time bintime\n\tBlock_size    uint32\n\tPad_cgo_0     [4]byte\n\tTag_types     [3]uint64\n\tFlags         uint32\n\tDevice_type   uint32\n\tPriority      uint32\n\tPad_cgo_1     [4]byte\n\tID            [sizeofPtr]byte\n\tSequence1     uint32\n\tPad_cgo_2     [4]byte\n}\n\ntype bintime struct {\n\tSec  int64\n\tFrac uint64\n}\n\ntype _Ctype_struct___0 struct {\n\tEmpty uint64\n}\n"
  },
  {
    "path": "disk/disk_freebsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_freebsd.go\n\npackage disk\n\nconst (\n\tsizeofPtr        = 0x4\n\tsizeofShort      = 0x2\n\tsizeofInt        = 0x4\n\tsizeofLong       = 0x4\n\tsizeofLongLong   = 0x8\n\tsizeofLongDouble = 0x8\n\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfdevstat = 0xf0\n)\n\ntype (\n\t_C_short       int16\n\t_C_int         int32\n\t_C_long        int32\n\t_C_long_long   int64\n\t_C_long_double int64\n)\n\ntype devstat struct {\n\tSequence0     uint32\n\tAllocated     int32\n\tStart_count   uint32\n\tEnd_count     uint32\n\tBusy_from     bintime\n\tDev_links     _Ctype_struct___0\n\tDevice_number uint32\n\tDevice_name   [16]int8\n\tUnit_number   int32\n\tBytes         [4]uint64\n\tOperations    [4]uint64\n\tDuration      [4]bintime\n\tBusy_time     bintime\n\tCreation_time bintime\n\tBlock_size    uint32\n\tTag_types     [3]uint64\n\tFlags         uint32\n\tDevice_type   uint32\n\tPriority      uint32\n\tId            [sizeofPtr]byte\n\tSequence1     uint32\n}\n\ntype bintime struct {\n\tSec  int32\n\tFrac uint64\n}\n\ntype _Ctype_struct___0 struct {\n\tEmpty uint32\n}\n"
  },
  {
    "path": "disk/disk_freebsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs disk/types_freebsd.go\n\npackage disk\n\nconst (\n\tsizeofPtr        = 0x8\n\tsizeofShort      = 0x2\n\tsizeofInt        = 0x4\n\tsizeofLong       = 0x8\n\tsizeofLongLong   = 0x8\n\tsizeofLongDouble = 0x8\n\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfdevstat = 0x120\n)\n\ntype (\n\t_C_short       int16\n\t_C_int         int32\n\t_C_long        int64\n\t_C_long_long   int64\n\t_C_long_double int64\n)\n\ntype devstat struct {\n\tSequence0     uint32\n\tAllocated     int32\n\tStart_count   uint32\n\tEnd_count     uint32\n\tBusy_from     bintime\n\tDev_links     _Ctype_struct___0\n\tDevice_number uint32\n\tDevice_name   [16]int8\n\tUnit_number   int32\n\tBytes         [4]uint64\n\tOperations    [4]uint64\n\tDuration      [4]bintime\n\tBusy_time     bintime\n\tCreation_time bintime\n\tBlock_size    uint32\n\tTag_types     [3]uint64\n\tFlags         uint32\n\tDevice_type   uint32\n\tPriority      uint32\n\tId            [sizeofPtr]byte\n\tSequence1     uint32\n\tPad_cgo_0     [4]byte\n}\ntype bintime struct {\n\tSec  int64\n\tFrac uint64\n}\n\ntype _Ctype_struct___0 struct {\n\tEmpty uint64\n}\n"
  },
  {
    "path": "disk/disk_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage disk\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst (\n\tsectorSize = 512\n)\n\nconst (\n\t// man statfs\n\tADFS_SUPER_MAGIC      = 0xadf5\n\tAFFS_SUPER_MAGIC      = 0xADFF\n\tBDEVFS_MAGIC          = 0x62646576\n\tBEFS_SUPER_MAGIC      = 0x42465331\n\tBFS_MAGIC             = 0x1BADFACE\n\tBINFMTFS_MAGIC        = 0x42494e4d\n\tBTRFS_SUPER_MAGIC     = 0x9123683E\n\tCGROUP_SUPER_MAGIC    = 0x27e0eb\n\tCIFS_MAGIC_NUMBER     = 0xFF534D42\n\tCODA_SUPER_MAGIC      = 0x73757245\n\tCOH_SUPER_MAGIC       = 0x012FF7B7\n\tCRAMFS_MAGIC          = 0x28cd3d45\n\tDEBUGFS_MAGIC         = 0x64626720\n\tDEVFS_SUPER_MAGIC     = 0x1373\n\tDEVPTS_SUPER_MAGIC    = 0x1cd1\n\tEFIVARFS_MAGIC        = 0xde5e81e4\n\tEFS_SUPER_MAGIC       = 0x00414A53\n\tEXT_SUPER_MAGIC       = 0x137D\n\tEXT2_OLD_SUPER_MAGIC  = 0xEF51\n\tEXT2_SUPER_MAGIC      = 0xEF53\n\tEXT3_SUPER_MAGIC      = 0xEF53\n\tEXT4_SUPER_MAGIC      = 0xEF53\n\tFUSE_SUPER_MAGIC      = 0x65735546\n\tFUTEXFS_SUPER_MAGIC   = 0xBAD1DEA\n\tHFS_SUPER_MAGIC       = 0x4244\n\tHFSPLUS_SUPER_MAGIC   = 0x482b\n\tHOSTFS_SUPER_MAGIC    = 0x00c0ffee\n\tHPFS_SUPER_MAGIC      = 0xF995E849\n\tHUGETLBFS_MAGIC       = 0x958458f6\n\tISOFS_SUPER_MAGIC     = 0x9660\n\tJFFS2_SUPER_MAGIC     = 0x72b6\n\tJFS_SUPER_MAGIC       = 0x3153464a\n\tMINIX_SUPER_MAGIC     = 0x137F /* orig. minix */\n\tMINIX_SUPER_MAGIC2    = 0x138F /* 30 char minix */\n\tMINIX2_SUPER_MAGIC    = 0x2468 /* minix V2 */\n\tMINIX2_SUPER_MAGIC2   = 0x2478 /* minix V2, 30 char names */\n\tMINIX3_SUPER_MAGIC    = 0x4d5a /* minix V3 fs, 60 char names */\n\tMQUEUE_MAGIC          = 0x19800202\n\tMSDOS_SUPER_MAGIC     = 0x4d44\n\tNCP_SUPER_MAGIC       = 0x564c\n\tNFS_SUPER_MAGIC       = 0x6969\n\tNILFS_SUPER_MAGIC     = 0x3434\n\tNTFS_SB_MAGIC         = 0x5346544e\n\tOCFS2_SUPER_MAGIC     = 0x7461636f\n\tOPENPROM_SUPER_MAGIC  = 0x9fa1\n\tPIPEFS_MAGIC          = 0x50495045\n\tPROC_SUPER_MAGIC      = 0x9fa0\n\tPSTOREFS_MAGIC        = 0x6165676C\n\tQNX4_SUPER_MAGIC      = 0x002f\n\tQNX6_SUPER_MAGIC      = 0x68191122\n\tRAMFS_MAGIC           = 0x858458f6\n\tREISERFS_SUPER_MAGIC  = 0x52654973\n\tROMFS_MAGIC           = 0x7275\n\tSELINUX_MAGIC         = 0xf97cff8c\n\tSMACK_MAGIC           = 0x43415d53\n\tSMB_SUPER_MAGIC       = 0x517B\n\tSOCKFS_MAGIC          = 0x534F434B\n\tSQUASHFS_MAGIC        = 0x73717368\n\tSYSFS_MAGIC           = 0x62656572\n\tSYSV2_SUPER_MAGIC     = 0x012FF7B6\n\tSYSV4_SUPER_MAGIC     = 0x012FF7B5\n\tTMPFS_MAGIC           = 0x01021994\n\tUDF_SUPER_MAGIC       = 0x15013346\n\tUFS_MAGIC             = 0x00011954\n\tUSBDEVICE_SUPER_MAGIC = 0x9fa2\n\tV9FS_MAGIC            = 0x01021997\n\tVXFS_SUPER_MAGIC      = 0xa501FCF5\n\tXENFS_SUPER_MAGIC     = 0xabba1974\n\tXENIX_SUPER_MAGIC     = 0x012FF7B4\n\tXFS_SUPER_MAGIC       = 0x58465342\n\t_XIAFS_SUPER_MAGIC    = 0x012FD16D\n\n\tAFS_SUPER_MAGIC             = 0x5346414F\n\tAUFS_SUPER_MAGIC            = 0x61756673\n\tANON_INODE_FS_SUPER_MAGIC   = 0x09041934\n\tBCACHEFS_SUPER_MAGIC        = 0xCA451A4E\n\tBPF_FS_MAGIC                = 0xCAFE4A11\n\tCEPH_SUPER_MAGIC            = 0x00C36400\n\tCGROUP2_SUPER_MAGIC         = 0x63677270\n\tCONFIGFS_MAGIC              = 0x62656570\n\tECRYPTFS_SUPER_MAGIC        = 0xF15F\n\tF2FS_SUPER_MAGIC            = 0xF2F52010\n\tFAT_SUPER_MAGIC             = 0x4006\n\tFHGFS_SUPER_MAGIC           = 0x19830326\n\tFUSEBLK_SUPER_MAGIC         = 0x65735546\n\tFUSECTL_SUPER_MAGIC         = 0x65735543\n\tGFS_SUPER_MAGIC             = 0x1161970\n\tGPFS_SUPER_MAGIC            = 0x47504653\n\tMTD_INODE_FS_SUPER_MAGIC    = 0x11307854\n\tINOTIFYFS_SUPER_MAGIC       = 0x2BAD1DEA\n\tISOFS_R_WIN_SUPER_MAGIC     = 0x4004\n\tISOFS_WIN_SUPER_MAGIC       = 0x4000\n\tJFFS_SUPER_MAGIC            = 0x07C0\n\tKAFS_SUPER_MAGIC            = 0x6B414653\n\tLUSTRE_SUPER_MAGIC          = 0x0BD00BD0\n\tNFSD_SUPER_MAGIC            = 0x6E667364\n\tNSFS_MAGIC                  = 0x6E736673\n\tPANFS_SUPER_MAGIC           = 0xAAD7AAEA\n\tRPC_PIPEFS_SUPER_MAGIC      = 0x67596969\n\tSECURITYFS_SUPER_MAGIC      = 0x73636673\n\tTRACEFS_MAGIC               = 0x74726163\n\tUFS_BYTESWAPPED_SUPER_MAGIC = 0x54190100\n\tVMHGFS_SUPER_MAGIC          = 0xBACBACBC\n\tVZFS_SUPER_MAGIC            = 0x565A4653\n\tZFS_SUPER_MAGIC             = 0x2FC12FC1\n)\n\n// coreutils/src/stat.c\nvar fsTypeMap = map[int64]string{\n\tADFS_SUPER_MAGIC:          \"adfs\",          /* 0xADF5 local */\n\tAFFS_SUPER_MAGIC:          \"affs\",          /* 0xADFF local */\n\tAFS_SUPER_MAGIC:           \"afs\",           /* 0x5346414F remote */\n\tANON_INODE_FS_SUPER_MAGIC: \"anon-inode FS\", /* 0x09041934 local */\n\tAUFS_SUPER_MAGIC:          \"aufs\",          /* 0x61756673 remote */\n\t//\tAUTOFS_SUPER_MAGIC:          \"autofs\",              /* 0x0187 local */\n\tBCACHEFS_SUPER_MAGIC:        \"bcachefs\",            /* 0xCA451A4E local */\n\tBEFS_SUPER_MAGIC:            \"befs\",                /* 0x42465331 local */\n\tBDEVFS_MAGIC:                \"bdevfs\",              /* 0x62646576 local */\n\tBFS_MAGIC:                   \"bfs\",                 /* 0x1BADFACE local */\n\tBINFMTFS_MAGIC:              \"binfmt_misc\",         /* 0x42494E4D local */\n\tBPF_FS_MAGIC:                \"bpf\",                 /* 0xCAFE4A11 local */\n\tBTRFS_SUPER_MAGIC:           \"btrfs\",               /* 0x9123683E local */\n\tCEPH_SUPER_MAGIC:            \"ceph\",                /* 0x00C36400 remote */\n\tCGROUP_SUPER_MAGIC:          \"cgroupfs\",            /* 0x0027E0EB local */\n\tCGROUP2_SUPER_MAGIC:         \"cgroup2fs\",           /* 0x63677270 local */\n\tCIFS_MAGIC_NUMBER:           \"cifs\",                /* 0xFF534D42 remote */\n\tCODA_SUPER_MAGIC:            \"coda\",                /* 0x73757245 remote */\n\tCOH_SUPER_MAGIC:             \"coh\",                 /* 0x012FF7B7 local */\n\tCONFIGFS_MAGIC:              \"configfs\",            /* 0x62656570 local */\n\tCRAMFS_MAGIC:                \"cramfs\",              /* 0x28CD3D45 local */\n\tDEBUGFS_MAGIC:               \"debugfs\",             /* 0x64626720 local */\n\tDEVFS_SUPER_MAGIC:           \"devfs\",               /* 0x1373 local */\n\tDEVPTS_SUPER_MAGIC:          \"devpts\",              /* 0x1CD1 local */\n\tECRYPTFS_SUPER_MAGIC:        \"ecryptfs\",            /* 0xF15F local */\n\tEFIVARFS_MAGIC:              \"efivarfs\",            /* 0xDE5E81E4 local */\n\tEFS_SUPER_MAGIC:             \"efs\",                 /* 0x00414A53 local */\n\tEXT_SUPER_MAGIC:             \"ext\",                 /* 0x137D local */\n\tEXT2_SUPER_MAGIC:            \"ext2/ext3\",           /* 0xEF53 local */\n\tEXT2_OLD_SUPER_MAGIC:        \"ext2\",                /* 0xEF51 local */\n\tF2FS_SUPER_MAGIC:            \"f2fs\",                /* 0xF2F52010 local */\n\tFAT_SUPER_MAGIC:             \"fat\",                 /* 0x4006 local */\n\tFHGFS_SUPER_MAGIC:           \"fhgfs\",               /* 0x19830326 remote */\n\tFUSEBLK_SUPER_MAGIC:         \"fuseblk\",             /* 0x65735546 remote */\n\tFUSECTL_SUPER_MAGIC:         \"fusectl\",             /* 0x65735543 remote */\n\tFUTEXFS_SUPER_MAGIC:         \"futexfs\",             /* 0x0BAD1DEA local */\n\tGFS_SUPER_MAGIC:             \"gfs/gfs2\",            /* 0x1161970 remote */\n\tGPFS_SUPER_MAGIC:            \"gpfs\",                /* 0x47504653 remote */\n\tHFS_SUPER_MAGIC:             \"hfs\",                 /* 0x4244 local */\n\tHFSPLUS_SUPER_MAGIC:         \"hfsplus\",             /* 0x482b local */\n\tHPFS_SUPER_MAGIC:            \"hpfs\",                /* 0xF995E849 local */\n\tHUGETLBFS_MAGIC:             \"hugetlbfs\",           /* 0x958458F6 local */\n\tMTD_INODE_FS_SUPER_MAGIC:    \"inodefs\",             /* 0x11307854 local */\n\tINOTIFYFS_SUPER_MAGIC:       \"inotifyfs\",           /* 0x2BAD1DEA local */\n\tISOFS_SUPER_MAGIC:           \"isofs\",               /* 0x9660 local */\n\tISOFS_R_WIN_SUPER_MAGIC:     \"isofs\",               /* 0x4004 local */\n\tISOFS_WIN_SUPER_MAGIC:       \"isofs\",               /* 0x4000 local */\n\tJFFS_SUPER_MAGIC:            \"jffs\",                /* 0x07C0 local */\n\tJFFS2_SUPER_MAGIC:           \"jffs2\",               /* 0x72B6 local */\n\tJFS_SUPER_MAGIC:             \"jfs\",                 /* 0x3153464A local */\n\tKAFS_SUPER_MAGIC:            \"k-afs\",               /* 0x6B414653 remote */\n\tLUSTRE_SUPER_MAGIC:          \"lustre\",              /* 0x0BD00BD0 remote */\n\tMINIX_SUPER_MAGIC:           \"minix\",               /* 0x137F local */\n\tMINIX_SUPER_MAGIC2:          \"minix (30 char.)\",    /* 0x138F local */\n\tMINIX2_SUPER_MAGIC:          \"minix v2\",            /* 0x2468 local */\n\tMINIX2_SUPER_MAGIC2:         \"minix v2 (30 char.)\", /* 0x2478 local */\n\tMINIX3_SUPER_MAGIC:          \"minix3\",              /* 0x4D5A local */\n\tMQUEUE_MAGIC:                \"mqueue\",              /* 0x19800202 local */\n\tMSDOS_SUPER_MAGIC:           \"msdos\",               /* 0x4D44 local */\n\tNCP_SUPER_MAGIC:             \"novell\",              /* 0x564C remote */\n\tNFS_SUPER_MAGIC:             \"nfs\",                 /* 0x6969 remote */\n\tNFSD_SUPER_MAGIC:            \"nfsd\",                /* 0x6E667364 remote */\n\tNILFS_SUPER_MAGIC:           \"nilfs\",               /* 0x3434 local */\n\tNSFS_MAGIC:                  \"nsfs\",                /* 0x6E736673 local */\n\tNTFS_SB_MAGIC:               \"ntfs\",                /* 0x5346544E local */\n\tOPENPROM_SUPER_MAGIC:        \"openprom\",            /* 0x9FA1 local */\n\tOCFS2_SUPER_MAGIC:           \"ocfs2\",               /* 0x7461636f remote */\n\tPANFS_SUPER_MAGIC:           \"panfs\",               /* 0xAAD7AAEA remote */\n\tPIPEFS_MAGIC:                \"pipefs\",              /* 0x50495045 remote */\n\tPROC_SUPER_MAGIC:            \"proc\",                /* 0x9FA0 local */\n\tPSTOREFS_MAGIC:              \"pstorefs\",            /* 0x6165676C local */\n\tQNX4_SUPER_MAGIC:            \"qnx4\",                /* 0x002F local */\n\tQNX6_SUPER_MAGIC:            \"qnx6\",                /* 0x68191122 local */\n\tRAMFS_MAGIC:                 \"ramfs\",               /* 0x858458F6 local */\n\tREISERFS_SUPER_MAGIC:        \"reiserfs\",            /* 0x52654973 local */\n\tROMFS_MAGIC:                 \"romfs\",               /* 0x7275 local */\n\tRPC_PIPEFS_SUPER_MAGIC:      \"rpc_pipefs\",          /* 0x67596969 local */\n\tSECURITYFS_SUPER_MAGIC:      \"securityfs\",          /* 0x73636673 local */\n\tSELINUX_MAGIC:               \"selinux\",             /* 0xF97CFF8C local */\n\tSMB_SUPER_MAGIC:             \"smb\",                 /* 0x517B remote */\n\tSOCKFS_MAGIC:                \"sockfs\",              /* 0x534F434B local */\n\tSQUASHFS_MAGIC:              \"squashfs\",            /* 0x73717368 local */\n\tSYSFS_MAGIC:                 \"sysfs\",               /* 0x62656572 local */\n\tSYSV2_SUPER_MAGIC:           \"sysv2\",               /* 0x012FF7B6 local */\n\tSYSV4_SUPER_MAGIC:           \"sysv4\",               /* 0x012FF7B5 local */\n\tTMPFS_MAGIC:                 \"tmpfs\",               /* 0x01021994 local */\n\tTRACEFS_MAGIC:               \"tracefs\",             /* 0x74726163 local */\n\tUDF_SUPER_MAGIC:             \"udf\",                 /* 0x15013346 local */\n\tUFS_MAGIC:                   \"ufs\",                 /* 0x00011954 local */\n\tUFS_BYTESWAPPED_SUPER_MAGIC: \"ufs\",                 /* 0x54190100 local */\n\tUSBDEVICE_SUPER_MAGIC:       \"usbdevfs\",            /* 0x9FA2 local */\n\tV9FS_MAGIC:                  \"v9fs\",                /* 0x01021997 local */\n\tVMHGFS_SUPER_MAGIC:          \"vmhgfs\",              /* 0xBACBACBC remote */\n\tVXFS_SUPER_MAGIC:            \"vxfs\",                /* 0xA501FCF5 local */\n\tVZFS_SUPER_MAGIC:            \"vzfs\",                /* 0x565A4653 local */\n\tXENFS_SUPER_MAGIC:           \"xenfs\",               /* 0xABBA1974 local */\n\tXENIX_SUPER_MAGIC:           \"xenix\",               /* 0x012FF7B4 local */\n\tXFS_SUPER_MAGIC:             \"xfs\",                 /* 0x58465342 local */\n\t_XIAFS_SUPER_MAGIC:          \"xia\",                 /* 0x012FD16D local */\n\tZFS_SUPER_MAGIC:             \"zfs\",                 /* 0x2FC12FC1 local */\n}\n\n// readMountFile reads mountinfo or mounts file under the specified root path\n// (eg, /proc/1, /proc/self, etc)\nfunc readMountFile(root string) (lines []string, useMounts bool, filename string, err error) {\n\tfilename = path.Join(root, \"mountinfo\")\n\tlines, err = common.ReadLines(filename)\n\tif err != nil {\n\t\tvar pathErr *os.PathError\n\t\tif !errors.As(err, &pathErr) {\n\t\t\treturn lines, useMounts, filename, err\n\t\t}\n\t\t// if kernel does not support 1/mountinfo, fallback to 1/mounts (<2.6.26)\n\t\tuseMounts = true\n\t\tfilename = path.Join(root, \"mounts\")\n\t\tlines, err = common.ReadLines(filename)\n\t\tif err != nil {\n\t\t\treturn lines, useMounts, filename, err\n\t\t}\n\t\treturn lines, useMounts, filename, err\n\t}\n\treturn lines, useMounts, filename, err\n}\n\nfunc PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, error) {\n\t// by default, try \"/proc/1/...\" first\n\troot := common.HostProcWithContext(ctx, path.Join(\"1\"))\n\n\t// force preference for dirname of HOST_PROC_MOUNTINFO, if set  #1271\n\thpmPath := common.HostProcMountInfoWithContext(ctx)\n\tif hpmPath != \"\" {\n\t\troot = filepath.Dir(hpmPath)\n\t}\n\n\tlines, useMounts, filename, err := readMountFile(root)\n\tif err != nil {\n\t\tif hpmPath != \"\" { // don't fallback with HOST_PROC_MOUNTINFO\n\t\t\treturn nil, err\n\t\t}\n\t\t// fallback to \"/proc/self/...\"  #1159\n\t\tlines, useMounts, filename, err = readMountFile(common.HostProcWithContext(ctx, path.Join(\"self\")))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tfs, err := getFileSystems(ctx)\n\tif err != nil && !all {\n\t\treturn nil, err\n\t}\n\n\tvar ret []PartitionStat\n\tif useMounts { // use mounts file\n\t\tret = parseFieldsOnMounts(lines, all, fs)\n\t\treturn ret, nil\n\t}\n\n\t// use mountinfo\n\tret, err = parseFieldsOnMountinfo(ctx, lines, all, filename)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing mountinfo file %s: %w\", filename, err)\n\t}\n\n\treturn ret, nil\n}\n\nfunc parseFieldsOnMounts(lines []string, all bool, fs []string) []PartitionStat {\n\tret := make([]PartitionStat, 0, len(lines))\n\tfor _, line := range lines {\n\t\tfields := strings.Fields(line)\n\n\t\td := PartitionStat{\n\t\t\tDevice:     fields[0],\n\t\t\tMountpoint: unescapeFstab(fields[1]),\n\t\t\tFstype:     fields[2],\n\t\t\tOpts:       strings.Split(fields[3], \",\"),\n\t\t}\n\n\t\tif !all {\n\t\t\tif d.Device == \"none\" || !common.StringsHas(fs, d.Fstype) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tret = append(ret, d)\n\t}\n\n\treturn ret\n}\n\nfunc parseFieldsOnMountinfo(ctx context.Context, lines []string, all bool, filename string) ([]PartitionStat, error) {\n\tret := make([]PartitionStat, 0, len(lines))\n\tseenDevIDs := make(map[string]string)\n\n\tfor _, line := range lines {\n\t\t// See proc_pid_mountinfo(5) (proc(5) on EL)\n\t\t// A line of <filename> (<procfs root>/<pid>/mountinfo) has the following structure:\n\t\t//\t36  35  98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue\n\t\t//\t(1) (2) (3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)\n\t\t// Documentation is unclear if (6) is optional/may not be present, so it is conditionally parsed if present.\n\t\t// (7) is optional and may not be present, but this function does not currently use it.\n\t\t// Documentation is unclear if (11) is optional or not but this function does not currently use it.\n\n\t\t// split the mountinfo line by the separator hyphen (`(8)` above)\n\t\tparts := strings.SplitN(line, \" - \", 2)\n\t\tif len(parts) != 2 {\n\t\t\treturn nil, fmt.Errorf(\"found invalid mountinfo line in file %s (bad parts len): %s \", filename, line)\n\t\t}\n\n\t\tfields := strings.Fields(parts[0])\n\t\tif len(fields) < 5 { // field (7) is optional, field (6) may(?) be optional\n\t\t\treturn nil, fmt.Errorf(\"found invalid mountinfo line in file %s (bad fields(1) len): %s \", filename, line)\n\t\t}\n\t\tblockDeviceID := fields[2]\n\t\trootDir := fields[3]\n\t\tmountPoint := fields[4]\n\t\tmountOpts := []string{}\n\t\tif len(fields) >= 6 {\n\t\t\tmountOpts = strings.Split(fields[5], \",\")\n\t\t}\n\t\tfields = strings.Fields(parts[1])\n\t\tif len(fields) < 2 {\n\t\t\treturn nil, fmt.Errorf(\"found invalid mountinfo line in file %s (bad fields(2) len): %s \", filename, line)\n\t\t}\n\t\tfsType := fields[0]\n\t\tmntSrc := fields[1]\n\t\tisBind := false\n\t\t// Per fstab(5), the device can be any string for non-storage-backed filesystems.\n\t\tif !all && !strings.HasPrefix(mntSrc, \"/\") {\n\t\t\tcontinue\n\t\t}\n\t\t// Some virtual/non-storage filesystems do still have real sources (e.g. nsfs binds),\n\t\t// but need to use the \"root\" field (field 4) instead of the \"source\" field (field 10).\n\t\t// The \"source\" field is actually \"*filesystem-specific\" information\".\n\t\tdevice := rootDir\n\t\tif strings.HasPrefix(mntSrc, \"/\") {\n\t\t\tdevice = mntSrc\n\t\t} else if rootDir == \"/\" {\n\t\t\tdevice = mntSrc\n\t\t}\n\n\t\t// Track device paths by block device ID to resolve bind mounts.\n\t\t// A bind mount is identified by rootDir != \"/\" (mounting a subdirectory of a filesystem).\n\t\t// Only apply bind detection for storage-backed filesystems (mntSrc starts with \"/\"),\n\t\t// since virtual filesystems (e.g. nsfs) use rootDir for non-path identifiers.\n\t\tif firstDev, ok := seenDevIDs[blockDeviceID]; ok {\n\t\t\t// Same block device seen before - use the original device path.\n\t\t\tdevice = firstDev\n\t\t}\n\t\tif strings.HasPrefix(mntSrc, \"/\") && rootDir != \"/\" {\n\t\t\tisBind = true\n\t\t\tmountOpts = append(mountOpts, \"bind\")\n\t\t}\n\t\tif _, ok := seenDevIDs[blockDeviceID]; !ok {\n\t\t\tseenDevIDs[blockDeviceID] = device\n\t\t}\n\n\t\tif !all && isBind {\n\t\t\tcontinue\n\t\t}\n\n\t\td := PartitionStat{\n\t\t\tDevice:     device,\n\t\t\tMountpoint: unescapeFstab(mountPoint),\n\t\t\tFstype:     fsType,\n\t\t\tOpts:       mountOpts,\n\t\t}\n\n\t\tif strings.HasPrefix(d.Device, \"/dev/mapper/\") {\n\t\t\tdevpath, err := filepath.EvalSymlinks(common.HostDevWithContext(ctx, strings.Replace(d.Device, \"/dev\", \"\", 1)))\n\t\t\tif err == nil {\n\t\t\t\td.Device = devpath\n\t\t\t}\n\t\t}\n\n\t\t// /dev/root is not the real device name\n\t\t// so we get the real device name from its major/minor number\n\t\tif d.Device == \"/dev/root\" {\n\t\t\tdevpath, err := os.Readlink(common.HostSysWithContext(ctx, \"/dev/block/\"+blockDeviceID))\n\t\t\tif err == nil {\n\t\t\t\td.Device = strings.Replace(d.Device, \"root\", filepath.Base(devpath), 1)\n\t\t\t}\n\t\t}\n\t\tret = append(ret, d)\n\t}\n\treturn ret, nil\n}\n\n// getFileSystems returns supported filesystems from /proc/filesystems\nfunc getFileSystems(ctx context.Context) ([]string, error) {\n\tfilename := common.HostProcWithContext(ctx, \"filesystems\")\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar ret []string\n\tfor _, line := range lines {\n\t\tif !strings.HasPrefix(line, \"nodev\") {\n\t\t\tret = append(ret, strings.TrimSpace(line))\n\t\t\tcontinue\n\t\t}\n\t\tt := strings.Split(line, \"\\t\")\n\t\tif len(t) != 2 || t[1] != \"zfs\" {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, strings.TrimSpace(t[1]))\n\t}\n\n\treturn ret, nil\n}\n\nfunc IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {\n\tfilename := common.HostProcWithContext(ctx, \"diskstats\")\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := make(map[string]IOCountersStat)\n\tempty := IOCountersStat{}\n\n\t// use only basename such as \"/dev/sda1\" to \"sda1\"\n\tfor i, name := range names {\n\t\tnames[i] = filepath.Base(name)\n\t}\n\n\tfor _, line := range lines {\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) < 14 {\n\t\t\t// malformed line in /proc/diskstats, avoid panic by ignoring.\n\t\t\tcontinue\n\t\t}\n\t\tname := fields[2]\n\n\t\tif len(names) > 0 && !common.StringsHas(names, name) {\n\t\t\tcontinue\n\t\t}\n\n\t\treads, err := strconv.ParseUint((fields[3]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tmergedReads, err := strconv.ParseUint((fields[4]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\trbytes, err := strconv.ParseUint((fields[5]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\trtime, err := strconv.ParseUint((fields[6]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\twrites, err := strconv.ParseUint((fields[7]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tmergedWrites, err := strconv.ParseUint((fields[8]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\twbytes, err := strconv.ParseUint((fields[9]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\twtime, err := strconv.ParseUint((fields[10]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tiopsInProgress, err := strconv.ParseUint((fields[11]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tiotime, err := strconv.ParseUint((fields[12]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tweightedIO, err := strconv.ParseUint((fields[13]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\td := IOCountersStat{\n\t\t\tReadBytes:        rbytes * sectorSize,\n\t\t\tWriteBytes:       wbytes * sectorSize,\n\t\t\tReadCount:        reads,\n\t\t\tWriteCount:       writes,\n\t\t\tMergedReadCount:  mergedReads,\n\t\t\tMergedWriteCount: mergedWrites,\n\t\t\tReadTime:         rtime,\n\t\t\tWriteTime:        wtime,\n\t\t\tIopsInProgress:   iopsInProgress,\n\t\t\tIoTime:           iotime,\n\t\t\tWeightedIO:       weightedIO,\n\t\t}\n\t\tif d == empty {\n\t\t\tcontinue\n\t\t}\n\t\td.Name = name\n\n\t\t// Names passed in can be full paths (/dev/sda) or just device names (sda).\n\t\t// Since `name` here is already a basename, re-add the /dev path.\n\t\t// This is not ideal, but we may break the API by changing how SerialNumberWithContext\n\t\t// works.\n\t\tdeviceName := getDeviceName(name)\n\t\td.SerialNumber, _ = SerialNumberWithContext(ctx, common.HostDevWithContext(ctx, deviceName))\n\t\td.Label, _ = LabelWithContext(ctx, deviceName)\n\n\t\tret[name] = d\n\t}\n\treturn ret, nil\n}\n\nfunc udevData(ctx context.Context, major, minor uint32, name string) (string, error) {\n\tudevDataPath := common.HostRunWithContext(ctx, fmt.Sprintf(\"udev/data/b%d:%d\", major, minor))\n\tif f, err := os.Open(udevDataPath); err == nil {\n\t\tdefer f.Close()\n\t\tscanner := bufio.NewScanner(f)\n\t\tfor scanner.Scan() {\n\t\t\tvalues := strings.SplitN(scanner.Text(), \"=\", 3)\n\t\t\tif len(values) == 2 && values[0] == name {\n\t\t\t\treturn values[1], nil\n\t\t\t}\n\t\t}\n\t\treturn \"\", scanner.Err()\n\t} else if !os.IsNotExist(err) {\n\t\treturn \"\", err\n\t}\n\treturn \"\", nil\n}\n\nfunc SerialNumberWithContext(ctx context.Context, name string) (string, error) {\n\tvar stat unix.Stat_t\n\tif err := unix.Stat(name, &stat); err != nil {\n\t\treturn \"\", err\n\t}\n\tmajor := unix.Major(uint64(stat.Rdev))\n\tminor := unix.Minor(uint64(stat.Rdev))\n\n\tsserial, _ := udevData(ctx, major, minor, \"E:ID_SERIAL\")\n\tif sserial != \"\" {\n\t\treturn sserial, nil\n\t}\n\n\t// Try to get the serial from sysfs, look at the disk device (minor 0) directly\n\t// because if it is a partition it is not going to contain any device information\n\tdevicePath := common.HostSysWithContext(ctx, fmt.Sprintf(\"dev/block/%d:0/device\", major))\n\tmodel, _ := os.ReadFile(filepath.Join(devicePath, \"model\"))\n\tserial, _ := os.ReadFile(filepath.Join(devicePath, \"serial\"))\n\tif len(model) > 0 && len(serial) > 0 {\n\t\treturn fmt.Sprintf(\"%s_%s\", string(model), string(serial)), nil\n\t}\n\treturn \"\", nil\n}\n\nfunc LabelWithContext(ctx context.Context, name string) (string, error) {\n\t// Try label based on devicemapper name\n\tdmnameFilename := common.HostSysWithContext(ctx, fmt.Sprintf(\"block/%s/dm/name\", name))\n\t// Could errors.Join errs with Go >= 1.20\n\tif common.PathExists(dmnameFilename) {\n\t\tdmname, err := os.ReadFile(dmnameFilename)\n\t\tif err == nil {\n\t\t\treturn strings.TrimSpace(string(dmname)), nil\n\t\t}\n\t}\n\t// Try udev data\n\tvar stat unix.Stat_t\n\tif err := unix.Stat(common.HostDevWithContext(ctx, name), &stat); err != nil {\n\t\treturn \"\", err\n\t}\n\tmajor := unix.Major(uint64(stat.Rdev))\n\tminor := unix.Minor(uint64(stat.Rdev))\n\n\tlabel, err := udevData(ctx, major, minor, \"E:ID_FS_LABEL\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn label, nil\n}\n\nfunc getFsType(stat unix.Statfs_t) string {\n\tt := int64(stat.Type)\n\tret, ok := fsTypeMap[t]\n\tif !ok {\n\t\treturn \"\"\n\t}\n\treturn ret\n}\n\n// getDeviceName normalizes NVMe device names by converting controller notation\n// from diskstats format (nvmeXcYnZ) to actual device format (nvmeXnZ).\n// This handles the discrepancy where /proc/diskstats reports nvmeXcYnZ\n// but actual device files exist as /dev/nvmeXnZ.\nfunc getDeviceName(name string) string {\n\tif !strings.HasPrefix(name, \"nvme\") {\n\t\treturn name\n\t}\n\n\t// Look for controller notation pattern: nvmeXcYnZ\n\tif cIdx := strings.Index(name, \"c\"); cIdx > 4 { // \"nvme\" is 4 chars\n\t\tif nIdx := strings.Index(name[cIdx:], \"n\"); nIdx > 0 {\n\t\t\t// Convert nvmeXcYnZ to nvmeXnZ by removing \"cY\" part\n\t\t\treturn name[:cIdx] + name[cIdx+nIdx:]\n\t\t}\n\t}\n\n\treturn name\n}\n"
  },
  {
    "path": "disk/disk_linux_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage disk\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test_parseFieldsOnMountinfo(t *testing.T) {\n\tlines := []string{\n\t\t\"05   2 9:126 /           /              rw,noatime                      shared:1   - ext4  /dev/sda1 rw\",\n\t\t\"06   3 9:127 /           /foo           rw,noatime                      shared:1   - ext4  /dev/sda2 rw\",\n\t\t\"07   3 9:127 /bar        /foo/bar       rw,noatime                      shared:1   - ext4  /dev/sda2 rw\", // \"bind mount\" on /foo\n\t\t\"22  13 0:19  /           /dev/shm       rw,nosuid,nodev,noexec,relatime            - tmpfs -         rw\",\n\t\t\"37  29  0:4  net:[12345] /run/netns/foo rw                              shared:552 - nsfs  nsfs      rw\",\n\t\t\"111 80 0:22  /           /sys           rw,nosuid,nodev,noexec,noatime  shared:15  - sysfs sysfs     rw\",\n\t\t\"114 80 0:61  /           /run           rw,nosuid,nodev                 shared:18  - tmpfs none      rw,mode=755\",\n\t}\n\n\tcases := map[string]struct {\n\t\tall    bool\n\t\texpect []PartitionStat\n\t}{\n\t\t\"all\": {\n\t\t\tall: true,\n\t\t\texpect: []PartitionStat{\n\t\t\t\t{Device: \"/dev/sda1\", Mountpoint: \"/\", Fstype: \"ext4\", Opts: []string{\"rw\", \"noatime\"}},\n\t\t\t\t{Device: \"/dev/sda2\", Mountpoint: \"/foo\", Fstype: \"ext4\", Opts: []string{\"rw\", \"noatime\"}},\n\t\t\t\t{Device: \"/dev/sda2\", Mountpoint: \"/foo/bar\", Fstype: \"ext4\", Opts: []string{\"rw\", \"noatime\", \"bind\"}},\n\t\t\t\t{Device: \"-\", Mountpoint: \"/dev/shm\", Fstype: \"tmpfs\", Opts: []string{\"rw\", \"nosuid\", \"nodev\", \"noexec\", \"relatime\"}},\n\t\t\t\t{Device: \"net:[12345]\", Mountpoint: \"/run/netns/foo\", Fstype: \"nsfs\", Opts: []string{\"rw\"}},\n\t\t\t\t{Device: \"sysfs\", Mountpoint: \"/sys\", Fstype: \"sysfs\", Opts: []string{\"rw\", \"nosuid\", \"nodev\", \"noexec\", \"noatime\"}},\n\t\t\t\t{Device: \"none\", Mountpoint: \"/run\", Fstype: \"tmpfs\", Opts: []string{\"rw\", \"nosuid\", \"nodev\"}},\n\t\t\t},\n\t\t},\n\t\t\"not all\": {\n\t\t\tall: false,\n\t\t\texpect: []PartitionStat{\n\t\t\t\t{Device: \"/dev/sda1\", Mountpoint: \"/\", Fstype: \"ext4\", Opts: []string{\"rw\", \"noatime\"}},\n\t\t\t\t{Device: \"/dev/sda2\", Mountpoint: \"/foo\", Fstype: \"ext4\", Opts: []string{\"rw\", \"noatime\"}},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor name, c := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tactual, err := parseFieldsOnMountinfo(context.Background(), lines, c.all, \"\")\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, c.expect, actual)\n\t\t})\n\t}\n}\n\nfunc Test_parseFieldsOnMountinfo_multiMount(t *testing.T) {\n\t// Reproduces issue #2005: same block device (259:4) mounted multiple times\n\t// with different rootDirs. Bind mounts should be detected by rootDir != \"/\",\n\t// not by whether the device ID was seen before.\n\tlines := []string{\n\t\t\"1204 1184 259:4 /var/lib/kubelet/pods/abc/volumes/tmp     /tmp               rw,relatime shared:1 - ext4 /dev/nvme0n1p3 rw\",\n\t\t\"1205 1184 259:4 /var/lib/kubelet/pods/abc/volumes/config  /etc/datadog-agent rw,relatime shared:1 - ext4 /dev/nvme0n1p3 rw\",\n\t\t\"1209 1184 259:4 /etc/passwd                               /etc/passwd        ro,relatime shared:1 - ext4 /dev/nvme0n1p3 rw\",\n\t\t\"1210 1184 259:4 /                                         /host/root         ro,relatime shared:1 - ext4 /dev/nvme0n1p3 rw\",\n\t}\n\n\tactual, err := parseFieldsOnMountinfo(context.Background(), lines, true, \"\")\n\trequire.NoError(t, err)\n\n\texpected := []PartitionStat{\n\t\t{Device: \"/dev/nvme0n1p3\", Mountpoint: \"/tmp\", Fstype: \"ext4\", Opts: []string{\"rw\", \"relatime\", \"bind\"}},\n\t\t{Device: \"/dev/nvme0n1p3\", Mountpoint: \"/etc/datadog-agent\", Fstype: \"ext4\", Opts: []string{\"rw\", \"relatime\", \"bind\"}},\n\t\t{Device: \"/dev/nvme0n1p3\", Mountpoint: \"/etc/passwd\", Fstype: \"ext4\", Opts: []string{\"ro\", \"relatime\", \"bind\"}},\n\t\t{Device: \"/dev/nvme0n1p3\", Mountpoint: \"/host/root\", Fstype: \"ext4\", Opts: []string{\"ro\", \"relatime\"}},\n\t}\n\tassert.Equal(t, expected, actual)\n}\n\nfunc Test_parseFieldsOnMounts(t *testing.T) {\n\tfs := []string{\"sysfs\", \"tmpfs\"}\n\n\tlines := []string{\n\t\t\"sysfs /sys sysfs rw,nosuid,nodev,noexec,noatime 0 0\",\n\t\t\"none /run tmpfs rw,nosuid,nodev,mode=755 0 0\",\n\t}\n\n\tcases := map[string]struct {\n\t\tall    bool\n\t\texpect []PartitionStat\n\t}{\n\t\t\"all\": {\n\t\t\tall: true,\n\t\t\texpect: []PartitionStat{\n\t\t\t\t{Device: \"sysfs\", Mountpoint: \"/sys\", Fstype: \"sysfs\", Opts: []string{\"rw\", \"nosuid\", \"nodev\", \"noexec\", \"noatime\"}},\n\t\t\t\t{Device: \"none\", Mountpoint: \"/run\", Fstype: \"tmpfs\", Opts: []string{\"rw\", \"nosuid\", \"nodev\", \"mode=755\"}},\n\t\t\t},\n\t\t},\n\t\t\"not all\": {\n\t\t\tall: false,\n\t\t\texpect: []PartitionStat{\n\t\t\t\t{Device: \"sysfs\", Mountpoint: \"/sys\", Fstype: \"sysfs\", Opts: []string{\"rw\", \"nosuid\", \"nodev\", \"noexec\", \"noatime\"}},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor name, c := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tactual := parseFieldsOnMounts(lines, c.all, fs)\n\t\t\tassert.Equal(t, c.expect, actual)\n\t\t})\n\t}\n}\n\nfunc TestGetDeviceName(t *testing.T) {\n\ttestCases := []struct {\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t// Controller notation conversion\n\t\t{\"nvme0c0n1\", \"nvme0n1\"},\n\t\t{\"nvme10c23n1\", \"nvme10n1\"},\n\t\t{\"nvme5c5n2\", \"nvme5n2\"},\n\n\t\t// Controller and partition together\n\t\t{\"nvme0c0n1p1\", \"nvme0n1p1\"},\n\t\t{\"nvme2c2n1p2\", \"nvme2n1p2\"},\n\t\t{\"nvme10c23n1p3\", \"nvme10n1p3\"},\n\n\t\t// Should NOT be changed\n\t\t{\"nvme0n1\", \"nvme0n1\"},     // standard notation\n\t\t{\"nvme0n1p1\", \"nvme0n1p1\"}, // partition\n\t\t{\"sda\", \"sda\"},             // non-nvme\n\t\t{\"nvme5\", \"nvme5\"},         // incomplete\n\t\t{\"nvme0c0\", \"nvme0c0\"},     // no namespace\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.input, func(t *testing.T) {\n\t\t\tactual := getDeviceName(tc.input)\n\t\t\tassert.Equal(t, tc.expected, actual)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "disk/disk_netbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build netbsd\n\npackage disk\n\nimport (\n\t\"context\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst (\n\t// see sys/fstypes.h and `man 5 statvfs`\n\tMNT_RDONLY      = 0x00000001 /* read only filesystem */\n\tMNT_SYNCHRONOUS = 0x00000002 /* file system written synchronously */\n\tMNT_NOEXEC      = 0x00000004 /* can't exec from filesystem */\n\tMNT_NOSUID      = 0x00000008 /* don't honor setuid bits on fs */\n\tMNT_NODEV       = 0x00000010 /* don't interpret special files */\n\tMNT_ASYNC       = 0x00000040 /* file system written asynchronously */\n\tMNT_NOATIME     = 0x04000000 /* Never update access times in fs */\n\tMNT_SOFTDEP     = 0x80000000 /* Use soft dependencies */\n)\n\nfunc PartitionsWithContext(_ context.Context, _ bool) ([]PartitionStat, error) {\n\tvar ret []PartitionStat\n\n\tflag := uint64(1) // ST_WAIT/MNT_WAIT, see sys/fstypes.h\n\n\t// get required buffer size\n\temptyBufSize := 0\n\tr, _, err := unix.Syscall(\n\t\t483, // SYS___getvfsstat90 syscall\n\t\tuintptr(unsafe.Pointer(nil)),\n\t\tuintptr(unsafe.Pointer(&emptyBufSize)),\n\t\tuintptr(unsafe.Pointer(&flag)),\n\t)\n\tif err != 0 {\n\t\treturn ret, err\n\t}\n\tmountedFsCount := uint64(r)\n\n\t// calculate the buffer size\n\tbufSize := sizeOfStatvfs * mountedFsCount\n\tbuf := make([]Statvfs, mountedFsCount)\n\n\t// request again to get desired mount data\n\t_, _, err = unix.Syscall(\n\t\t483, // SYS___getvfsstat90 syscall\n\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\tuintptr(unsafe.Pointer(&bufSize)),\n\t\tuintptr(unsafe.Pointer(&flag)),\n\t)\n\tif err != 0 {\n\t\treturn ret, err\n\t}\n\n\tfor i := range buf {\n\t\tstat := &buf[i]\n\t\topts := []string{\"rw\"}\n\t\tif stat.Flag&MNT_RDONLY != 0 {\n\t\t\topts = []string{\"rw\"}\n\t\t}\n\t\tif stat.Flag&MNT_SYNCHRONOUS != 0 {\n\t\t\topts = append(opts, \"sync\")\n\t\t}\n\t\tif stat.Flag&MNT_NOEXEC != 0 {\n\t\t\topts = append(opts, \"noexec\")\n\t\t}\n\t\tif stat.Flag&MNT_NOSUID != 0 {\n\t\t\topts = append(opts, \"nosuid\")\n\t\t}\n\t\tif stat.Flag&MNT_NODEV != 0 {\n\t\t\topts = append(opts, \"nodev\")\n\t\t}\n\t\tif stat.Flag&MNT_ASYNC != 0 {\n\t\t\topts = append(opts, \"async\")\n\t\t}\n\t\tif stat.Flag&MNT_SOFTDEP != 0 {\n\t\t\topts = append(opts, \"softdep\")\n\t\t}\n\t\tif stat.Flag&MNT_NOATIME != 0 {\n\t\t\topts = append(opts, \"noatime\")\n\t\t}\n\n\t\td := PartitionStat{\n\t\t\tDevice:     common.ByteToString([]byte(stat.Mntfromname[:])),\n\t\t\tMountpoint: common.ByteToString([]byte(stat.Mntonname[:])),\n\t\t\tFstype:     common.ByteToString([]byte(stat.Fstypename[:])),\n\t\t\tOpts:       opts,\n\t\t}\n\n\t\tret = append(ret, d)\n\t}\n\n\treturn ret, nil\n}\n\nfunc IOCountersWithContext(_ context.Context, _ ...string) (map[string]IOCountersStat, error) {\n\tret := make(map[string]IOCountersStat)\n\treturn ret, common.ErrNotImplementedError\n}\n\nfunc UsageWithContext(_ context.Context, path string) (*UsageStat, error) {\n\tstat := Statvfs{}\n\tflag := uint64(1) // ST_WAIT/MNT_WAIT, see sys/fstypes.h\n\n\t_path, e := unix.BytePtrFromString(path)\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\n\t_, _, err := unix.Syscall(\n\t\t484, // SYS___statvfs190, see sys/syscall.h\n\t\tuintptr(unsafe.Pointer(_path)),\n\t\tuintptr(unsafe.Pointer(&stat)),\n\t\tuintptr(unsafe.Pointer(&flag)),\n\t)\n\tif err != 0 {\n\t\treturn nil, err\n\t}\n\n\t// frsize is the real block size on NetBSD. See discuss here: https://bugzilla.samba.org/show_bug.cgi?id=11810\n\tbsize := stat.Frsize\n\tret := &UsageStat{\n\t\tPath:        path,\n\t\tFstype:      getFsType(stat),\n\t\tTotal:       (uint64(stat.Blocks) * uint64(bsize)),\n\t\tFree:        (uint64(stat.Bavail) * uint64(bsize)),\n\t\tInodesTotal: (uint64(stat.Files)),\n\t\tInodesFree:  (uint64(stat.Ffree)),\n\t}\n\n\tret.InodesUsed = (ret.InodesTotal - ret.InodesFree)\n\tret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0\n\tret.Used = (uint64(stat.Blocks) - uint64(stat.Bfree)) * uint64(bsize)\n\tret.UsedPercent = (float64(ret.Used) / float64(ret.Total)) * 100.0\n\n\treturn ret, nil\n}\n\nfunc getFsType(stat Statvfs) string {\n\treturn common.ByteToString(stat.Fstypename[:])\n}\n\nfunc SerialNumberWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc LabelWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "disk/disk_netbsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build netbsd && amd64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs types_netbsd.go\n\npackage disk\n\nconst (\n\tsizeOfStatvfs = 0xce0\n)\n\ntype (\n\tStatvfs struct {\n\t\tFlag         uint64\n\t\tBsize        uint64\n\t\tFrsize       uint64\n\t\tIosize       uint64\n\t\tBlocks       uint64\n\t\tBfree        uint64\n\t\tBavail       uint64\n\t\tBresvd       uint64\n\t\tFiles        uint64\n\t\tFfree        uint64\n\t\tFavail       uint64\n\t\tFresvd       uint64\n\t\tSyncreads    uint64\n\t\tSyncwrites   uint64\n\t\tAsyncreads   uint64\n\t\tAsyncwrites  uint64\n\t\tFsidx        _Ctype_struct___0\n\t\tFsid         uint64\n\t\tNamemax      uint64\n\t\tOwner        uint32\n\t\tSpare        [4]uint64\n\t\tFstypename   [32]uint8\n\t\tMntonname    [1024]uint8\n\t\tMntfromname  [1024]uint8\n\t\tMntfromlabel [1024]uint8\n\t}\n)\n\ntype _Ctype_struct___0 struct {\n\tFsidVal [2]int32\n}\n"
  },
  {
    "path": "disk/disk_netbsd_arm.go",
    "content": "//go:build netbsd && arm\n// +build netbsd,arm\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs disk/types_netbsd.go\n\npackage disk\n\nconst (\n\tsizeOfStatvfs = 0xcc8\n)\n\ntype (\n\tStatvfs struct {\n\t\tFlag         uint32\n\t\tBsize        uint32\n\t\tFrsize       uint32\n\t\tIosize       uint32\n\t\tBlocks       uint64\n\t\tBfree        uint64\n\t\tBavail       uint64\n\t\tBresvd       uint64\n\t\tFiles        uint64\n\t\tFfree        uint64\n\t\tFavail       uint64\n\t\tFresvd       uint64\n\t\tSyncreads    uint64\n\t\tSyncwrites   uint64\n\t\tAsyncreads   uint64\n\t\tAsyncwrites  uint64\n\t\tFsidx        _Ctype_struct___0\n\t\tFsid         uint32\n\t\tNamemax      uint32\n\t\tOwner        uint32\n\t\tPad_cgo_0    [4]byte\n\t\tSpare        [4]uint64\n\t\tFstypename   [32]uint8\n\t\tMntonname    [1024]uint8\n\t\tMntfromname  [1024]uint8\n\t\tMntfromlabel [1024]uint8\n\t}\n)\n\ntype _Ctype_struct___0 struct {\n\tFsidVal [2]int32\n}\n"
  },
  {
    "path": "disk/disk_netbsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build netbsd && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs types_netbsd.go\n\npackage disk\n\nconst (\n\tsizeOfStatvfs = 0xce0\n)\n\ntype (\n\tStatvfs struct {\n\t\tFlag         uint64\n\t\tBsize        uint64\n\t\tFrsize       uint64\n\t\tIosize       uint64\n\t\tBlocks       uint64\n\t\tBfree        uint64\n\t\tBavail       uint64\n\t\tBresvd       uint64\n\t\tFiles        uint64\n\t\tFfree        uint64\n\t\tFavail       uint64\n\t\tFresvd       uint64\n\t\tSyncreads    uint64\n\t\tSyncwrites   uint64\n\t\tAsyncreads   uint64\n\t\tAsyncwrites  uint64\n\t\tFsidx        _Ctype_struct___0\n\t\tFsid         uint64\n\t\tNamemax      uint64\n\t\tOwner        uint32\n\t\tSpare        [4]uint64\n\t\tFstypename   [32]uint8\n\t\tMntonname    [1024]uint8\n\t\tMntfromname  [1024]uint8\n\t\tMntfromlabel [1024]uint8\n\t}\n)\n\ntype _Ctype_struct___0 struct {\n\tFsidVal [2]int32\n}\n"
  },
  {
    "path": "disk/disk_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage disk\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc PartitionsWithContext(_ context.Context, _ bool) ([]PartitionStat, error) {\n\tvar ret []PartitionStat\n\n\t// get length\n\tcount, err := unix.Getfsstat(nil, unix.MNT_WAIT)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tfs := make([]unix.Statfs_t, count)\n\tif _, err = unix.Getfsstat(fs, unix.MNT_WAIT); err != nil {\n\t\treturn ret, err\n\t}\n\n\tfor i := range fs {\n\t\tstat := &fs[i]\n\t\topts := []string{\"rw\"}\n\t\tif stat.F_flags&unix.MNT_RDONLY != 0 {\n\t\t\topts = []string{\"rw\"}\n\t\t}\n\t\tif stat.F_flags&unix.MNT_SYNCHRONOUS != 0 {\n\t\t\topts = append(opts, \"sync\")\n\t\t}\n\t\tif stat.F_flags&unix.MNT_NOEXEC != 0 {\n\t\t\topts = append(opts, \"noexec\")\n\t\t}\n\t\tif stat.F_flags&unix.MNT_NOSUID != 0 {\n\t\t\topts = append(opts, \"nosuid\")\n\t\t}\n\t\tif stat.F_flags&unix.MNT_NODEV != 0 {\n\t\t\topts = append(opts, \"nodev\")\n\t\t}\n\t\tif stat.F_flags&unix.MNT_ASYNC != 0 {\n\t\t\topts = append(opts, \"async\")\n\t\t}\n\t\tif stat.F_flags&unix.MNT_SOFTDEP != 0 {\n\t\t\topts = append(opts, \"softdep\")\n\t\t}\n\t\tif stat.F_flags&unix.MNT_NOATIME != 0 {\n\t\t\topts = append(opts, \"noatime\")\n\t\t}\n\t\tif stat.F_flags&unix.MNT_WXALLOWED != 0 {\n\t\t\topts = append(opts, \"wxallowed\")\n\t\t}\n\n\t\td := PartitionStat{\n\t\t\tDevice:     common.ByteToString(stat.F_mntfromname[:]),\n\t\t\tMountpoint: common.ByteToString(stat.F_mntonname[:]),\n\t\t\tFstype:     common.ByteToString(stat.F_fstypename[:]),\n\t\t\tOpts:       opts,\n\t\t}\n\n\t\tret = append(ret, d)\n\t}\n\n\treturn ret, nil\n}\n\nfunc IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCountersStat, error) {\n\tret := make(map[string]IOCountersStat)\n\n\tr, err := unix.SysctlRaw(\"hw.diskstats\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuf := []byte(r)\n\tlength := len(buf)\n\n\tcount := int(uint64(length) / uint64(sizeOfDiskstats))\n\n\t// parse buf to Diskstats\n\tfor i := 0; i < count; i++ {\n\t\tb := buf[i*sizeOfDiskstats : i*sizeOfDiskstats+sizeOfDiskstats]\n\t\td, err := parseDiskstats(b)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tname := common.IntToString(d.Name[:])\n\n\t\tif len(names) > 0 && !common.StringsHas(names, name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tds := IOCountersStat{\n\t\t\tReadCount:  d.Rxfer,\n\t\t\tWriteCount: d.Wxfer,\n\t\t\tReadBytes:  d.Rbytes,\n\t\t\tWriteBytes: d.Wbytes,\n\t\t\tName:       name,\n\t\t}\n\t\tret[name] = ds\n\t}\n\n\treturn ret, nil\n}\n\n// BT2LD(time)     ((long double)(time).sec + (time).frac * BINTIME_SCALE)\n\nfunc parseDiskstats(buf []byte) (Diskstats, error) {\n\tvar ds Diskstats\n\tbr := bytes.NewReader(buf)\n\tif err := binary.Read(br, binary.LittleEndian, &ds); err != nil {\n\t\treturn ds, err\n\t}\n\n\treturn ds, nil\n}\n\nfunc UsageWithContext(_ context.Context, path string) (*UsageStat, error) {\n\tstat := unix.Statfs_t{}\n\terr := unix.Statfs(path, &stat)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbsize := stat.F_bsize\n\n\tret := &UsageStat{\n\t\tPath:        path,\n\t\tFstype:      getFsType(stat),\n\t\tTotal:       (uint64(stat.F_blocks) * uint64(bsize)),\n\t\tFree:        (uint64(stat.F_bavail) * uint64(bsize)),\n\t\tInodesTotal: (uint64(stat.F_files)),\n\t\tInodesFree:  (uint64(stat.F_ffree)),\n\t}\n\n\tret.InodesUsed = (ret.InodesTotal - ret.InodesFree)\n\tret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0\n\tret.Used = (uint64(stat.F_blocks) - uint64(stat.F_bfree)) * uint64(bsize)\n\tret.UsedPercent = (float64(ret.Used) / float64(ret.Total)) * 100.0\n\n\treturn ret, nil\n}\n\nfunc getFsType(stat unix.Statfs_t) string {\n\treturn common.ByteToString(stat.F_fstypename[:])\n}\n\nfunc SerialNumberWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc LabelWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "disk/disk_openbsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && 386\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs disk/types_openbsd.go\n\npackage disk\n\nconst (\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfDiskstats = 0x60\n)\n\ntype Diskstats struct {\n\tName       [16]int8\n\tBusy       int32\n\tRxfer      uint64\n\tWxfer      uint64\n\tSeek       uint64\n\tRbytes     uint64\n\tWbytes     uint64\n\tAttachtime Timeval\n\tTimestamp  Timeval\n\tTime       Timeval\n}\ntype Timeval struct {\n\tSec  int64\n\tUsec int32\n}\n\ntype (\n\tDiskstat struct{}\n\tbintime  struct{}\n)\n"
  },
  {
    "path": "disk/disk_openbsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs types_openbsd.go\n\npackage disk\n\nconst (\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfDiskstats = 0x70\n)\n\ntype Diskstats struct {\n\tName       [16]int8\n\tBusy       int32\n\tPad_cgo_0  [4]byte\n\tRxfer      uint64\n\tWxfer      uint64\n\tSeek       uint64\n\tRbytes     uint64\n\tWbytes     uint64\n\tAttachtime Timeval\n\tTimestamp  Timeval\n\tTime       Timeval\n}\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype (\n\tDiskstat struct{}\n\tbintime  struct{}\n)\n"
  },
  {
    "path": "disk/disk_openbsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && arm\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs disk/types_openbsd.go\n\npackage disk\n\nconst (\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfDiskstats = 0x60\n)\n\ntype Diskstats struct {\n\tName       [16]int8\n\tBusy       int32\n\tRxfer      uint64\n\tWxfer      uint64\n\tSeek       uint64\n\tRbytes     uint64\n\tWbytes     uint64\n\tAttachtime Timeval\n\tTimestamp  Timeval\n\tTime       Timeval\n}\ntype Timeval struct {\n\tSec  int64\n\tUsec int32\n}\n\ntype (\n\tDiskstat struct{}\n\tbintime  struct{}\n)\n"
  },
  {
    "path": "disk/disk_openbsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs disk/types_openbsd.go\n\npackage disk\n\nconst (\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfDiskstats = 0x70\n)\n\ntype Diskstats struct {\n\tName       [16]int8\n\tBusy       int32\n\tRxfer      uint64\n\tWxfer      uint64\n\tSeek       uint64\n\tRbytes     uint64\n\tWbytes     uint64\n\tAttachtime Timeval\n\tTimestamp  Timeval\n\tTime       Timeval\n}\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype (\n\tDiskstat struct{}\n\tbintime  struct{}\n)\n"
  },
  {
    "path": "disk/disk_openbsd_riscv64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && riscv64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs disk/types_openbsd.go\n\npackage disk\n\nconst (\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfDiskstats = 0x70\n)\n\ntype (\n\tDiskstats struct {\n\t\tName       [16]int8\n\t\tBusy       int32\n\t\tRxfer      uint64\n\t\tWxfer      uint64\n\t\tSeek       uint64\n\t\tRbytes     uint64\n\t\tWbytes     uint64\n\t\tAttachtime Timeval\n\t\tTimestamp  Timeval\n\t\tTime       Timeval\n\t}\n\tTimeval struct {\n\t\tSec  int64\n\t\tUsec int64\n\t}\n)\n\ntype (\n\tDiskstat struct{}\n\tbintime  struct{}\n)\n"
  },
  {
    "path": "disk/disk_solaris.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build solaris\n\npackage disk\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst (\n\t// _DEFAULT_NUM_MOUNTS is set to `cat /etc/mnttab | wc -l` rounded up to the\n\t// nearest power of two.\n\t_DEFAULT_NUM_MOUNTS = 32\n\n\t// _MNTTAB default place to read mount information\n\t_MNTTAB = \"/etc/mnttab\"\n)\n\n// A blacklist of read-only virtual filesystems.  Writable filesystems are of\n// operational concern and must not be included in this list.\nvar fsTypeBlacklist = map[string]struct{}{\n\t\"ctfs\":   {},\n\t\"dev\":    {},\n\t\"fd\":     {},\n\t\"lofs\":   {},\n\t\"lxproc\": {},\n\t\"mntfs\":  {},\n\t\"objfs\":  {},\n\t\"proc\":   {},\n}\n\nfunc PartitionsWithContext(_ context.Context, _ bool) ([]PartitionStat, error) {\n\tret := make([]PartitionStat, 0, _DEFAULT_NUM_MOUNTS)\n\n\t// Scan mnttab(4)\n\tf, err := os.Open(_MNTTAB)\n\tif err != nil {\n\t}\n\tdefer func() {\n\t\tif err == nil {\n\t\t\terr = f.Close()\n\t\t} else {\n\t\t\tf.Close()\n\t\t}\n\t}()\n\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tfields := strings.Split(scanner.Text(), \"\\t\")\n\n\t\tif _, found := fsTypeBlacklist[fields[2]]; found {\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, PartitionStat{\n\t\t\t// NOTE(seanc@): Device isn't exactly accurate: from mnttab(4): \"The name\n\t\t\t// of the resource that has been mounted.\"  Ideally this value would come\n\t\t\t// from Statvfs_t.Fsid but I'm leaving it to the caller to traverse\n\t\t\t// unix.Statvfs().\n\t\t\tDevice:     fields[0],\n\t\t\tMountpoint: fields[1],\n\t\t\tFstype:     fields[2],\n\t\t\tOpts:       strings.Split(fields[3], \",\"),\n\t\t})\n\t}\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to scan %q: %w\", _MNTTAB, err)\n\t}\n\n\treturn ret, err\n}\n\nvar kstatSplit = regexp.MustCompile(`[:\\s]+`)\n\nfunc IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {\n\tvar issolaris bool\n\tif runtime.GOOS == \"illumos\" {\n\t\tissolaris = false\n\t} else {\n\t\tissolaris = true\n\t}\n\t// check disks instead of zfs pools\n\tfilterstr := \"/[^zfs]/:::/^nread$|^nwritten$|^reads$|^writes$|^rtime$|^wtime$/\"\n\tkstatSysOut, err := invoke.CommandWithContext(ctx, \"kstat\", \"-c\", \"disk\", \"-p\", filterstr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot execute kstat: %w\", err)\n\t}\n\tlines := strings.Split(strings.TrimSpace(string(kstatSysOut)), \"\\n\")\n\tif len(lines) == 0 {\n\t\treturn nil, errors.New(\"no disk class found\")\n\t}\n\tdnamearr := make(map[string]string)\n\tnreadarr := make(map[string]uint64)\n\tnwrittenarr := make(map[string]uint64)\n\treadsarr := make(map[string]uint64)\n\twritesarr := make(map[string]uint64)\n\trtimearr := make(map[string]uint64)\n\twtimearr := make(map[string]uint64)\n\n\t// in case the name is \"/dev/sda1\", then convert to \"sda1\"\n\tfor i, name := range names {\n\t\tnames[i] = filepath.Base(name)\n\t}\n\n\tfor _, line := range lines {\n\t\tfields := kstatSplit.Split(line, -1)\n\t\tif len(fields) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tmoduleName := fields[0]\n\t\tinstance := fields[1]\n\t\tdname := fields[2]\n\n\t\tif len(names) > 0 && !common.StringsHas(names, dname) {\n\t\t\tcontinue\n\t\t}\n\t\tdnamearr[moduleName+instance] = dname\n\t\t// fields[3] is the statistic label, fields[4] is the value\n\t\tswitch fields[3] {\n\t\tcase \"nread\":\n\t\t\tnreadarr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase \"nwritten\":\n\t\t\tnwrittenarr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase \"reads\":\n\t\t\treadsarr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase \"writes\":\n\t\t\twritesarr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase \"rtime\":\n\t\t\tif issolaris {\n\t\t\t\t// from sec to milli secs\n\t\t\t\tvar frtime float64\n\t\t\t\tfrtime, err = strconv.ParseFloat((fields[4]), 64)\n\t\t\t\trtimearr[moduleName+instance] = uint64(frtime * 1000)\n\t\t\t} else {\n\t\t\t\t// from nano to milli secs\n\t\t\t\trtimearr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64)\n\t\t\t\trtimearr[moduleName+instance] = rtimearr[moduleName+instance] / 1000 / 1000\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase \"wtime\":\n\t\t\tif issolaris {\n\t\t\t\t// from sec to milli secs\n\t\t\t\tvar fwtime float64\n\t\t\t\tfwtime, err = strconv.ParseFloat((fields[4]), 64)\n\t\t\t\twtimearr[moduleName+instance] = uint64(fwtime * 1000)\n\t\t\t} else {\n\t\t\t\t// from nano to milli secs\n\t\t\t\twtimearr[moduleName+instance], err = strconv.ParseUint((fields[4]), 10, 64)\n\t\t\t\twtimearr[moduleName+instance] = wtimearr[moduleName+instance] / 1000 / 1000\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\tret := make(map[string]IOCountersStat, 0)\n\tfor k := range dnamearr {\n\t\td := IOCountersStat{\n\t\t\tName:       dnamearr[k],\n\t\t\tReadBytes:  nreadarr[k],\n\t\t\tWriteBytes: nwrittenarr[k],\n\t\t\tReadCount:  readsarr[k],\n\t\t\tWriteCount: writesarr[k],\n\t\t\tReadTime:   rtimearr[k],\n\t\t\tWriteTime:  wtimearr[k],\n\t\t}\n\t\tret[d.Name] = d\n\t}\n\treturn ret, nil\n}\n\nfunc UsageWithContext(_ context.Context, path string) (*UsageStat, error) {\n\tstatvfs := unix.Statvfs_t{}\n\tif err := unix.Statvfs(path, &statvfs); err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to call statvfs(2) on %q: %w\", path, err)\n\t}\n\n\tusageStat := &UsageStat{\n\t\tPath:   path,\n\t\tFstype: common.IntToString(statvfs.Basetype[:]),\n\t\tTotal:  statvfs.Blocks * statvfs.Frsize,\n\t\tFree:   statvfs.Bfree * statvfs.Frsize,\n\t\tUsed:   (statvfs.Blocks - statvfs.Bfree) * statvfs.Frsize,\n\n\t\t// NOTE: ZFS (and FreeBZSD's UFS2) use dynamic inode/dnode allocation.\n\t\t// Explicitly return a near-zero value for InodesUsedPercent so that nothing\n\t\t// attempts to garbage collect based on a lack of available inodes/dnodes.\n\t\t// Similarly, don't use the zero value to prevent divide-by-zero situations\n\t\t// and inject a faux near-zero value.  Filesystems evolve.  Has your\n\t\t// filesystem evolved?  Probably not if you care about the number of\n\t\t// available inodes.\n\t\tInodesTotal:       1024.0 * 1024.0,\n\t\tInodesUsed:        1024.0,\n\t\tInodesFree:        math.MaxUint64,\n\t\tInodesUsedPercent: (1024.0 / (1024.0 * 1024.0)) * 100.0,\n\t}\n\n\tusageStat.UsedPercent = (float64(usageStat.Used) / float64(usageStat.Total)) * 100.0\n\n\treturn usageStat, nil\n}\n\nfunc SerialNumberWithContext(ctx context.Context, name string) (string, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"cfgadm\", \"-ls\", \"select=type(disk),cols=ap_id:info,cols2=,noheadings\")\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"exec cfgadm: %w\", err)\n\t}\n\n\tsuf := \"::\" + strings.TrimPrefix(name, \"/dev/\")\n\ts := bufio.NewScanner(bytes.NewReader(out))\n\tfor s.Scan() {\n\t\tflds := strings.Fields(s.Text())\n\t\tif strings.HasSuffix(flds[0], suf) {\n\t\t\tflen := len(flds)\n\t\t\tif flen >= 3 {\n\t\t\t\tfor i, f := range flds {\n\t\t\t\t\tif i > 0 && i < flen-1 && f == \"SN:\" {\n\t\t\t\t\t\treturn flds[i+1], nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"\", nil\n\t\t}\n\t}\n\tif err := s.Err(); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn \"\", nil\n}\n\nfunc LabelWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "disk/disk_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage disk\n\nimport (\n\t\"errors\"\n\t\"runtime\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestUsage(t *testing.T) {\n\tpath := \"/\"\n\tif runtime.GOOS == \"windows\" {\n\t\tpath = \"C:\"\n\t}\n\tv, err := Usage(path)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\n\trequire.NoError(t, err)\n\tassert.Equalf(t, v.Path, path, \"error %v\", err)\n}\n\nfunc TestPartitions(t *testing.T) {\n\tret, err := Partitions(false)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\n\tif err != nil || len(ret) == 0 {\n\t\tt.Errorf(\"error %v\", err)\n\t}\n\tt.Log(ret)\n\n\tassert.NotEmptyf(t, ret, \"ret is empty\")\n\tfor _, disk := range ret {\n\t\tassert.NotEmptyf(t, disk.Device, \"Could not get device info %v\", disk)\n\t}\n}\n\nfunc TestIOCounters(t *testing.T) {\n\tret, err := IOCounters()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, ret, \"ret is empty\")\n\tempty := IOCountersStat{}\n\tfor part, io := range ret {\n\t\tt.Log(part, io)\n\t\tassert.NotEqualf(t, io, empty, \"io_counter error %v, %v\", part, io)\n\t}\n}\n\n// https://github.com/shirou/gopsutil/issues/560 regression test\nfunc TestIOCounters_concurrency_on_darwin_cgo(t *testing.T) {\n\tif runtime.GOOS != \"darwin\" {\n\t\tt.Skip(\"darwin only\")\n\t}\n\tvar wg sync.WaitGroup\n\tconst maxCount = 1000\n\tfor i := 1; i < maxCount; i++ {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tIOCounters()\n\t\t}()\n\t}\n\twg.Wait()\n}\n\nfunc TestUsageStat_String(t *testing.T) {\n\tv := UsageStat{\n\t\tPath:              \"/\",\n\t\tTotal:             1000,\n\t\tFree:              2000,\n\t\tUsed:              3000,\n\t\tUsedPercent:       50.1,\n\t\tInodesTotal:       4000,\n\t\tInodesUsed:        5000,\n\t\tInodesFree:        6000,\n\t\tInodesUsedPercent: 49.1,\n\t\tFstype:            \"ext4\",\n\t}\n\te := `{\"path\":\"/\",\"fstype\":\"ext4\",\"total\":1000,\"free\":2000,\"used\":3000,\"usedPercent\":50.1,\"inodesTotal\":4000,\"inodesUsed\":5000,\"inodesFree\":6000,\"inodesUsedPercent\":49.1}`\n\tassert.JSONEqf(t, e, v.String(), \"DiskUsageStat string is invalid: %v\", v)\n}\n\nfunc TestPartitionStat_String(t *testing.T) {\n\tv := PartitionStat{\n\t\tDevice:     \"sd01\",\n\t\tMountpoint: \"/\",\n\t\tFstype:     \"ext4\",\n\t\tOpts:       []string{\"ro\"},\n\t}\n\te := `{\"device\":\"sd01\",\"mountpoint\":\"/\",\"fstype\":\"ext4\",\"opts\":[\"ro\"]}`\n\tassert.JSONEqf(t, e, v.String(), \"DiskUsageStat string is invalid: %v\", v)\n}\n\nfunc TestIOCountersStat_String(t *testing.T) {\n\tv := IOCountersStat{\n\t\tName:         \"sd01\",\n\t\tReadCount:    100,\n\t\tWriteCount:   200,\n\t\tReadBytes:    300,\n\t\tWriteBytes:   400,\n\t\tSerialNumber: \"SERIAL\",\n\t}\n\te := `{\"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\":\"\"}`\n\tassert.JSONEqf(t, e, v.String(), \"DiskUsageStat string is invalid: %v\", v)\n}\n"
  },
  {
    "path": "disk/disk_unix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd || linux || darwin\n\npackage disk\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc UsageWithContext(_ context.Context, path string) (*UsageStat, error) {\n\tstat := unix.Statfs_t{}\n\terr := unix.Statfs(path, &stat)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbsize := stat.Bsize\n\n\tret := &UsageStat{\n\t\tPath:        unescapeFstab(path),\n\t\tFstype:      getFsType(stat),\n\t\tTotal:       (uint64(stat.Blocks) * uint64(bsize)),\n\t\tFree:        (uint64(stat.Bavail) * uint64(bsize)),\n\t\tInodesTotal: (uint64(stat.Files)),\n\t\tInodesFree:  (uint64(stat.Ffree)),\n\t}\n\n\tret.Used = (uint64(stat.Blocks) - uint64(stat.Bfree)) * uint64(bsize)\n\n\tif (ret.Used + ret.Free) == 0 {\n\t\tret.UsedPercent = 0\n\t} else {\n\t\t// We don't use ret.Total to calculate percent.\n\t\t// see https://github.com/shirou/gopsutil/issues/562\n\t\tret.UsedPercent = (float64(ret.Used) / float64(ret.Used+ret.Free)) * 100.0\n\t}\n\n\t// if could not get InodesTotal, return empty\n\tif ret.InodesTotal < ret.InodesFree {\n\t\treturn ret, nil\n\t}\n\n\tret.InodesUsed = (ret.InodesTotal - ret.InodesFree)\n\n\tif ret.InodesTotal == 0 {\n\t\tret.InodesUsedPercent = 0\n\t} else {\n\t\tret.InodesUsedPercent = (float64(ret.InodesUsed) / float64(ret.InodesTotal)) * 100.0\n\t}\n\n\treturn ret, nil\n}\n\n// Unescape escaped octal chars (like space 040, ampersand 046 and backslash 134) to their real value in fstab fields issue#555\nfunc unescapeFstab(path string) string {\n\tescaped, err := strconv.Unquote(`\"` + path + `\"`)\n\tif err != nil {\n\t\treturn path\n\t}\n\treturn escaped\n}\n"
  },
  {
    "path": "disk/disk_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage disk\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"syscall\"\n\t\"unicode/utf16\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\t\"golang.org/x/sys/windows/registry\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst (\n\tmaxVolumeNameLength     = uint32(windows.MAX_PATH + 1) // this should be a GUID (50), but for safety I keep max_path\n\tmaxFileSystemNameLength = uint32(windows.MAX_PATH + 1)\n\tmaxWarningsInDrive      = 5\n)\n\n// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa#parameters\nconst (\n\trw       = \"rw\"\n\tro       = \"ro\"\n\tcompress = \"compress\"\n)\n\nconst (\n\tfirstPossibleDriveLetter = 'A'\n\tlastPossibleDriveLetter  = 'Z'\n)\n\nvar (\n\tprocGetDiskFreeSpaceExW              = common.Modkernel32.NewProc(\"GetDiskFreeSpaceExW\")\n\tprocGetLogicalDriveStringsW          = common.Modkernel32.NewProc(\"GetLogicalDriveStringsW\")\n\tprocGetVolumeInformation             = common.Modkernel32.NewProc(\"GetVolumeInformationW\")\n\tprocFindFirstVolumeW                 = common.Modkernel32.NewProc(\"FindFirstVolumeW\")\n\tprocFindNextVolumeW                  = common.Modkernel32.NewProc(\"FindNextVolumeW\")\n\tprocFindVolumeClose                  = common.Modkernel32.NewProc(\"FindVolumeClose\")\n\tprocGetVolumePathNamesForVolumeNameW = common.Modkernel32.NewProc(\"GetVolumePathNamesForVolumeNameW\")\n)\n\nvar (\n\tfileFileCompression = int64(16)     // 0x00000010\n\tfileReadOnlyVolume  = int64(524288) // 0x00080000\n)\n\n// diskPerformance is an equivalent representation of DISK_PERFORMANCE in the Windows API.\n// https://docs.microsoft.com/fr-fr/windows/win32/api/winioctl/ns-winioctl-disk_performance\ntype diskPerformance struct {\n\tBytesRead           int64\n\tBytesWritten        int64\n\tReadTime            int64\n\tWriteTime           int64\n\tIdleTime            int64\n\tReadCount           uint32\n\tWriteCount          uint32\n\tQueueDepth          uint32\n\tSplitCount          uint32\n\tQueryTime           int64\n\tStorageDeviceNumber uint32\n\tStorageManagerName  [8]uint16\n\talignmentPadding    uint32 // necessary for 32bit support, see https://github.com/elastic/beats/pull/16553\n}\n\nfunc init() {\n\t// enable disk performance counters on Windows Server editions (needs to run as admin)\n\tkey, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\\CurrentControlSet\\Services\\PartMgr`, registry.SET_VALUE)\n\tif err == nil {\n\t\tkey.SetDWordValue(\"EnableCounterForIoctl\", 1)\n\t\tkey.Close()\n\t}\n}\n\nfunc UsageWithContext(_ context.Context, path string) (*UsageStat, error) {\n\tlpFreeBytesAvailable := int64(0)\n\tlpTotalNumberOfBytes := int64(0)\n\tlpTotalNumberOfFreeBytes := int64(0)\n\tdiskret, _, err := procGetDiskFreeSpaceExW.Call(\n\t\tuintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))),\n\t\tuintptr(unsafe.Pointer(&lpFreeBytesAvailable)),\n\t\tuintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),\n\t\tuintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))\n\tif diskret == 0 {\n\t\treturn nil, err\n\t}\n\tret := &UsageStat{\n\t\tPath:        path,\n\t\tTotal:       uint64(lpTotalNumberOfBytes),\n\t\tFree:        uint64(lpTotalNumberOfFreeBytes),\n\t\tUsed:        uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),\n\t\tUsedPercent: (float64(lpTotalNumberOfBytes) - float64(lpTotalNumberOfFreeBytes)) / float64(lpTotalNumberOfBytes) * 100,\n\t\t// InodesTotal: 0,\n\t\t// InodesFree: 0,\n\t\t// InodesUsed: 0,\n\t\t// InodesUsedPercent: 0,\n\t}\n\treturn ret, nil\n}\n\n// PartitionsWithContext returns disk partitions.\n// It uses procGetLogicalDriveStringsW to get drives with drive letters and procFindFirstVolumeW to get volumes without drive letters.\n// Since the api calls don't have a timeout, this method uses context to set deadline by users.\nfunc PartitionsWithContext(ctx context.Context, _ bool) ([]PartitionStat, error) {\n\twarnings := Warnings{Verbose: true}\n\tprocessedPaths := make(map[string]struct{})\n\tpartitionStats := []PartitionStat{}\n\n\t// Get drives with drive letters (including remote drives, ex: SMB shares)\n\tdrives, err := getLogicalDrives(ctx)\n\tif err != nil {\n\t\treturn partitionStats, err\n\t}\n\n\tpartitionStats = processLogicalDrives(ctx, drives, processedPaths, partitionStats, warnings)\n\n\t// Get volumes without drive letters (ex: mounted folders with no drive letter)\n\tpartitionStats = processVolumesMountedAsFolders(ctx, partitionStats, warnings, processedPaths)\n\treturn partitionStats, warnings.Reference()\n}\n\nfunc processVolumesMountedAsFolders(ctx context.Context, partitionStats []PartitionStat, warnings Warnings, processedPaths map[string]struct{}) []PartitionStat {\n\tvolNameBuf := make([]uint16, maxVolumeNameLength)\n\tnextVolHandle, _, err := procFindFirstVolumeW.Call(\n\t\tuintptr(unsafe.Pointer(&volNameBuf[0])),\n\t\tuintptr(maxVolumeNameLength))\n\tif windows.Handle(nextVolHandle) == windows.InvalidHandle {\n\t\twarnings.Add(fmt.Errorf(\"failed to get first-volume: %w\", err))\n\t\treturn partitionStats\n\t}\n\tdefer procFindVolumeClose.Call(nextVolHandle)\n\tpartitionStats = processVolumeLoop(ctx, nextVolHandle, volNameBuf, processedPaths, partitionStats, warnings)\n\treturn partitionStats\n}\n\nfunc processVolumeLoop(ctx context.Context, nextVolHandle uintptr, volNameBuf []uint16, processedPaths map[string]struct{}, partitionStats []PartitionStat, warnings Warnings) []PartitionStat {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\twarnings.Add(fmt.Errorf(\"context cancelled while processing volumes: %w\", ctx.Err()))\n\t\t\treturn partitionStats\n\t\tdefault:\n\t\t}\n\n\t\tmounts, err := getVolumePaths(volNameBuf)\n\t\tif err != nil {\n\t\t\twarnings.Add(fmt.Errorf(\"failed to find paths for volume %s\", windows.UTF16ToString(volNameBuf)))\n\t\t\tcontinue\n\t\t}\n\n\t\tpartitionStats = processMountsForVolume(ctx, mounts, processedPaths, partitionStats, warnings)\n\n\t\tvolNameBuf = make([]uint16, maxVolumeNameLength)\n\t\tif volRet, _, err := procFindNextVolumeW.Call(\n\t\t\tnextVolHandle,\n\t\t\tuintptr(unsafe.Pointer(&volNameBuf[0])),\n\t\t\tuintptr(maxVolumeNameLength)); err != nil && volRet == 0 {\n\t\t\tvar errno syscall.Errno\n\t\t\tif errors.As(err, &errno) && errno == windows.ERROR_NO_MORE_FILES {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\twarnings.Add(fmt.Errorf(\"failed to find next volume: %w\", err))\n\t\t\tif len(warnings.List) > maxWarningsInDrive {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn partitionStats\n}\n\nfunc processMountsForVolume(ctx context.Context, mounts []string, processedPaths map[string]struct{}, partitionStats []PartitionStat, warnings Warnings) []PartitionStat {\n\tfor _, mount := range mounts {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\twarnings.Add(fmt.Errorf(\"context cancelled while processing mount points per volume: %w\", ctx.Err()))\n\t\t\treturn partitionStats\n\t\tdefault:\n\t\t\tif _, ok := processedPaths[mount]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif partitionStat, warning := buildPartitionStat(mount); warning == nil {\n\t\t\t\tpartitionStats = append(partitionStats, partitionStat)\n\t\t\t} else {\n\t\t\t\twarnings.Add(warning)\n\t\t\t}\n\t\t}\n\t}\n\treturn partitionStats\n}\n\nfunc processLogicalDrives(ctx context.Context, drives []string, processedPaths map[string]struct{}, partitionStats []PartitionStat, warnings Warnings) []PartitionStat {\n\tfor _, drive := range drives {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\twarnings.Add(fmt.Errorf(\"context cancelled while processing logical drives: %w\", ctx.Err()))\n\t\t\treturn partitionStats\n\t\tdefault:\n\t\t\tif drive != \"\" && drive[0] >= firstPossibleDriveLetter && drive[0] <= lastPossibleDriveLetter {\n\t\t\t\tv := drive[0]\n\t\t\t\tpath := string(v) + \":\"\n\t\t\t\tif partitionStat, warning := buildPartitionStat(path); warning == nil {\n\t\t\t\t\tprocessedPaths[partitionStat.Mountpoint+\"\\\\\"] = struct{}{}\n\t\t\t\t\tpartitionStats = append(partitionStats, partitionStat)\n\t\t\t\t} else {\n\t\t\t\t\twarnings.Add(warning)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn partitionStats\n}\n\n// getLogicalDrives retrieves all logical drives using GetLogicalDriveStringsW.\n// We first call GetLogicalDriveStringsW with a buffer length of 0 to get the required buffer size.\n// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrivestringsw\nfunc getLogicalDrives(ctx context.Context) ([]string, error) {\n\tbufferLen, _, err := procGetLogicalDriveStringsW.Call(\n\t\tuintptr(0),\n\t\tuintptr(0))\n\tif !errors.Is(err, windows.ERROR_SUCCESS) {\n\t\treturn nil, err // The call failed with an unexpected error\n\t}\n\tif ctx.Err() != nil {\n\t\treturn nil, ctx.Err()\n\t}\n\tlpBuffer := make([]uint16, bufferLen)\n\t// buffer can be longer than MAX_PATH\n\t_, _, err = procGetLogicalDriveStringsW.Call(\n\t\tuintptr(len(lpBuffer)),\n\t\tuintptr(unsafe.Pointer(&lpBuffer[0])))\n\tif !errors.Is(err, windows.ERROR_SUCCESS) {\n\t\treturn nil, err // The call failed with an unexpected error\n\t}\n\n\tdrives := split0(lpBuffer, int(bufferLen))\n\treturn drives, nil\n}\n\nfunc buildPartitionStat(path string) (PartitionStat, error) {\n\ttypePath, _ := windows.UTF16PtrFromString(path)\n\tdriveType := windows.GetDriveType(typePath)\n\n\tif driveType == windows.DRIVE_UNKNOWN {\n\t\treturn PartitionStat{}, windows.GetLastError()\n\t}\n\n\tif driveType == windows.DRIVE_REMOVABLE || driveType == windows.DRIVE_FIXED ||\n\t\tdriveType == windows.DRIVE_REMOTE || driveType == windows.DRIVE_CDROM {\n\t\tvolPath, _ := windows.UTF16PtrFromString(path + \"/\")\n\t\tvolumeName := make([]byte, maxVolumeNameLength)\n\t\tfsName := make([]byte, maxFileSystemNameLength)\n\t\tvar fsFlags int64\n\n\t\t// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationw\n\t\tret, _, err := procGetVolumeInformation.Call(\n\t\t\tuintptr(unsafe.Pointer(volPath)),\n\t\t\tuintptr(unsafe.Pointer(&volumeName[0])),\n\t\t\tuintptr(len(volumeName)),\n\t\t\tuintptr(0), // serial number\n\t\t\tuintptr(0), // max component length\n\t\t\tuintptr(unsafe.Pointer(&fsFlags)),\n\t\t\tuintptr(unsafe.Pointer(&fsName[0])),\n\t\t\tuintptr(len(fsName)),\n\t\t)\n\n\t\tif ret == 0 {\n\t\t\tif driveType == windows.DRIVE_REMOVABLE || driveType == windows.DRIVE_REMOTE || driveType == windows.DRIVE_CDROM {\n\t\t\t\treturn PartitionStat{}, nil // Device not ready\n\t\t\t}\n\t\t\treturn PartitionStat{}, err\n\t\t}\n\n\t\topts := []string{rw}\n\t\tif fsFlags&fileReadOnlyVolume != 0 {\n\t\t\topts = []string{ro}\n\t\t}\n\t\tif fsFlags&fileFileCompression != 0 {\n\t\t\topts = append(opts, compress)\n\t\t}\n\n\t\treturn PartitionStat{\n\t\t\tMountpoint: path,\n\t\t\tDevice:     path,\n\t\t\tFstype:     string(bytes.ReplaceAll(fsName, []byte(\"\\x00\"), []byte(\"\"))),\n\t\t\tOpts:       opts,\n\t\t}, nil\n\t}\n\n\treturn PartitionStat{}, nil\n}\n\nfunc IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCountersStat, error) {\n\t// https://github.com/giampaolo/psutil/blob/544e9daa4f66a9f80d7bf6c7886d693ee42f0a13/psutil/arch/windows/disk.c#L83\n\tdrivemap := make(map[string]IOCountersStat, 0)\n\tvar dPerformance diskPerformance\n\n\tlpBuffer := make([]uint16, 254)\n\tlpBufferLen, err := windows.GetLogicalDriveStrings(uint32(len(lpBuffer)), &lpBuffer[0])\n\tif err != nil {\n\t\treturn drivemap, err\n\t}\n\tfor _, v := range lpBuffer[:lpBufferLen] {\n\t\tif v < firstPossibleDriveLetter || v > lastPossibleDriveLetter {\n\t\t\tcontinue\n\t\t}\n\t\tpath := string(rune(v)) + \":\"\n\t\ttypepath, _ := windows.UTF16PtrFromString(path)\n\t\ttyperet := windows.GetDriveType(typepath)\n\t\tif typeret != windows.DRIVE_FIXED {\n\t\t\tcontinue\n\t\t}\n\t\tszDevice := `\\\\.\\` + path\n\t\tconst IOCTL_DISK_PERFORMANCE = 0x70020\n\t\th, err := windows.CreateFile(windows.StringToUTF16Ptr(szDevice), 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, windows.ERROR_FILE_NOT_FOUND) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn drivemap, err\n\t\t}\n\t\tdefer windows.CloseHandle(h)\n\n\t\tvar diskPerformanceSize uint32\n\t\terr = windows.DeviceIoControl(h, IOCTL_DISK_PERFORMANCE, nil, 0, (*byte)(unsafe.Pointer(&dPerformance)), uint32(unsafe.Sizeof(dPerformance)), &diskPerformanceSize, nil)\n\t\tif err != nil {\n\t\t\t// ERROR_INVALID_FUNCTION and ERROR_NOT_SUPPORTED indicate that\n\t\t\t// the drive does not support IOCTL_DISK_PERFORMANCE (e.g. virtual\n\t\t\t// drives like Google Drive, or systems where disk performance\n\t\t\t// counters are disabled such as Windows Server 2016).\n\t\t\t// Skip the drive and continue, matching psutil behavior:\n\t\t\t// https://github.com/giampaolo/psutil/blob/544e9daa4f66a9f80d7bf6c7886d693ee42f0a13/psutil/arch/windows/disk.c#L146-L163\n\t\t\tif errors.Is(err, windows.ERROR_INVALID_FUNCTION) || errors.Is(err, windows.ERROR_NOT_SUPPORTED) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn drivemap, err\n\t\t}\n\n\t\tif len(names) == 0 || common.StringsHas(names, path) {\n\t\t\tdrivemap[path] = IOCountersStat{\n\t\t\t\tReadBytes:  uint64(dPerformance.BytesRead),\n\t\t\t\tWriteBytes: uint64(dPerformance.BytesWritten),\n\t\t\t\tReadCount:  uint64(dPerformance.ReadCount),\n\t\t\t\tWriteCount: uint64(dPerformance.WriteCount),\n\t\t\t\tReadTime:   uint64(dPerformance.ReadTime / 10000 / 1000), // convert to ms: https://github.com/giampaolo/psutil/issues/1012\n\t\t\t\tWriteTime:  uint64(dPerformance.WriteTime / 10000 / 1000),\n\t\t\t\tName:       path,\n\t\t\t}\n\t\t}\n\t}\n\treturn drivemap, nil\n}\n\nfunc SerialNumberWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc LabelWithContext(_ context.Context, _ string) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\n// getVolumePaths returns the path for the given volume name.\nfunc getVolumePaths(volNameBuf []uint16) ([]string, error) {\n\t// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumepathnamesforvolumenamew\n\t// Consider that NTFS supports paths longer than windows.MAX_PATH\n\treturnLen := uint32(0)\n\tfirstResult, _, volumePathFirstErr := procGetVolumePathNamesForVolumeNameW.Call(\n\t\tuintptr(unsafe.Pointer(&volNameBuf[0])),\n\t\tuintptr(0),\n\t\tuintptr(0),\n\t\tuintptr(unsafe.Pointer(&returnLen)))\n\tif firstResult == 0 && !errors.Is(volumePathFirstErr, windows.ERROR_MORE_DATA) {\n\t\treturn nil, fmt.Errorf(\"failed to get volume paths size for volume %s: %w\", windows.UTF16ToString(volNameBuf), volumePathFirstErr)\n\t}\n\n\tvolPathsBuf := make([]uint16, returnLen)\n\tok, _, volumePathNamesErr := procGetVolumePathNamesForVolumeNameW.Call(\n\t\tuintptr(unsafe.Pointer(&volNameBuf[0])),\n\t\tuintptr(unsafe.Pointer(&volPathsBuf[0])),\n\t\tuintptr(returnLen),\n\t\tuintptr(unsafe.Pointer(&returnLen)))\n\tif ok != 0 {\n\t\treturn split0(volPathsBuf, int(returnLen)), nil\n\t}\n\treturn nil, fmt.Errorf(\"failed to get volume paths for volume %s: %w\", windows.UTF16ToString(volNameBuf), volumePathNamesErr)\n}\n\n// split0 iterates through s16 upto `end` and slices `s16` into sub-slices separated by the null character (uint16(0)).\n// split0 converts the sub-slices between the null characters into strings then returns them in a slice.\nfunc split0(s16 []uint16, end int) []string {\n\tif end > len(s16) {\n\t\tend = len(s16)\n\t}\n\n\tfrom, ss := 0, make([]string, 0)\n\n\tfor to := 0; to < end; to++ {\n\t\tif s16[to] == 0 {\n\t\t\tif from < to && s16[from] != 0 {\n\t\t\t\tss = append(ss, string(utf16.Decode(s16[from:to])))\n\t\t\t}\n\t\t\tfrom = to + 1\n\t\t}\n\t}\n\n\treturn ss\n}\n"
  },
  {
    "path": "disk/disk_windows_test.go",
    "content": "package disk\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"os/exec\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetLogicalDrives(t *testing.T) {\n\t// Create a virtual drive using subst to ensure multiple drives exist\n\ttempDir := t.TempDir()\n\n\t// Find an unused drive letter (Y: to G:, reverse order)\n\tvar driveLetter string\n\tfor c := 'Y'; c >= 'G'; c-- {\n\t\ttestDrive := string(c) + \":\"\n\t\t_, err := os.Stat(testDrive + \"\\\\\")\n\t\tif os.IsNotExist(err) {\n\t\t\tdriveLetter = testDrive\n\t\t\tbreak\n\t\t}\n\t}\n\tif driveLetter == \"\" {\n\t\tt.Skip(\"No available drive letter for subst\")\n\t}\n\tctx := context.Background()\n\t// Create virtual drive by using subst command\n\tcmd := exec.CommandContext(ctx, \"subst\", driveLetter, tempDir)\n\tif err := cmd.Run(); err != nil {\n\t\tt.Skipf(\"subst command failed: %v\", err)\n\t}\n\tt.Cleanup(func() {\n\t\texec.CommandContext(ctx, \"subst\", driveLetter, \"/d\").Run()\n\t})\n\n\tdrives, err := getLogicalDrives(context.Background())\n\trequire.NoError(t, err)\n\tassert.NotEmpty(t, drives)\n\tfor _, d := range drives {\n\t\tassert.NotEmpty(t, d)\n\t}\n\tt.Log(\"Logical Drives:\", drives)\n\tassert.Contains(t, drives, `C:\\`)\n\tassert.Contains(t, drives, driveLetter+`\\`)\n}\n\nfunc TestBuildPartitionStat(t *testing.T) {\n\tvolumeC := `C:\\`\n\tpart, err := buildPartitionStat(volumeC)\n\trequire.NoError(t, err)\n\tassert.Equal(t, volumeC, part.Mountpoint)\n\tassert.Equal(t, volumeC, part.Device)\n\tassert.Equal(t, \"NTFS\", part.Fstype) // NTFS should be the only allowed fs on C: drive since windows Vista, maybe in future could be also reFS\n\tassert.Contains(t, part.Opts, rw)    // C: must have atleast rw option\n}\n\nfunc TestProcessLogicalDrives(t *testing.T) {\n\tdrives := []string{`C:\\`}\n\tpartitionStats := []PartitionStat{}\n\tprocessedPaths := map[string]struct{}{}\n\twarnings := Warnings{}\n\n\tparts := processLogicalDrives(context.Background(), drives, processedPaths, partitionStats, warnings)\n\tassert.Len(t, parts, 1)\n\tassert.Equal(t, \"C:\", parts[0].Mountpoint)\n\tassert.Equal(t, \"C:\", parts[0].Device)\n\tassert.Equal(t, \"NTFS\", parts[0].Fstype)\n\tassert.Contains(t, parts[0].Opts, rw)\n}\n"
  },
  {
    "path": "disk/types_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n// Hand writing:\n//   - add _Ctype_struct___0 struct\n//   - devstat.ID *byte -> [sizeOfPtr]byte in order to use binary.Read\n\n/*\nInput to cgo -godefs.\n\n*/\n\npackage disk\n\n/*\n#include <sys/types.h>\n#include <sys/mount.h>\n#include <devstat.h>\n\nenum {\n\tsizeofPtr = sizeof(void*),\n};\n\n// because statinfo has long double snap_time, redefine with changing long long\nstruct statinfo2 {\n        long            cp_time[CPUSTATES];\n        long            tk_nin;\n        long            tk_nout;\n        struct devinfo  *dinfo;\n        long long       snap_time;\n};\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tsizeofPtr        = C.sizeofPtr\n\tsizeofShort      = C.sizeof_short\n\tsizeofInt        = C.sizeof_int\n\tsizeofLong       = C.sizeof_long\n\tsizeofLongLong   = C.sizeof_longlong\n\tsizeofLongDouble = C.sizeof_longlong\n\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfdevstat = C.sizeof_struct_devstat\n)\n\n// Basic types\n\ntype (\n\t_C_short       C.short\n\t_C_int         C.int\n\t_C_long        C.long\n\t_C_long_long   C.longlong\n\t_C_long_double C.longlong\n)\n\ntype (\n\tdevstat C.struct_devstat\n\tbintime C.struct_bintime\n)\n"
  },
  {
    "path": "disk/types_netbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n// Hand writing: _Ctype_struct___0\n\n/*\nInput to cgo -godefs.\n*/\n\npackage disk\n\n/*\n#include <sys/types.h>\n#include <sys/statvfs.h>\n#include <sys/cdefs.h>\n#include <sys/featuretest.h>\n#include <sys/stdint.h>\n#include <machine/ansi.h>\n#include <sys/ansi.h>\n\n*/\nimport \"C\"\n\nconst (\n\tsizeOfStatvfs = C.sizeof_struct_statvfs\n)\n\ntype (\n\tStatvfs C.struct_statvfs\n)\n"
  },
  {
    "path": "disk/types_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n// Hand writing: _Ctype_struct___0\n\n/*\nInput to cgo -godefs.\n*/\n\npackage disk\n\n/*\n#include <sys/types.h>\n#include <sys/disk.h>\n#include <sys/mount.h>\n*/\nimport \"C\"\n\nconst (\n\tdevstat_NO_DATA = 0x00\n\tdevstat_READ    = 0x01\n\tdevstat_WRITE   = 0x02\n\tdevstat_FREE    = 0x03\n)\n\nconst (\n\tsizeOfDiskstats = C.sizeof_struct_diskstats\n)\n\ntype (\n\tDiskstats C.struct_diskstats\n\tTimeval   C.struct_timeval\n)\n\ntype (\n\tDiskstat C.struct_diskstat\n\tbintime  C.struct_bintime\n)\n"
  },
  {
    "path": "doc.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage gopsutil\n"
  },
  {
    "path": "docker/docker.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage docker\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar (\n\tErrDockerNotAvailable = errors.New(\"docker not available\")\n\tErrCgroupNotAvailable = errors.New(\"cgroup not available\")\n)\n\nvar invoke common.Invoker = common.Invoke{}\n\nconst nanoseconds = 1e9\n\ntype CgroupCPUStat struct {\n\tcpu.TimesStat\n\tUsage float64\n}\n\ntype CgroupMemStat struct {\n\tContainerID             string `json:\"containerID\"`\n\tCache                   uint64 `json:\"cache\"`\n\tRSS                     uint64 `json:\"rss\"`\n\tRSSHuge                 uint64 `json:\"rssHuge\"`\n\tMappedFile              uint64 `json:\"mappedFile\"`\n\tPgpgin                  uint64 `json:\"pgpgin\"`\n\tPgpgout                 uint64 `json:\"pgpgout\"`\n\tPgfault                 uint64 `json:\"pgfault\"`\n\tPgmajfault              uint64 `json:\"pgmajfault\"`\n\tInactiveAnon            uint64 `json:\"inactiveAnon\"`\n\tActiveAnon              uint64 `json:\"activeAnon\"`\n\tInactiveFile            uint64 `json:\"inactiveFile\"`\n\tActiveFile              uint64 `json:\"activeFile\"`\n\tUnevictable             uint64 `json:\"unevictable\"`\n\tHierarchicalMemoryLimit uint64 `json:\"hierarchicalMemoryLimit\"`\n\tTotalCache              uint64 `json:\"totalCache\"`\n\tTotalRSS                uint64 `json:\"totalRss\"`\n\tTotalRSSHuge            uint64 `json:\"totalRssHuge\"`\n\tTotalMappedFile         uint64 `json:\"totalMappedFile\"`\n\tTotalPgpgIn             uint64 `json:\"totalPgpgin\"`\n\tTotalPgpgOut            uint64 `json:\"totalPgpgout\"`\n\tTotalPgFault            uint64 `json:\"totalPgfault\"`\n\tTotalPgMajFault         uint64 `json:\"totalPgmajfault\"`\n\tTotalInactiveAnon       uint64 `json:\"totalInactiveAnon\"`\n\tTotalActiveAnon         uint64 `json:\"totalActiveAnon\"`\n\tTotalInactiveFile       uint64 `json:\"totalInactiveFile\"`\n\tTotalActiveFile         uint64 `json:\"totalActiveFile\"`\n\tTotalUnevictable        uint64 `json:\"totalUnevictable\"`\n\tMemUsageInBytes         uint64 `json:\"memUsageInBytes\"`\n\tMemMaxUsageInBytes      uint64 `json:\"memMaxUsageInBytes\"`\n\tMemLimitInBytes         uint64 `json:\"memoryLimitInBytes\"`\n\tMemFailCnt              uint64 `json:\"memoryFailcnt\"`\n}\n\nfunc (m CgroupMemStat) String() string {\n\ts, _ := json.Marshal(m)\n\treturn string(s)\n}\n\ntype CgroupDockerStat struct {\n\tContainerID string `json:\"containerID\"`\n\tName        string `json:\"name\"`\n\tImage       string `json:\"image\"`\n\tStatus      string `json:\"status\"`\n\tRunning     bool   `json:\"running\"`\n}\n\nfunc (c CgroupDockerStat) String() string {\n\ts, _ := json.Marshal(c)\n\treturn string(s)\n}\n"
  },
  {
    "path": "docker/docker_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage docker\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// GetDockerStat returns a list of Docker basic stats.\n// This requires certain permission.\nfunc GetDockerStat() ([]CgroupDockerStat, error) {\n\treturn GetDockerStatWithContext(context.Background())\n}\n\nfunc GetDockerStatWithContext(ctx context.Context) ([]CgroupDockerStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"docker\", \"ps\", \"-a\", \"--no-trunc\", \"--format\", \"{{.ID}}|{{.Image}}|{{.Names}}|{{.Status}}\")\n\tif err != nil {\n\t\tif errors.Is(err, exec.ErrNotFound) {\n\t\t\treturn nil, ErrDockerNotAvailable\n\t\t}\n\t\treturn []CgroupDockerStat{}, err\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\tret := make([]CgroupDockerStat, 0, len(lines))\n\n\tfor _, l := range lines {\n\t\tif l == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tcols := strings.Split(l, \"|\")\n\t\tif len(cols) != 4 {\n\t\t\tcontinue\n\t\t}\n\t\tnames := strings.Split(cols[2], \",\")\n\t\tstat := CgroupDockerStat{\n\t\t\tContainerID: cols[0],\n\t\t\tName:        names[0],\n\t\t\tImage:       cols[1],\n\t\t\tStatus:      cols[3],\n\t\t\tRunning:     strings.Contains(cols[3], \"Up\"),\n\t\t}\n\t\tret = append(ret, stat)\n\t}\n\n\treturn ret, nil\n}\n\n// GetDockerIDList returns a list of DockerID.\n// This requires certain permission.\nfunc GetDockerIDList() ([]string, error) {\n\treturn GetDockerIDListWithContext(context.Background())\n}\n\nfunc GetDockerIDListWithContext(ctx context.Context) ([]string, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"docker\", \"ps\", \"-q\", \"--no-trunc\")\n\tif err != nil {\n\t\tif errors.Is(err, exec.ErrNotFound) {\n\t\t\treturn nil, ErrDockerNotAvailable\n\t\t}\n\t\treturn []string{}, err\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\tret := make([]string, 0, len(lines))\n\n\tfor _, l := range lines {\n\t\tif l == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, l)\n\t}\n\n\treturn ret, nil\n}\n\n// CgroupCPU returns specified cgroup id CPU status.\n// containerID is same as docker id if you use docker.\n// If you use container via systemd.slice, you could use\n// containerID = docker-<container id>.scope and base=/sys/fs/cgroup/cpuacct/system.slice/\nfunc CgroupCPU(containerID, base string) (*CgroupCPUStat, error) {\n\treturn CgroupCPUWithContext(context.Background(), containerID, base)\n}\n\n// CgroupCPUUsage returns specified cgroup id CPU usage.\n// containerID is same as docker id if you use docker.\n// If you use container via systemd.slice, you could use\n// containerID = docker-<container id>.scope and base=/sys/fs/cgroup/cpuacct/system.slice/\nfunc CgroupCPUUsage(containerID, base string) (float64, error) {\n\treturn CgroupCPUUsageWithContext(context.Background(), containerID, base)\n}\n\nfunc CgroupCPUWithContext(ctx context.Context, containerID, base string) (*CgroupCPUStat, error) {\n\tstatfile := getCgroupFilePath(ctx, containerID, base, \"cpuacct\", \"cpuacct.stat\")\n\tlines, err := common.ReadLines(statfile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// empty containerID means all cgroup\n\tif containerID == \"\" {\n\t\tcontainerID = \"all\"\n\t}\n\n\tret := &CgroupCPUStat{}\n\tret.CPU = containerID\n\tfor _, line := range lines {\n\t\tfields := strings.Split(line, \" \")\n\t\tif fields[0] == \"user\" {\n\t\t\tuser, err := strconv.ParseFloat(fields[1], 64)\n\t\t\tif err == nil {\n\t\t\t\tret.User = user / cpu.ClocksPerSec\n\t\t\t}\n\t\t}\n\t\tif fields[0] == \"system\" {\n\t\t\tsystem, err := strconv.ParseFloat(fields[1], 64)\n\t\t\tif err == nil {\n\t\t\t\tret.System = system / cpu.ClocksPerSec\n\t\t\t}\n\t\t}\n\t}\n\tusage, err := CgroupCPUUsageWithContext(ctx, containerID, base)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret.Usage = usage\n\treturn ret, nil\n}\n\nfunc CgroupCPUUsageWithContext(ctx context.Context, containerID, base string) (float64, error) {\n\tusagefile := getCgroupFilePath(ctx, containerID, base, \"cpuacct\", \"cpuacct.usage\")\n\tlines, err := common.ReadLinesOffsetN(usagefile, 0, 1)\n\tif err != nil {\n\t\treturn 0.0, err\n\t}\n\n\tns, err := strconv.ParseFloat(lines[0], 64)\n\tif err != nil {\n\t\treturn 0.0, err\n\t}\n\n\treturn ns / nanoseconds, nil\n}\n\nfunc CgroupCPUDocker(containerID string) (*CgroupCPUStat, error) {\n\treturn CgroupCPUDockerWithContext(context.Background(), containerID)\n}\n\nfunc CgroupCPUUsageDocker(containerID string) (float64, error) {\n\treturn CgroupCPUDockerUsageWithContext(context.Background(), containerID)\n}\n\nfunc CgroupCPUDockerWithContext(ctx context.Context, containerID string) (*CgroupCPUStat, error) {\n\treturn CgroupCPUWithContext(ctx, containerID, common.HostSysWithContext(ctx, \"fs/cgroup/cpuacct/docker\"))\n}\n\nfunc CgroupCPUDockerUsageWithContext(ctx context.Context, containerID string) (float64, error) {\n\treturn CgroupCPUUsageWithContext(ctx, containerID, common.HostSysWithContext(ctx, \"fs/cgroup/cpuacct/docker\"))\n}\n\nfunc CgroupMem(containerID, base string) (*CgroupMemStat, error) {\n\treturn CgroupMemWithContext(context.Background(), containerID, base)\n}\n\nfunc CgroupMemWithContext(ctx context.Context, containerID, base string) (*CgroupMemStat, error) {\n\tstatfile := getCgroupFilePath(ctx, containerID, base, \"memory\", \"memory.stat\")\n\n\t// empty containerID means all cgroup\n\tif containerID == \"\" {\n\t\tcontainerID = \"all\"\n\t}\n\tlines, err := common.ReadLines(statfile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := &CgroupMemStat{ContainerID: containerID}\n\tfor _, line := range lines {\n\t\tfields := strings.Split(line, \" \")\n\t\tv, err := strconv.ParseUint(fields[1], 10, 64)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tswitch fields[0] {\n\t\tcase \"cache\":\n\t\t\tret.Cache = v\n\t\tcase \"rss\":\n\t\t\tret.RSS = v\n\t\tcase \"rssHuge\", \"rss_huge\":\n\t\t\tret.RSSHuge = v\n\t\tcase \"mappedFile\", \"mapped_file\":\n\t\t\tret.MappedFile = v\n\t\tcase \"pgpgin\":\n\t\t\tret.Pgpgin = v\n\t\tcase \"pgpgout\":\n\t\t\tret.Pgpgout = v\n\t\tcase \"pgfault\":\n\t\t\tret.Pgfault = v\n\t\tcase \"pgmajfault\":\n\t\t\tret.Pgmajfault = v\n\t\tcase \"inactiveAnon\", \"inactive_anon\":\n\t\t\tret.InactiveAnon = v\n\t\tcase \"activeAnon\", \"active_anon\":\n\t\t\tret.ActiveAnon = v\n\t\tcase \"inactiveFile\", \"inactive_file\":\n\t\t\tret.InactiveFile = v\n\t\tcase \"activeFile\", \"active_file\":\n\t\t\tret.ActiveFile = v\n\t\tcase \"unevictable\":\n\t\t\tret.Unevictable = v\n\t\tcase \"hierarchicalMemoryLimit\", \"hierarchical_memory_limit\":\n\t\t\tret.HierarchicalMemoryLimit = v\n\t\tcase \"totalCache\", \"total_cache\":\n\t\t\tret.TotalCache = v\n\t\tcase \"totalRss\", \"total_rss\":\n\t\t\tret.TotalRSS = v\n\t\tcase \"totalRssHuge\", \"total_rss_huge\":\n\t\t\tret.TotalRSSHuge = v\n\t\tcase \"totalMappedFile\", \"total_mapped_file\":\n\t\t\tret.TotalMappedFile = v\n\t\tcase \"totalPgpgin\", \"total_pgpgin\":\n\t\t\tret.TotalPgpgIn = v\n\t\tcase \"totalPgpgout\", \"total_pgpgout\":\n\t\t\tret.TotalPgpgOut = v\n\t\tcase \"totalPgfault\", \"total_pgfault\":\n\t\t\tret.TotalPgFault = v\n\t\tcase \"totalPgmajfault\", \"total_pgmajfault\":\n\t\t\tret.TotalPgMajFault = v\n\t\tcase \"totalInactiveAnon\", \"total_inactive_anon\":\n\t\t\tret.TotalInactiveAnon = v\n\t\tcase \"totalActiveAnon\", \"total_active_anon\":\n\t\t\tret.TotalActiveAnon = v\n\t\tcase \"totalInactiveFile\", \"total_inactive_file\":\n\t\t\tret.TotalInactiveFile = v\n\t\tcase \"totalActiveFile\", \"total_active_file\":\n\t\t\tret.TotalActiveFile = v\n\t\tcase \"totalUnevictable\", \"total_unevictable\":\n\t\t\tret.TotalUnevictable = v\n\t\t}\n\t}\n\n\tr, err := getCgroupMemFile(ctx, containerID, base, \"memory.usage_in_bytes\")\n\tif err == nil {\n\t\tret.MemUsageInBytes = r\n\t}\n\tr, err = getCgroupMemFile(ctx, containerID, base, \"memory.max_usage_in_bytes\")\n\tif err == nil {\n\t\tret.MemMaxUsageInBytes = r\n\t}\n\tr, err = getCgroupMemFile(ctx, containerID, base, \"memory.limit_in_bytes\")\n\tif err == nil {\n\t\tret.MemLimitInBytes = r\n\t}\n\tr, err = getCgroupMemFile(ctx, containerID, base, \"memory.failcnt\")\n\tif err == nil {\n\t\tret.MemFailCnt = r\n\t}\n\n\treturn ret, nil\n}\n\nfunc CgroupMemDocker(containerID string) (*CgroupMemStat, error) {\n\treturn CgroupMemDockerWithContext(context.Background(), containerID)\n}\n\nfunc CgroupMemDockerWithContext(ctx context.Context, containerID string) (*CgroupMemStat, error) {\n\treturn CgroupMemWithContext(ctx, containerID, common.HostSysWithContext(ctx, \"fs/cgroup/memory/docker\"))\n}\n\n// getCgroupFilePath constructs file path to get targeted stats file.\nfunc getCgroupFilePath(ctx context.Context, containerID, base, target, file string) string {\n\tif base == \"\" {\n\t\tbase = common.HostSysWithContext(ctx, fmt.Sprintf(\"fs/cgroup/%s/docker\", target))\n\t}\n\tstatfile := path.Join(base, containerID, file)\n\n\tif _, err := os.Stat(statfile); os.IsNotExist(err) {\n\t\tstatfile = path.Join(\n\t\t\tcommon.HostSysWithContext(ctx, fmt.Sprintf(\"fs/cgroup/%s/system.slice\", target)), \"docker-\"+containerID+\".scope\", file)\n\t}\n\n\treturn statfile\n}\n\n// getCgroupMemFile reads a cgroup file and return the contents as uint64.\nfunc getCgroupMemFile(ctx context.Context, containerID, base, file string) (uint64, error) {\n\tstatfile := getCgroupFilePath(ctx, containerID, base, \"memory\", file)\n\tlines, err := common.ReadLines(statfile)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif len(lines) != 1 {\n\t\treturn 0, fmt.Errorf(\"wrong format file: %s\", statfile)\n\t}\n\treturn strconv.ParseUint(lines[0], 10, 64)\n}\n"
  },
  {
    "path": "docker/docker_linux_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage docker\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetDockerIDList(_ *testing.T) {\n\t// If there is not docker environment, this test always fail.\n\t// not tested here\n\t/*\n\t\t_, err := GetDockerIDList()\n\t\tif err != nil {\n\t\t\tt.Errorf(\"error %v\", err)\n\t\t}\n\t*/\n}\n\nfunc TestGetDockerStat(_ *testing.T) {\n\t// If there is not docker environment, this test always fail.\n\t// not tested here\n\n\t/*\n\t\tret, err := GetDockerStat()\n\t\tif err != nil {\n\t\t\tt.Errorf(\"error %v\", err)\n\t\t}\n\t\tif len(ret) == 0 {\n\t\t\tt.Errorf(\"ret is empty\")\n\t\t}\n\t\tempty := CgroupDockerStat{}\n\t\tfor _, v := range ret {\n\t\t\tif empty == v {\n\t\t\t\tt.Errorf(\"empty CgroupDockerStat\")\n\t\t\t}\n\t\t\tif v.ContainerID == \"\" {\n\t\t\t\tt.Errorf(\"Could not get container id\")\n\t\t\t}\n\t\t}\n\t*/\n}\n\nfunc TestCgroupCPU(t *testing.T) {\n\tv, _ := GetDockerIDList()\n\tfor _, id := range v {\n\t\tv, err := CgroupCPUDockerWithContext(context.Background(), id)\n\t\trequire.NoError(t, err)\n\t\tassert.NotEmptyf(t, v.CPU, \"could not get CgroupCPU %v\", v)\n\n\t}\n}\n\nfunc TestCgroupCPUInvalidId(t *testing.T) {\n\t_, err := CgroupCPUDockerWithContext(context.Background(), \"bad id\")\n\tassert.Errorf(t, err, \"Expected path does not exist error\")\n}\n\nfunc TestCgroupMem(t *testing.T) {\n\tv, _ := GetDockerIDList()\n\tfor _, id := range v {\n\t\tv, err := CgroupMemDocker(id)\n\t\trequire.NoError(t, err)\n\t\tempty := &CgroupMemStat{}\n\t\tassert.NotSamef(t, v, empty, \"Could not CgroupMemStat %v\", v)\n\t}\n}\n\nfunc TestCgroupMemInvalidId(t *testing.T) {\n\t_, err := CgroupMemDocker(\"bad id\")\n\tassert.Errorf(t, err, \"Expected path does not exist error\")\n}\n"
  },
  {
    "path": "docker/docker_notlinux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !linux\n\npackage docker\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// GetDockerStat returns a list of Docker basic stats.\n// This requires certain permission.\nfunc GetDockerStat() ([]CgroupDockerStat, error) {\n\treturn GetDockerStatWithContext(context.Background())\n}\n\nfunc GetDockerStatWithContext(_ context.Context) ([]CgroupDockerStat, error) {\n\treturn nil, ErrDockerNotAvailable\n}\n\n// GetDockerIDList returns a list of DockerID.\n// This requires certain permission.\nfunc GetDockerIDList() ([]string, error) {\n\treturn GetDockerIDListWithContext(context.Background())\n}\n\nfunc GetDockerIDListWithContext(_ context.Context) ([]string, error) {\n\treturn nil, ErrDockerNotAvailable\n}\n\n// CgroupCPU returns specified cgroup id CPU status.\n// containerID is same as docker id if you use docker.\n// If you use container via systemd.slice, you could use\n// containerID = docker-<container id>.scope and base=/sys/fs/cgroup/cpuacct/system.slice/\nfunc CgroupCPU(containerID, base string) (*CgroupCPUStat, error) {\n\treturn CgroupCPUWithContext(context.Background(), containerID, base)\n}\n\nfunc CgroupCPUWithContext(_ context.Context, _, _ string) (*CgroupCPUStat, error) {\n\treturn nil, ErrCgroupNotAvailable\n}\n\nfunc CgroupCPUDocker(containerID string) (*CgroupCPUStat, error) {\n\treturn CgroupCPUDockerWithContext(context.Background(), containerID)\n}\n\nfunc CgroupCPUDockerWithContext(ctx context.Context, containerID string) (*CgroupCPUStat, error) {\n\treturn CgroupCPUWithContext(ctx, containerID, common.HostSysWithContext(ctx, \"fs/cgroup/cpuacct/docker\"))\n}\n\nfunc CgroupMem(containerID, base string) (*CgroupMemStat, error) {\n\treturn CgroupMemWithContext(context.Background(), containerID, base)\n}\n\nfunc CgroupMemWithContext(_ context.Context, _, _ string) (*CgroupMemStat, error) {\n\treturn nil, ErrCgroupNotAvailable\n}\n\nfunc CgroupMemDocker(containerID string) (*CgroupMemStat, error) {\n\treturn CgroupMemDockerWithContext(context.Background(), containerID)\n}\n\nfunc CgroupMemDockerWithContext(ctx context.Context, containerID string) (*CgroupMemStat, error) {\n\treturn CgroupMemWithContext(ctx, containerID, common.HostSysWithContext(ctx, \"fs/cgroup/memory/docker\"))\n}\n"
  },
  {
    "path": "docker/main_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage docker\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestSysAdvancedDockerInfo(_ *testing.T) {\n\tlist, err := GetDockerIDList()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\tfor _, item := range list {\n\t\tfmt.Println(item)\n\t}\n\t/*docker,err := SysAdvancedDockerInfo()\n\tif err!= nil{\n\t\tfmt.Println(err)\n\t}\n\tfmt.Printf(\"%#v\",docker)*/\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/shirou/gopsutil/v4\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/ebitengine/purego v0.10.0\n\tgithub.com/google/go-cmp v0.7.0\n\tgithub.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0\n\tgithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/tklauser/go-sysconf v0.3.16\n\tgithub.com/yusufpapurcu/wmi v1.2.4\n\tgolang.org/x/sys v0.41.0\n)\n\nrequire (\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/go-ole/go-ole v1.2.6 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/tklauser/numcpus v0.11.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=\ngithub.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=\ngithub.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=\ngithub.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=\ngithub.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=\ngithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=\ngithub.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=\ngithub.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=\ngithub.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=\ngithub.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=\ngithub.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=\ngolang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=\ngolang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "host/freebsd_headers/utxdb.h",
    "content": "/*-\n * SPDX-License-Identifier: BSD-2-Clause-FreeBSD\n *\n * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef _UTXDB_H_\n#define\t_UTXDB_H_\n\n#include <stdint.h>\n\n#define\t_PATH_UTX_ACTIVE\t\"/var/run/utx.active\"\n#define\t_PATH_UTX_LASTLOGIN\t\"/var/log/utx.lastlogin\"\n#define\t_PATH_UTX_LOG\t\t\"/var/log/utx.log\"\n\n/*\n * Entries in struct futx are ordered by how often they are used.  In\n * utx.log only entries will be written until the last non-zero byte,\n * which means we want to put the hostname at the end. Most primitive\n * records only store a ut_type and ut_tv, which means we want to store\n * those at the front.\n */\n\nstruct utmpx;\n\nstruct futx {\n\tuint8_t\t\tfu_type;\n\tuint64_t\tfu_tv;\n\tchar\t\tfu_id[8];\n\tuint32_t\tfu_pid;\n\tchar\t\tfu_user[32];\n\tchar\t\tfu_line[16];\n\tchar\t\tfu_host[128];\n} __packed;\n\nvoid\tutx_to_futx(const struct utmpx *, struct futx *);\nstruct utmpx *futx_to_utx(const struct futx *);\n\n#endif /* !_UTXDB_H_ */\n"
  },
  {
    "path": "host/host.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage host\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\ntype Warnings = common.Warnings\n\nvar invoke common.Invoker = common.Invoke{}\n\n// A HostInfoStat describes the host status.\n// This is not in the psutil but it useful.\ntype InfoStat struct {\n\tHostname             string `json:\"hostname\"`\n\tUptime               uint64 `json:\"uptime\"`\n\tBootTime             uint64 `json:\"bootTime\"`\n\tProcs                uint64 `json:\"procs\"`           // number of processes\n\tOS                   string `json:\"os\"`              // ex: freebsd, linux\n\tPlatform             string `json:\"platform\"`        // ex: ubuntu, linuxmint\n\tPlatformFamily       string `json:\"platformFamily\"`  // ex: debian, rhel\n\tPlatformVersion      string `json:\"platformVersion\"` // version of the complete OS\n\tKernelVersion        string `json:\"kernelVersion\"`   // version of the OS kernel (if available)\n\tKernelArch           string `json:\"kernelArch\"`      // native cpu architecture queried at runtime, as returned by `uname -m` or empty string in case of error\n\tVirtualizationSystem string `json:\"virtualizationSystem\"`\n\tVirtualizationRole   string `json:\"virtualizationRole\"` // guest or host\n\tHostID               string `json:\"hostId\"`             // ex: uuid\n}\n\ntype UserStat struct {\n\tUser     string `json:\"user\"`\n\tTerminal string `json:\"terminal\"`\n\tHost     string `json:\"host\"`\n\tStarted  int    `json:\"started\"`\n}\n\nfunc (h InfoStat) String() string {\n\ts, _ := json.Marshal(h)\n\treturn string(s)\n}\n\nfunc (u UserStat) String() string {\n\ts, _ := json.Marshal(u)\n\treturn string(s)\n}\n\nvar enableBootTimeCache bool\n\n// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.\nfunc EnableBootTimeCache(enable bool) {\n\tenableBootTimeCache = enable\n}\n\nfunc Info() (*InfoStat, error) {\n\treturn InfoWithContext(context.Background())\n}\n\nfunc InfoWithContext(ctx context.Context) (*InfoStat, error) {\n\tvar err error\n\tret := &InfoStat{\n\t\tOS: runtime.GOOS,\n\t}\n\n\tret.Hostname, err = os.Hostname()\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting hostname: %w\", err)\n\t}\n\n\tret.Platform, ret.PlatformFamily, ret.PlatformVersion, err = PlatformInformationWithContext(ctx)\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting platform information: %w\", err)\n\t}\n\n\tret.KernelVersion, err = KernelVersionWithContext(ctx)\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting kernel version: %w\", err)\n\t}\n\n\tret.KernelArch, err = KernelArch()\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting kernel architecture: %w\", err)\n\t}\n\n\tret.VirtualizationSystem, ret.VirtualizationRole, err = VirtualizationWithContext(ctx)\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting virtualization information: %w\", err)\n\t}\n\n\tret.BootTime, err = BootTimeWithContext(ctx)\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting boot time: %w\", err)\n\t}\n\n\tret.Uptime, err = UptimeWithContext(ctx)\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting uptime: %w\", err)\n\t}\n\n\tret.Procs, err = numProcs(ctx)\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting number of procs: %w\", err)\n\t}\n\n\tret.HostID, err = HostIDWithContext(ctx)\n\tif err != nil && !errors.Is(err, common.ErrNotImplementedError) {\n\t\treturn nil, fmt.Errorf(\"getting host ID: %w\", err)\n\t}\n\n\treturn ret, nil\n}\n\n// BootTime returns the system boot time expressed in seconds since the epoch.\nfunc BootTime() (uint64, error) {\n\treturn BootTimeWithContext(context.Background())\n}\n\nfunc Uptime() (uint64, error) {\n\treturn UptimeWithContext(context.Background())\n}\n\nfunc Users() ([]UserStat, error) {\n\treturn UsersWithContext(context.Background())\n}\n\nfunc PlatformInformation() (string, string, string, error) {\n\treturn PlatformInformationWithContext(context.Background())\n}\n\n// HostID returns the unique host ID provided by the OS.\nfunc HostID() (string, error) {\n\treturn HostIDWithContext(context.Background())\n}\n\nfunc Virtualization() (string, string, error) {\n\treturn VirtualizationWithContext(context.Background())\n}\n\nfunc KernelVersion() (string, error) {\n\treturn KernelVersionWithContext(context.Background())\n}\n"
  },
  {
    "path": "host/host_aix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage host\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// from https://www.ibm.com/docs/en/aix/7.2?topic=files-utmph-file\nconst (\n\tuser_PROCESS = 7 //nolint:revive //FIXME\n)\n\nfunc HostIDWithContext(ctx context.Context) (string, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"uname\", \"-u\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// The command always returns an extra newline, so we make use of Split() to get only the first line\n\treturn strings.Split(string(out), \"\\n\")[0], nil\n}\n\nfunc BootTimeWithContext(ctx context.Context) (btime uint64, err error) {\n\treturn common.BootTimeWithContext(ctx, invoke)\n}\n\n// Uses ps to get the elapsed time for PID 1 in DAYS-HOURS:MINUTES:SECONDS format.\nfunc UptimeWithContext(ctx context.Context) (uint64, error) {\n\treturn common.UptimeWithContext(ctx, invoke)\n}\n\n// This is a weak implementation due to the limitations on retrieving this data in AIX\nfunc UsersWithContext(ctx context.Context) ([]UserStat, error) {\n\tvar ret []UserStat\n\tout, err := invoke.CommandWithContext(ctx, \"w\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\tif len(lines) < 3 {\n\t\treturn []UserStat{}, common.ErrNotImplementedError\n\t}\n\n\thf := strings.Fields(lines[1]) // headers\n\tfor l := 2; l < len(lines); l++ {\n\t\tv := strings.Fields(lines[l]) // values\n\t\tif len(v) == 0 || v[0] == \"-\" {\n\t\t\tcontinue\n\t\t}\n\t\tus := &UserStat{}\n\t\tfor i, header := range hf {\n\t\t\tif i >= len(v) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tswitch header {\n\t\t\tcase \"User\":\n\t\t\t\tus.User = v[i]\n\t\t\tcase \"tty\":\n\t\t\t\tus.Terminal = v[i]\n\t\t\t}\n\t\t}\n\n\t\t// Valid User data, so append it\n\t\tret = append(ret, *us)\n\t}\n\n\treturn ret, nil\n}\n\n// Much of this function could be static. However, to be future proofed, I've made it call the OS for the information in all instances.\nfunc PlatformInformationWithContext(ctx context.Context) (platform, family, version string, err error) {\n\t// Set the platform (which should always, and only be, \"AIX\") from `uname -s`\n\tout, err := invoke.CommandWithContext(ctx, \"uname\", \"-s\")\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", err\n\t}\n\tplatform = strings.TrimRight(string(out), \"\\n\")\n\n\t// Set the family\n\tfamily = strings.TrimRight(string(out), \"\\n\")\n\n\t// Set the version\n\tout, err = invoke.CommandWithContext(ctx, \"oslevel\")\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", err\n\t}\n\tversion = strings.TrimRight(string(out), \"\\n\")\n\n\treturn platform, family, version, nil\n}\n\nfunc KernelVersionWithContext(ctx context.Context) (version string, err error) {\n\tout, err := invoke.CommandWithContext(ctx, \"oslevel\", \"-s\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tversion = strings.TrimRight(string(out), \"\\n\")\n\n\treturn version, nil\n}\n\nfunc KernelArch() (arch string, err error) {\n\tout, err := invoke.Command(\"bootinfo\", \"-y\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tarch = strings.TrimRight(string(out), \"\\n\")\n\n\treturn arch, nil\n}\n\nfunc VirtualizationWithContext(_ context.Context) (string, string, error) {\n\treturn \"\", \"\", common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "host/host_aix_cgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && cgo\n\npackage host\n\nimport (\n\t\"context\"\n\n\t\"github.com/power-devops/perfstat\"\n)\n\nfunc numProcs(_ context.Context) (uint64, error) {\n\tprocs, err := perfstat.ProcessStat()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(len(procs)), nil\n}\n"
  },
  {
    "path": "host/host_aix_nocgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && !cgo\n\npackage host\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc numProcs(_ context.Context) (uint64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "host/host_aix_ppc64.go",
    "content": "//go:build aix && ppc64 && cgo\n\n// Guessed at from the following document:\n// https://www.ibm.com/docs/sl/ibm-mq/9.2?topic=platforms-standard-data-types-aix-linux-windows\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType              int16\n\tPad_cgo_0         [2]byte\n\tPid               int32\n\tLine              [32]int8\n\tId                [4]int8\n\tUser              [32]int8\n\tHost              [256]int8\n\tExit              exit_status\n\tSession           int32\n\tTv                timeval\n\tAddr_v6           [4]int32\n\tX__glibc_reserved [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int64\n\tUsec int64\n}\n"
  },
  {
    "path": "host/host_aix_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage host\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBootTimeWithContext(t *testing.T) {\n\t// This is a wrapper function that delegates to common.BootTimeWithContext\n\t// Actual implementation testing is done in common_aix_test.go\n\tbootTime, err := BootTimeWithContext(context.TODO())\n\trequire.NoError(t, err)\n\tassert.Positive(t, bootTime)\n}\n\nfunc TestUptimeWithContext(t *testing.T) {\n\t// This is a wrapper function that delegates to common.UptimeWithContext\n\t// Actual implementation testing is done in common_aix_test.go\n\tuptime, err := UptimeWithContext(context.TODO())\n\trequire.NoError(t, err)\n\tassert.Positive(t, uptime)\n}\n"
  },
  {
    "path": "host/host_bsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin || freebsd || openbsd || netbsd\n\npackage host\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// cachedBootTime must be accessed via atomic.Load/StoreUint64\nvar cachedBootTime uint64\n\nfunc BootTimeWithContext(_ context.Context) (uint64, error) {\n\tif enableBootTimeCache {\n\t\tt := atomic.LoadUint64(&cachedBootTime)\n\t\tif t != 0 {\n\t\t\treturn t, nil\n\t\t}\n\t}\n\ttv, err := unix.SysctlTimeval(\"kern.boottime\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tif enableBootTimeCache {\n\t\tatomic.StoreUint64(&cachedBootTime, uint64(tv.Sec))\n\t}\n\n\treturn uint64(tv.Sec), nil\n}\n\nfunc UptimeWithContext(ctx context.Context) (uint64, error) {\n\tboot, err := BootTimeWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn common.TimeSince(boot), nil\n}\n"
  },
  {
    "path": "host/host_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage host\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/process\"\n)\n\n// from utmpx.h\nconst user_PROCESS = 7 //nolint:revive //FIXME\n\nfunc HostIDWithContext(ctx context.Context) (string, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"ioreg\", \"-rd1\", \"-c\", \"IOPlatformExpertDevice\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfor _, line := range strings.Split(string(out), \"\\n\") {\n\t\tif strings.Contains(line, \"IOPlatformUUID\") {\n\t\t\tparts := strings.SplitAfter(line, `\" = \"`)\n\t\t\tif len(parts) == 2 {\n\t\t\t\tuuid := strings.TrimRight(parts[1], `\"`)\n\t\t\t\treturn strings.ToLower(uuid), nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\", errors.New(\"cannot find host id\")\n}\n\nfunc numProcs(ctx context.Context) (uint64, error) {\n\tprocs, err := process.PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(len(procs)), nil\n}\n\nfunc UsersWithContext(_ context.Context) ([]UserStat, error) {\n\tutmpfile := \"/var/run/utmpx\"\n\tvar ret []UserStat\n\n\tfile, err := os.Open(utmpfile)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tdefer file.Close()\n\n\tbuf, err := io.ReadAll(file)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\t// Skip macOS utmpx header part\n\tconst ut32Size = int(unsafe.Sizeof(utmpx32{}))\n\tbuf = buf[ut32Size:]\n\n\tcount := len(buf) / ut32Size\n\n\tfor i := range count {\n\t\tb := buf[i*ut32Size : i*ut32Size+ut32Size]\n\n\t\tvar u utmpx32\n\t\tcopy(unsafe.Slice((*byte)(unsafe.Pointer(&u)), len(b)), b)\n\t\tif u.Type != user_PROCESS {\n\t\t\tcontinue\n\t\t}\n\t\tuser := UserStat{\n\t\t\tUser:     common.IntToString(u.User[:]),\n\t\t\tTerminal: common.IntToString(u.Line[:]),\n\t\t\tHost:     common.IntToString(u.Host[:]),\n\t\t\tStarted:  int(u.Tv.Sec),\n\t\t}\n\t\tret = append(ret, user)\n\t}\n\n\treturn ret, nil\n}\n\nfunc PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {\n\tplatform := \"\"\n\tfamily := \"\"\n\tpver := \"\"\n\n\tp, err := unix.Sysctl(\"kern.ostype\")\n\tif err == nil {\n\t\tplatform = strings.ToLower(p)\n\t}\n\n\tout, err := invoke.CommandWithContext(ctx, \"sw_vers\", \"-productVersion\")\n\tif err == nil {\n\t\tpver = strings.ToLower(strings.TrimSpace(string(out)))\n\t}\n\n\t// check if the macos server version file exists\n\t_, err = os.Stat(\"/System/Library/CoreServices/ServerVersion.plist\")\n\n\t// server file doesn't exist\n\tif os.IsNotExist(err) {\n\t\tfamily = \"Standalone Workstation\"\n\t} else {\n\t\tfamily = \"Server\"\n\t}\n\n\treturn platform, family, pver, nil\n}\n\nfunc VirtualizationWithContext(_ context.Context) (string, string, error) {\n\treturn \"\", \"\", common.ErrNotImplementedError\n}\n\nfunc KernelVersionWithContext(_ context.Context) (string, error) {\n\tversion, err := unix.Sysctl(\"kern.osrelease\")\n\treturn strings.ToLower(version), err\n}\n"
  },
  {
    "path": "host/host_darwin_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_darwin.go\n\npackage host\n\ntype utmpx32 struct {\n\tUser [256]int8\n\tId   [4]int8\n\tLine [32]int8\n\tPid  int32\n\tType int16\n\tTv   timeval32\n\tHost [256]int8\n\tPad  [16]uint32\n}\n\ntype timeval32 struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_darwin_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs host/types_darwin.go\n\npackage host\n\ntype utmpx32 struct {\n\tUser [256]int8\n\tId   [4]int8\n\tLine [32]int8\n\tPid  int32\n\tType int16\n\tTv   timeval32\n\tHost [256]int8\n\tPad  [16]uint32\n}\n\ntype timeval32 struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows && !aix\n\npackage host\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc HostIDWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc numProcs(_ context.Context) (uint64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc BootTimeWithContext(_ context.Context) (uint64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc UptimeWithContext(_ context.Context) (uint64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc UsersWithContext(_ context.Context) ([]UserStat, error) {\n\treturn []UserStat{}, common.ErrNotImplementedError\n}\n\nfunc VirtualizationWithContext(_ context.Context) (string, string, error) {\n\treturn \"\", \"\", common.ErrNotImplementedError\n}\n\nfunc KernelVersionWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc PlatformInformationWithContext(_ context.Context) (string, string, string, error) {\n\treturn \"\", \"\", \"\", common.ErrNotImplementedError\n}\n\nfunc KernelArch() (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "host/host_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd\n\npackage host\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"io\"\n\t\"math\"\n\t\"os\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/process\"\n)\n\nconst (\n\tUTNameSize = 16 /* see MAXLOGNAME in <sys/param.h> */\n\tUTLineSize = 8\n\tUTHostSize = 16\n)\n\nfunc HostIDWithContext(_ context.Context) (string, error) {\n\tuuid, err := unix.Sysctl(\"kern.hostuuid\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn strings.ToLower(uuid), err\n}\n\nfunc numProcs(ctx context.Context) (uint64, error) {\n\tprocs, err := process.PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(len(procs)), nil\n}\n\nfunc UsersWithContext(_ context.Context) ([]UserStat, error) {\n\tutmpfile := \"/var/run/utx.active\"\n\tif !common.PathExists(utmpfile) {\n\t\tutmpfile = \"/var/run/utmp\" // before 9.0\n\t\treturn getUsersFromUtmp(utmpfile)\n\t}\n\n\tvar ret []UserStat\n\tfile, err := os.Open(utmpfile)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tdefer file.Close()\n\n\tbuf, err := io.ReadAll(file)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tentrySize := sizeOfUtmpx\n\tcount := len(buf) / entrySize\n\n\tfor i := 0; i < count; i++ {\n\t\tb := buf[i*sizeOfUtmpx : (i+1)*sizeOfUtmpx]\n\t\tvar u Utmpx\n\t\tbr := bytes.NewReader(b)\n\t\terr := binary.Read(br, binary.BigEndian, &u)\n\t\tif err != nil || u.Type != 4 {\n\t\t\tcontinue\n\t\t}\n\t\tsec := math.Floor(float64(u.Tv) / 1000000)\n\t\tuser := UserStat{\n\t\t\tUser:     common.IntToString(u.User[:]),\n\t\t\tTerminal: common.IntToString(u.Line[:]),\n\t\t\tHost:     common.IntToString(u.Host[:]),\n\t\t\tStarted:  int(sec),\n\t\t}\n\n\t\tret = append(ret, user)\n\t}\n\n\treturn ret, nil\n}\n\nfunc PlatformInformationWithContext(_ context.Context) (string, string, string, error) {\n\tplatform, err := unix.Sysctl(\"kern.ostype\")\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", err\n\t}\n\n\tversion, err := unix.Sysctl(\"kern.osrelease\")\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", err\n\t}\n\n\treturn strings.ToLower(platform), \"\", strings.ToLower(version), nil\n}\n\nfunc VirtualizationWithContext(_ context.Context) (string, string, error) {\n\treturn \"\", \"\", common.ErrNotImplementedError\n}\n\n// before 9.0\nfunc getUsersFromUtmp(utmpfile string) ([]UserStat, error) {\n\tvar ret []UserStat\n\tfile, err := os.Open(utmpfile)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tdefer file.Close()\n\n\tbuf, err := io.ReadAll(file)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tentrySize := int(unsafe.Sizeof(Utmp{}))\n\tcount := len(buf) / entrySize\n\n\tfor i := 0; i < count; i++ {\n\t\tb := buf[i*entrySize : i*entrySize+entrySize]\n\t\tvar u Utmp\n\t\tbr := bytes.NewReader(b)\n\t\terr := binary.Read(br, binary.LittleEndian, &u)\n\t\tif err != nil || u.Time == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tuser := UserStat{\n\t\t\tUser:     common.IntToString(u.Name[:]),\n\t\t\tTerminal: common.IntToString(u.Line[:]),\n\t\t\tHost:     common.IntToString(u.Host[:]),\n\t\t\tStarted:  int(u.Time),\n\t\t}\n\n\t\tret = append(ret, user)\n\t}\n\n\treturn ret, nil\n}\n\nfunc KernelVersionWithContext(ctx context.Context) (string, error) {\n\t_, _, version, err := PlatformInformationWithContext(ctx)\n\treturn version, err\n}\n"
  },
  {
    "path": "host/host_freebsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs types_freebsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmpx    = 0xc5\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype Utmp struct {\n\tLine [8]int8\n\tName [16]int8\n\tHost [16]int8\n\tTime int32\n}\n\ntype Utmpx struct {\n\tType uint8\n\tTv   uint64\n\tId   [8]int8\n\tPid  uint32\n\tUser [32]int8\n\tLine [16]int8\n\tHost [128]int8\n}\n"
  },
  {
    "path": "host/host_freebsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs types_freebsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmpx    = 0xc5\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Utmp struct {\n\tLine [8]int8\n\tName [16]int8\n\tHost [16]int8\n\tTime int32\n}\n\ntype Utmpx struct {\n\tType uint8\n\tTv   uint64\n\tId   [8]int8\n\tPid  uint32\n\tUser [32]int8\n\tLine [16]int8\n\tHost [128]int8\n}\n"
  },
  {
    "path": "host/host_freebsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs types_freebsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmpx    = 0xc5\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype Utmp struct {\n\tLine [8]int8\n\tName [16]int8\n\tHost [16]int8\n\tTime int32\n}\n\ntype Utmpx struct {\n\tType uint8\n\tTv   uint64\n\tId   [8]int8\n\tPid  uint32\n\tUser [32]int8\n\tLine [16]int8\n\tHost [128]int8\n}\n"
  },
  {
    "path": "host/host_freebsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs host/types_freebsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmpx    = 0xc5\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Utmp struct {\n\tLine [8]int8\n\tName [16]int8\n\tHost [16]int8\n\tTime int32\n}\n\ntype Utmpx struct {\n\tType uint8\n\tTv   uint64\n\tId   [8]int8\n\tPid  uint32\n\tUser [32]int8\n\tLine [16]int8\n\tHost [128]int8\n}\n"
  },
  {
    "path": "host/host_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage host\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\ntype lsbStruct struct {\n\tID          string\n\tRelease     string\n\tCodename    string\n\tDescription string\n}\n\n// from utmp.h\nconst (\n\tuser_PROCESS = 7 //nolint:revive //FIXME\n)\n\nfunc HostIDWithContext(ctx context.Context) (string, error) {\n\tsysProductUUID := common.HostSysWithContext(ctx, \"class/dmi/id/product_uuid\")\n\tmachineID := common.HostEtcWithContext(ctx, \"machine-id\")\n\tprocSysKernelRandomBootID := common.HostProcWithContext(ctx, \"sys/kernel/random/boot_id\")\n\tswitch {\n\t// In order to read this file, needs to be supported by kernel/arch and run as root\n\t// so having fallback is important\n\tcase common.PathExists(sysProductUUID):\n\t\tlines, err := common.ReadLines(sysProductUUID)\n\t\tif err == nil && len(lines) > 0 && lines[0] != \"\" {\n\t\t\treturn strings.ToLower(lines[0]), nil\n\t\t}\n\t\tfallthrough\n\t// Fallback on GNU Linux systems with systemd, readable by everyone\n\tcase common.PathExists(machineID):\n\t\tlines, err := common.ReadLines(machineID)\n\t\tif err == nil && len(lines) > 0 && len(lines[0]) == 32 {\n\t\t\tst := lines[0]\n\t\t\treturn fmt.Sprintf(\"%s-%s-%s-%s-%s\", st[0:8], st[8:12], st[12:16], st[16:20], st[20:32]), nil\n\t\t}\n\t\tfallthrough\n\t// Not stable between reboot, but better than nothing\n\tdefault:\n\t\tlines, err := common.ReadLines(procSysKernelRandomBootID)\n\t\tif err == nil && len(lines) > 0 && lines[0] != \"\" {\n\t\t\treturn strings.ToLower(lines[0]), nil\n\t\t}\n\t}\n\n\treturn \"\", nil\n}\n\nfunc numProcs(ctx context.Context) (uint64, error) {\n\treturn common.NumProcsWithContext(ctx)\n}\n\nfunc BootTimeWithContext(ctx context.Context) (uint64, error) {\n\treturn common.BootTimeWithContext(ctx, enableBootTimeCache)\n}\n\nfunc UptimeWithContext(_ context.Context) (uint64, error) {\n\tsysinfo := &unix.Sysinfo_t{}\n\tif err := unix.Sysinfo(sysinfo); err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(sysinfo.Uptime), nil\n}\n\nfunc UsersWithContext(ctx context.Context) ([]UserStat, error) {\n\tutmpfile := common.HostVarWithContext(ctx, \"run/utmp\")\n\n\tfile, err := os.Open(utmpfile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer file.Close()\n\n\tbuf, err := io.ReadAll(file)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcount := len(buf) / sizeOfUtmp\n\n\tret := make([]UserStat, 0, count)\n\n\tfor i := 0; i < count; i++ {\n\t\tb := buf[i*sizeOfUtmp : (i+1)*sizeOfUtmp]\n\n\t\tvar u utmp\n\t\tbr := bytes.NewReader(b)\n\t\terr := binary.Read(br, binary.LittleEndian, &u)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif u.Type != user_PROCESS {\n\t\t\tcontinue\n\t\t}\n\t\tuser := UserStat{\n\t\t\tUser:     common.IntToString(u.User[:]),\n\t\t\tTerminal: common.IntToString(u.Line[:]),\n\t\t\tHost:     common.IntToString(u.Host[:]),\n\t\t\tStarted:  int(u.Tv.Sec),\n\t\t}\n\t\tret = append(ret, user)\n\t}\n\n\treturn ret, nil\n}\n\nfunc getlsbStruct(ctx context.Context) (*lsbStruct, error) {\n\tret := &lsbStruct{}\n\tif common.PathExists(common.HostEtcWithContext(ctx, \"lsb-release\")) {\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"lsb-release\"))\n\t\tif err != nil {\n\t\t\treturn ret, err // return empty\n\t\t}\n\t\tfor _, line := range contents {\n\t\t\tfield := strings.Split(line, \"=\")\n\t\t\tif len(field) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tswitch field[0] {\n\t\t\tcase \"DISTRIB_ID\":\n\t\t\t\tret.ID = strings.ReplaceAll(field[1], `\"`, ``)\n\t\t\tcase \"DISTRIB_RELEASE\":\n\t\t\t\tret.Release = strings.ReplaceAll(field[1], `\"`, ``)\n\t\t\tcase \"DISTRIB_CODENAME\":\n\t\t\t\tret.Codename = strings.ReplaceAll(field[1], `\"`, ``)\n\t\t\tcase \"DISTRIB_DESCRIPTION\":\n\t\t\t\tret.Description = strings.ReplaceAll(field[1], `\"`, ``)\n\t\t\t}\n\t\t}\n\t} else if common.PathExists(\"/usr/bin/lsb_release\") {\n\t\tout, err := invoke.Command(\"/usr/bin/lsb_release\")\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tfor _, line := range strings.Split(string(out), \"\\n\") {\n\t\t\tfield := strings.Split(line, \":\")\n\t\t\tif len(field) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tswitch field[0] {\n\t\t\tcase \"Distributor ID\":\n\t\t\t\tret.ID = strings.ReplaceAll(field[1], `\"`, ``)\n\t\t\tcase \"Release\":\n\t\t\t\tret.Release = strings.ReplaceAll(field[1], `\"`, ``)\n\t\t\tcase \"Codename\":\n\t\t\t\tret.Codename = strings.ReplaceAll(field[1], `\"`, ``)\n\t\t\tcase \"Description\":\n\t\t\t\tret.Description = strings.ReplaceAll(field[1], `\"`, ``)\n\t\t\t}\n\t\t}\n\n\t}\n\n\treturn ret, nil\n}\n\nfunc PlatformInformationWithContext(ctx context.Context) (platform, family, version string, err error) {\n\tlsb, err := getlsbStruct(ctx)\n\tif err != nil {\n\t\tlsb = &lsbStruct{}\n\t}\n\n\tswitch {\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"oracle-release\")):\n\t\tplatform = \"oracle\"\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"oracle-release\"))\n\t\tif err == nil {\n\t\t\tversion = getRedhatishVersion(contents)\n\t\t}\n\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"enterprise-release\")):\n\t\tplatform = \"oracle\"\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"enterprise-release\"))\n\t\tif err == nil {\n\t\t\tversion = getRedhatishVersion(contents)\n\t\t}\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"slackware-version\")):\n\t\tplatform = \"slackware\"\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"slackware-version\"))\n\t\tif err == nil {\n\t\t\tversion = getSlackwareVersion(contents)\n\t\t}\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"debian_version\")):\n\t\tswitch lsb.ID {\n\t\tcase \"Ubuntu\":\n\t\t\tplatform = \"ubuntu\"\n\t\t\tversion = lsb.Release\n\t\tcase \"LinuxMint\":\n\t\t\tplatform = \"linuxmint\"\n\t\t\tversion = lsb.Release\n\t\tcase \"Kylin\":\n\t\t\tplatform = \"Kylin\"\n\t\t\tversion = lsb.Release\n\t\tcase `\"Cumulus Linux\"`:\n\t\t\tplatform = \"cumuluslinux\"\n\t\t\tversion = lsb.Release\n\t\tcase \"uos\":\n\t\t\tplatform = \"uos\"\n\t\t\tversion = lsb.Release\n\t\tcase \"Deepin\":\n\t\t\tplatform = \"Deepin\"\n\t\t\tversion = lsb.Release\n\t\tdefault:\n\t\t\tif common.PathExistsWithContents(\"/usr/bin/raspi-config\") {\n\t\t\t\tplatform = \"raspbian\"\n\t\t\t} else {\n\t\t\t\tplatform = \"debian\"\n\t\t\t}\n\t\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"debian_version\"))\n\t\t\tif err == nil && len(contents) > 0 && contents[0] != \"\" {\n\t\t\t\tversion = contents[0]\n\t\t\t}\n\t\t}\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"neokylin-release\")):\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"neokylin-release\"))\n\t\tif err == nil {\n\t\t\tversion = getRedhatishVersion(contents)\n\t\t\tplatform = getRedhatishPlatform(contents)\n\t\t}\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"redhat-release\")):\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"redhat-release\"))\n\t\tif err == nil {\n\t\t\tversion = getRedhatishVersion(contents)\n\t\t\tplatform = getRedhatishPlatform(contents)\n\t\t}\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"system-release\")):\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"system-release\"))\n\t\tif err == nil {\n\t\t\tversion = getRedhatishVersion(contents)\n\t\t\tplatform = getRedhatishPlatform(contents)\n\t\t}\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"gentoo-release\")):\n\t\tplatform = \"gentoo\"\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"gentoo-release\"))\n\t\tif err == nil {\n\t\t\tversion = getRedhatishVersion(contents)\n\t\t}\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"SuSE-release\")):\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"SuSE-release\"))\n\t\tif err == nil {\n\t\t\tversion = getSuseVersion(contents)\n\t\t\tplatform = getSusePlatform(contents)\n\t\t}\n\t\t// TODO: slackware detection\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"arch-release\")):\n\t\tplatform = \"arch\"\n\t\tversion = lsb.Release\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"alpine-release\")):\n\t\tplatform = \"alpine\"\n\t\tcontents, err := common.ReadLines(common.HostEtcWithContext(ctx, \"alpine-release\"))\n\t\tif err == nil && len(contents) > 0 && contents[0] != \"\" {\n\t\t\tversion = contents[0]\n\t\t}\n\tcase common.PathExistsWithContents(common.HostEtcWithContext(ctx, \"os-release\")):\n\t\tp, v, err := common.GetOSReleaseWithContext(ctx)\n\t\tif err == nil {\n\t\t\tplatform = p\n\t\t\tversion = v\n\t\t}\n\tcase lsb.ID == \"RedHat\":\n\t\tplatform = \"redhat\"\n\t\tversion = lsb.Release\n\tcase lsb.ID == \"Amazon\":\n\t\tplatform = \"amazon\"\n\t\tversion = lsb.Release\n\tcase lsb.ID == \"ScientificSL\":\n\t\tplatform = \"scientific\"\n\t\tversion = lsb.Release\n\tcase lsb.ID == \"XenServer\":\n\t\tplatform = \"xenserver\"\n\t\tversion = lsb.Release\n\tcase lsb.ID != \"\":\n\t\tplatform = strings.ToLower(lsb.ID)\n\t\tversion = lsb.Release\n\t}\n\n\tplatform = strings.Trim(platform, `\"`)\n\n\tswitch platform {\n\tcase \"debian\", \"ubuntu\", \"linuxmint\", \"raspbian\", \"Kylin\", \"cumuluslinux\", \"uos\", \"Deepin\":\n\t\tfamily = \"debian\"\n\tcase \"fedora\":\n\t\tfamily = \"fedora\"\n\tcase \"oracle\", \"centos\", \"redhat\", \"scientific\", \"enterpriseenterprise\", \"amazon\", \"xenserver\", \"cloudlinux\", \"ibm_powerkvm\", \"rocky\", \"almalinux\":\n\t\tfamily = \"rhel\"\n\tcase \"suse\", \"opensuse\", \"opensuse-leap\", \"opensuse-tumbleweed\", \"opensuse-tumbleweed-kubic\", \"sles\", \"sled\", \"caasp\":\n\t\tfamily = \"suse\"\n\tcase \"gentoo\":\n\t\tfamily = \"gentoo\"\n\tcase \"slackware\":\n\t\tfamily = \"slackware\"\n\tcase \"arch\":\n\t\tfamily = \"arch\"\n\tcase \"exherbo\":\n\t\tfamily = \"exherbo\"\n\tcase \"alpine\":\n\t\tfamily = \"alpine\"\n\tcase \"coreos\":\n\t\tfamily = \"coreos\"\n\tcase \"solus\":\n\t\tfamily = \"solus\"\n\tcase \"neokylin\":\n\t\tfamily = \"neokylin\"\n\tcase \"anolis\":\n\t\tfamily = \"anolis\"\n\t}\n\n\treturn platform, family, version, nil\n}\n\nfunc KernelVersionWithContext(_ context.Context) (version string, err error) {\n\tvar utsname unix.Utsname\n\terr = unix.Uname(&utsname)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn unix.ByteSliceToString(utsname.Release[:]), nil\n}\n\nfunc getSlackwareVersion(contents []string) string {\n\tc := strings.ToLower(strings.Join(contents, \"\"))\n\tc = strings.Replace(c, \"slackware \", \"\", 1)\n\treturn c\n}\n\nvar redhatishReleaseMatch = regexp.MustCompile(`release (\\w[\\d.]*)`)\n\nfunc getRedhatishVersion(contents []string) string {\n\tc := strings.ToLower(strings.Join(contents, \"\"))\n\n\tif strings.Contains(c, \"rawhide\") {\n\t\treturn \"rawhide\"\n\t}\n\tif matches := redhatishReleaseMatch.FindStringSubmatch(c); matches != nil {\n\t\treturn matches[1]\n\t}\n\treturn \"\"\n}\n\nfunc getRedhatishPlatform(contents []string) string {\n\tc := strings.ToLower(strings.Join(contents, \"\"))\n\n\tif strings.Contains(c, \"red hat\") {\n\t\treturn \"redhat\"\n\t}\n\tf := strings.Split(c, \" \")\n\n\treturn f[0]\n}\n\nvar (\n\tsuseVersionMatch    = regexp.MustCompile(`VERSION = ([\\d.]+)`)\n\tsusePatchLevelMatch = regexp.MustCompile(`PATCHLEVEL = (\\d+)`)\n)\n\nfunc getSuseVersion(contents []string) string {\n\tversion := \"\"\n\tfor _, line := range contents {\n\t\tif matches := suseVersionMatch.FindStringSubmatch(line); matches != nil {\n\t\t\tversion = matches[1]\n\t\t} else if matches = susePatchLevelMatch.FindStringSubmatch(line); matches != nil {\n\t\t\tversion = version + \".\" + matches[1]\n\t\t}\n\t}\n\treturn version\n}\n\nfunc getSusePlatform(contents []string) string {\n\tc := strings.ToLower(strings.Join(contents, \"\"))\n\tif strings.Contains(c, \"opensuse\") {\n\t\treturn \"opensuse\"\n\t}\n\treturn \"suse\"\n}\n\nfunc VirtualizationWithContext(ctx context.Context) (string, string, error) {\n\treturn common.VirtualizationWithContext(ctx)\n}\n"
  },
  {
    "path": "host/host_linux_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// ATTENTION - FILE MANUAL FIXED AFTER CGO.\n// Fixed line: Tv\t\t_Ctype_struct_timeval -> Tv\t\tUtTv\n// Created by cgo -godefs, MANUAL FIXED\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16 //nolint:revive //FIXME\n\t_C_int       int32 //nolint:revive //FIXME\n\t_C_long      int32 //nolint:revive //FIXME\n\t_C_long_long int64 //nolint:revive //FIXME\n)\n\ntype utmp struct {\n\tType      int16\n\tPad_cgo_0 [2]byte //nolint:revive //FIXME\n\tPid       int32\n\tLine      [32]int8\n\tID        [4]int8\n\tUser      [32]int8\n\tHost      [256]int8\n\tExit      exit_status\n\tSession   int32\n\tTv        UtTv\n\tAddr_v6   [4]int32 //nolint:revive //FIXME\n\tX__unused [20]int8 //nolint:revive //FIXME\n}\n\ntype exit_status struct { //nolint:revive //FIXME\n\tTermination int16\n\tExit        int16\n}\n\ntype UtTv struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_linux_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType              int16\n\tPad_cgo_0         [2]byte\n\tPid               int32\n\tLine              [32]int8\n\tId                [4]int8\n\tUser              [32]int8\n\tHost              [256]int8\n\tExit              exit_status\n\tSession           int32\n\tTv                _Ctype_struct___0\n\tAddr_v6           [4]int32\n\tX__glibc_reserved [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype _Ctype_struct___0 struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_linux_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go | sed \"s/uint8/int8/g\"\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType              int16\n\tPad_cgo_0         [2]byte\n\tPid               int32\n\tLine              [32]int8\n\tId                [4]int8\n\tUser              [32]int8\n\tHost              [256]int8\n\tExit              exit_status\n\tSession           int32\n\tTv                timeval\n\tAddr_v6           [4]int32\n\tX__glibc_reserved [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_linux_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x190\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype (\n\tutmp struct {\n\t\tType              int16\n\t\tPad_cgo_0         [2]byte // changed by hand #1603\n\t\tPid               int32\n\t\tLine              [32]int8  // changed by hand\n\t\tId                [4]int8   // changed by hand\n\t\tUser              [32]int8  // changed by hand\n\t\tHost              [256]int8 // changed by hand\n\t\tExit              exit_status\n\t\tSession           int64\n\t\tTv                timeval\n\t\tAddr_v6           [4]int32\n\t\tX__glibc_reserved [20]uint8\n\t\tPad_cgo_1         [4]byte\n\t}\n\texit_status struct {\n\t\tTermination int16\n\t\tExit        int16\n\t}\n\ttimeval struct {\n\t\tSec  int64\n\t\tUsec int64\n\t}\n)\n"
  },
  {
    "path": "host/host_linux_loong64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs host/types_linux.go\n\n//go:build linux && loong64\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x190\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype (\n\tutmp struct {\n\t\tType              int16\n\t\tPid               int32\n\t\tLine              [32]int8\n\t\tId                [4]int8\n\t\tUser              [32]int8\n\t\tHost              [256]int8\n\t\tExit              exit_status\n\t\tSession           int64\n\t\tTv                timeval\n\t\tAddr_v6           [4]int32\n\t\tX__glibc_reserved [20]int8\n\t\tPad_cgo_0         [4]byte\n\t}\n\texit_status struct {\n\t\tTermination int16\n\t\tExit        int16\n\t}\n\ttimeval struct {\n\t\tSec  int64\n\t\tUsec int64\n\t}\n)\n"
  },
  {
    "path": "host/host_linux_mips.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType      int16\n\tPad_cgo_0 [2]byte\n\tPid       int32\n\tLine      [32]int8\n\tId        [4]int8\n\tUser      [32]int8\n\tHost      [256]int8\n\tExit      exit_status\n\tSession   int32\n\tTv        timeval\n\tAddr_v6   [4]int32\n\tX__unused [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_linux_mips64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType      int16\n\tPad_cgo_0 [2]byte\n\tPid       int32\n\tLine      [32]int8\n\tId        [4]int8\n\tUser      [32]int8\n\tHost      [256]int8\n\tExit      exit_status\n\tSession   int32\n\tTv        timeval\n\tAddr_v6   [4]int32\n\tX__unused [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_linux_mips64le.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType      int16\n\tPad_cgo_0 [2]byte\n\tPid       int32\n\tLine      [32]int8\n\tId        [4]int8\n\tUser      [32]int8\n\tHost      [256]int8\n\tExit      exit_status\n\tSession   int32\n\tTv        timeval\n\tAddr_v6   [4]int32\n\tX__unused [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_linux_mipsle.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType      int16\n\tPad_cgo_0 [2]byte\n\tPid       int32\n\tLine      [32]int8\n\tId        [4]int8\n\tUser      [32]int8\n\tHost      [256]int8\n\tExit      exit_status\n\tSession   int32\n\tTv        timeval\n\tAddr_v6   [4]int32\n\tX__unused [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_linux_ppc64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux && ppc64\n\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType              int16\n\tPad_cgo_0         [2]byte\n\tPid               int32\n\tLine              [32]int8\n\tId                [4]int8\n\tUser              [32]int8\n\tHost              [256]int8\n\tExit              exit_status\n\tSession           int32\n\tTv                timeval\n\tAddr_v6           [4]int32\n\tX__glibc_reserved [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int64\n\tUsec int64\n}\n"
  },
  {
    "path": "host/host_linux_ppc64le.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux && ppc64le\n\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType              int16\n\tPad_cgo_0         [2]byte\n\tPid               int32\n\tLine              [32]int8\n\tId                [4]int8\n\tUser              [32]int8\n\tHost              [256]int8\n\tExit              exit_status\n\tSession           int32\n\tTv                timeval\n\tAddr_v6           [4]int32\n\tX__glibc_reserved [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int64\n\tUsec int64\n}\n"
  },
  {
    "path": "host/host_linux_riscv64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType              int16\n\tPid               int32\n\tLine              [32]int8\n\tId                [4]int8\n\tUser              [32]int8\n\tHost              [256]int8\n\tExit              exit_status\n\tSession           int32\n\tTv                _Ctype_struct___0\n\tAddr_v6           [4]int32\n\tX__glibc_reserved [20]uint8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype _Ctype_struct___0 struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_linux_s390x.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux && s390x\n\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_linux.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x180\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype utmp struct {\n\tType              int16\n\tPad_cgo_0         [2]byte\n\tPid               int32\n\tLine              [32]int8\n\tId                [4]int8\n\tUser              [32]int8\n\tHost              [256]int8\n\tExit              exit_status\n\tSession           int32\n\tTv                timeval\n\tAddr_v6           [4]int32\n\tX__glibc_reserved [20]int8\n}\n\ntype exit_status struct {\n\tTermination int16\n\tExit        int16\n}\n\ntype timeval struct {\n\tSec  int64\n\tUsec int64\n}\n"
  },
  {
    "path": "host/host_linux_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage host\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/common\"\n)\n\nfunc TestGetRedhatishVersion(t *testing.T) {\n\tvar ret string\n\tc := []string{\"Rawhide\"}\n\tret = getRedhatishVersion(c)\n\tassert.Equalf(t, \"rawhide\", ret, \"Could not get version rawhide: %v\", ret)\n\n\tc = []string{\"Fedora release 15 (Lovelock)\"}\n\tret = getRedhatishVersion(c)\n\tassert.Equalf(t, \"15\", ret, \"Could not get version fedora: %v\", ret)\n\n\tc = []string{\"Enterprise Linux Server release 5.5 (Carthage)\"}\n\tret = getRedhatishVersion(c)\n\tassert.Equalf(t, \"5.5\", ret, \"Could not get version redhat enterprise: %v\", ret)\n\n\tc = []string{\"\"}\n\tret = getRedhatishVersion(c)\n\tassert.Emptyf(t, ret, \"Could not get version with no value: %v\", ret)\n}\n\nfunc TestGetRedhatishPlatform(t *testing.T) {\n\tvar ret string\n\tc := []string{\"red hat\"}\n\tret = getRedhatishPlatform(c)\n\tassert.Equalf(t, \"redhat\", ret, \"Could not get platform redhat: %v\", ret)\n\n\tc = []string{\"Fedora release 15 (Lovelock)\"}\n\tret = getRedhatishPlatform(c)\n\tassert.Equalf(t, \"fedora\", ret, \"Could not get platform fedora: %v\", ret)\n\n\tc = []string{\"Enterprise Linux Server release 5.5 (Carthage)\"}\n\tret = getRedhatishPlatform(c)\n\tassert.Equalf(t, \"enterprise\", ret, \"Could not get platform redhat enterprise: %v\", ret)\n\n\tc = []string{\"\"}\n\tret = getRedhatishPlatform(c)\n\tassert.Emptyf(t, ret, \"Could not get platform with no value: %v\", ret)\n}\n\nfunc TestGetlsbStruct(t *testing.T) {\n\tcases := []struct {\n\t\troot        string\n\t\tid          string\n\t\trelease     string\n\t\tcodename    string\n\t\tdescription string\n\t}{\n\t\t{\"arch\", \"Arch\", \"rolling\", \"\", \"Arch Linux\"},\n\t\t{\"ubuntu_22_04\", \"Ubuntu\", \"22.04\", \"jammy\", \"Ubuntu 22.04.2 LTS\"},\n\t}\n\n\tfor _, tt := range cases {\n\t\ttt := tt\n\t\tt.Run(tt.root, func(t *testing.T) {\n\t\t\tctx := context.WithValue(context.Background(),\n\t\t\t\tcommon.EnvKey,\n\t\t\t\tcommon.EnvMap{common.HostEtcEnvKey: \"./testdata/linux/lsbStruct/\" + tt.root},\n\t\t\t)\n\n\t\t\tv, err := getlsbStruct(ctx)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equalf(t, v.ID, tt.id, \"ID: want %v, got %v\", tt.id, v.ID)\n\t\t\tassert.Equalf(t, v.Release, tt.release, \"Release: want %v, got %v\", tt.release, v.Release)\n\t\t\tassert.Equalf(t, v.Codename, tt.codename, \"Codename: want %v, got %v\", tt.codename, v.Codename)\n\t\t\tassert.Equalf(t, v.Description, tt.description, \"Description: want %v, got %v\", tt.description, v.Description)\n\n\t\t\tt.Log(v)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "host/host_netbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build netbsd\n\npackage host\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc HostIDWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc numProcs(_ context.Context) (uint64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc PlatformInformationWithContext(_ context.Context) (string, string, string, error) {\n\tplatform := \"\"\n\tfamily := \"\"\n\tversion := \"\"\n\n\tp, err := unix.Sysctl(\"kern.ostype\")\n\tif err == nil {\n\t\tplatform = strings.ToLower(p)\n\t}\n\tv, err := unix.Sysctl(\"kern.osrelease\")\n\tif err == nil {\n\t\tversion = strings.ToLower(v)\n\t}\n\n\treturn platform, family, version, nil\n}\n\nfunc VirtualizationWithContext(_ context.Context) (string, string, error) {\n\treturn \"\", \"\", common.ErrNotImplementedError\n}\n\nfunc UsersWithContext(_ context.Context) ([]UserStat, error) {\n\tvar ret []UserStat\n\treturn ret, common.ErrNotImplementedError\n}\n\nfunc KernelVersionWithContext(ctx context.Context) (string, error) {\n\t_, _, version, err := PlatformInformationWithContext(ctx)\n\treturn version, err\n}\n"
  },
  {
    "path": "host/host_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage host\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/process\"\n)\n\nconst (\n\tUTNameSize = 32 /* see MAXLOGNAME in <sys/param.h> */\n\tUTLineSize = 8\n\tUTHostSize = 16\n)\n\nfunc HostIDWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc numProcs(ctx context.Context) (uint64, error) {\n\tprocs, err := process.PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(len(procs)), nil\n}\n\nfunc PlatformInformationWithContext(_ context.Context) (string, string, string, error) {\n\tplatform := \"\"\n\tfamily := \"\"\n\tversion := \"\"\n\n\tp, err := unix.Sysctl(\"kern.ostype\")\n\tif err == nil {\n\t\tplatform = strings.ToLower(p)\n\t}\n\tv, err := unix.Sysctl(\"kern.osrelease\")\n\tif err == nil {\n\t\tversion = strings.ToLower(v)\n\t}\n\n\treturn platform, family, version, nil\n}\n\nfunc VirtualizationWithContext(_ context.Context) (string, string, error) {\n\treturn \"\", \"\", common.ErrNotImplementedError\n}\n\nfunc UsersWithContext(_ context.Context) ([]UserStat, error) {\n\tvar ret []UserStat\n\tutmpfile := \"/var/run/utmp\"\n\tfile, err := os.Open(utmpfile)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tdefer file.Close()\n\n\tbuf, err := io.ReadAll(file)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tentrySize := int(unsafe.Sizeof(Utmp{}))\n\tcount := len(buf) / entrySize\n\n\tfor i := 0; i < count; i++ {\n\t\tb := buf[i*entrySize : i*entrySize+entrySize]\n\t\tvar u Utmp\n\t\tbr := bytes.NewReader(b)\n\t\terr := binary.Read(br, binary.LittleEndian, &u)\n\t\tif err != nil || u.Time == 0 || u.Name[0] == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tuser := UserStat{\n\t\t\tUser:     common.IntToString(u.Name[:]),\n\t\t\tTerminal: common.IntToString(u.Line[:]),\n\t\t\tHost:     common.IntToString(u.Host[:]),\n\t\t\tStarted:  int(u.Time),\n\t\t}\n\n\t\tret = append(ret, user)\n\t}\n\n\treturn ret, nil\n}\n\nfunc KernelVersionWithContext(ctx context.Context) (string, error) {\n\t_, _, version, err := PlatformInformationWithContext(ctx)\n\treturn version, err\n}\n"
  },
  {
    "path": "host/host_openbsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && 386\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs host/types_openbsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x130\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype Utmp struct {\n\tLine [8]int8\n\tName [32]int8\n\tHost [256]int8\n\tTime int64\n}\ntype Timeval struct {\n\tSec  int64\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_openbsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_openbsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x130\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Utmp struct {\n\tLine [8]int8\n\tName [32]int8\n\tHost [256]int8\n\tTime int64\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n"
  },
  {
    "path": "host/host_openbsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && arm\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs host/types_openbsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x130\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype Utmp struct {\n\tLine [8]int8\n\tName [32]int8\n\tHost [256]int8\n\tTime int64\n}\ntype Timeval struct {\n\tSec  int64\n\tUsec int32\n}\n"
  },
  {
    "path": "host/host_openbsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs host/types_openbsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x130\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Utmp struct {\n\tLine [8]int8\n\tName [32]int8\n\tHost [256]int8\n\tTime int64\n}\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n"
  },
  {
    "path": "host/host_openbsd_riscv64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && riscv64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs host/types_openbsd.go\n\npackage host\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n\tsizeOfUtmp     = 0x130\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype (\n\tUtmp struct {\n\t\tLine [8]int8\n\t\tName [32]int8\n\t\tHost [256]int8\n\t\tTime int64\n\t}\n\tTimeval struct {\n\t\tSec  int64\n\t\tUsec int64\n\t}\n)\n"
  },
  {
    "path": "host/host_posix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux || freebsd || openbsd || netbsd || darwin || solaris\n\npackage host\n\nimport \"golang.org/x/sys/unix\"\n\nfunc KernelArch() (string, error) {\n\tvar utsname unix.Utsname\n\terr := unix.Uname(&utsname)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn unix.ByteSliceToString(utsname.Machine[:]), nil\n}\n"
  },
  {
    "path": "host/host_solaris.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build solaris\n\npackage host\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc HostIDWithContext(ctx context.Context) (string, error) {\n\tplatform, err := parseReleaseFile()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif platform == \"SmartOS\" {\n\t\t// If everything works, use the current zone ID as the HostID if present.\n\t\tout, err := invoke.CommandWithContext(ctx, \"zonename\")\n\t\tif err == nil {\n\t\t\tsc := bufio.NewScanner(bytes.NewReader(out))\n\t\t\tfor sc.Scan() {\n\t\t\t\tline := sc.Text()\n\n\t\t\t\t// If we're in the global zone, rely on the hostname.\n\t\t\t\tif line != \"global\" {\n\t\t\t\t\treturn strings.TrimSpace(line), nil\n\t\t\t\t}\n\t\t\t\thostname, err := os.Hostname()\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn hostname, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// If HostID is still unknown, use hostid(1), which can lie to callers but at\n\t// this point there are no hardware facilities available.  This behavior\n\t// matches that of other supported OSes.\n\tout, err := invoke.CommandWithContext(ctx, \"hostid\")\n\tif err == nil {\n\t\tsc := bufio.NewScanner(bytes.NewReader(out))\n\t\tfor sc.Scan() {\n\t\t\tline := sc.Text()\n\t\t\treturn strings.TrimSpace(line), nil\n\t\t}\n\t}\n\n\treturn \"\", nil\n}\n\n// Count number of processes based on the number of entries in /proc\nfunc numProcs(_ context.Context) (uint64, error) {\n\tdirs, err := os.ReadDir(\"/proc\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(len(dirs)), nil\n}\n\nvar kstatMatch = regexp.MustCompile(`(\\S+)\\s+(\\S*)`)\n\nfunc BootTimeWithContext(ctx context.Context) (uint64, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"kstat\", \"-p\", \"unix:0:system_misc:boot_time\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tkstats := kstatMatch.FindAllStringSubmatch(string(out), -1)\n\tif len(kstats) != 1 {\n\t\treturn 0, fmt.Errorf(\"expected 1 kstat, found %d\", len(kstats))\n\t}\n\n\treturn strconv.ParseUint(kstats[0][2], 10, 64)\n}\n\nfunc UptimeWithContext(ctx context.Context) (uint64, error) {\n\tbootTime, err := BootTimeWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn common.TimeSince(bootTime), nil\n}\n\nfunc UsersWithContext(_ context.Context) ([]UserStat, error) {\n\treturn []UserStat{}, common.ErrNotImplementedError\n}\n\nfunc VirtualizationWithContext(_ context.Context) (string, string, error) {\n\treturn \"\", \"\", common.ErrNotImplementedError\n}\n\n// Find distribution name from /etc/release\nfunc parseReleaseFile() (string, error) {\n\tb, err := os.ReadFile(\"/etc/release\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\ts := string(b)\n\ts = strings.TrimSpace(s)\n\n\tvar platform string\n\n\tswitch {\n\tcase strings.HasPrefix(s, \"SmartOS\"):\n\t\tplatform = \"SmartOS\"\n\tcase strings.HasPrefix(s, \"OpenIndiana\"):\n\t\tplatform = \"OpenIndiana\"\n\tcase strings.HasPrefix(s, \"OmniOS\"):\n\t\tplatform = \"OmniOS\"\n\tcase strings.HasPrefix(s, \"Open Storage\"):\n\t\tplatform = \"NexentaStor\"\n\tcase strings.HasPrefix(s, \"Solaris\"):\n\t\tplatform = \"Solaris\"\n\tcase strings.HasPrefix(s, \"Oracle Solaris\"):\n\t\tplatform = \"Solaris\"\n\tdefault:\n\t\tplatform = strings.Fields(s)[0]\n\t}\n\n\treturn platform, nil\n}\n\n// parseUnameOutput returns platformFamily, kernelVersion and platformVersion\nfunc parseUnameOutput(ctx context.Context) (string, string, string, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"uname\", \"-srv\")\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", err\n\t}\n\n\tfields := strings.Fields(string(out))\n\tif len(fields) < 3 {\n\t\treturn \"\", \"\", \"\", errors.New(\"malformed `uname` output\")\n\t}\n\n\treturn fields[0], fields[1], fields[2], nil\n}\n\nfunc KernelVersionWithContext(ctx context.Context) (string, error) {\n\t_, kernelVersion, _, err := parseUnameOutput(ctx)\n\treturn kernelVersion, err\n}\n\nfunc PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {\n\tplatform, err := parseReleaseFile()\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", err\n\t}\n\n\tplatformFamily, _, platformVersion, err := parseUnameOutput(ctx)\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", err\n\t}\n\n\treturn platform, platformFamily, platformVersion, nil\n}\n"
  },
  {
    "path": "host/host_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage host\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestHostID(t *testing.T) {\n\tv, err := HostID()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, v, \"Could not get host id %v\", v)\n\tt.Log(v)\n}\n\nfunc TestInfo(t *testing.T) {\n\tv, err := Info()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tempty := &InfoStat{}\n\tassert.NotSamef(t, v, empty, \"Could not get hostinfo %v\", v)\n\tassert.NotZerof(t, v.Procs, \"Could not determine the number of host processes\")\n\tt.Log(v)\n}\n\nfunc TestUptime(t *testing.T) {\n\tif os.Getenv(\"CI\") == \"true\" {\n\t\tt.Skip(\"Skip CI\")\n\t}\n\n\tv, err := Uptime()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotZerof(t, v, \"Could not get up time %v\", v)\n}\n\nfunc TestBootTime(t *testing.T) {\n\tif os.Getenv(\"CI\") == \"true\" {\n\t\tt.Skip(\"Skip CI\")\n\t}\n\tv, err := BootTime()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotZerof(t, v, \"Could not get boot time %v\", v)\n\tassert.GreaterOrEqualf(t, v, uint64(946652400), \"Invalid Boottime, older than 2000-01-01\")\n\tt.Logf(\"first boot time: %d\", v)\n\n\tv2, err := BootTime()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.Equalf(t, v, v2, \"cached boot time is different\")\n\tt.Logf(\"second boot time: %d\", v2)\n}\n\nfunc TestUsers(t *testing.T) {\n\tv, err := Users()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tempty := UserStat{}\n\tif len(v) == 0 {\n\t\tt.Skip(\"Users is empty\")\n\t}\n\tfor _, u := range v {\n\t\tassert.NotEqualf(t, u, empty, \"Could not Users %v\", v)\n\t\tt.Log(u)\n\t}\n}\n\nfunc TestInfoStat_String(t *testing.T) {\n\tv := InfoStat{\n\t\tHostname:   \"test\",\n\t\tUptime:     3000,\n\t\tProcs:      100,\n\t\tOS:         \"linux\",\n\t\tPlatform:   \"ubuntu\",\n\t\tBootTime:   1447040000,\n\t\tHostID:     \"edfd25ff-3c9c-b1a4-e660-bd826495ad35\",\n\t\tKernelArch: \"x86_64\",\n\t}\n\te := `{\"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\"}`\n\tassert.JSONEqf(t, e, v.String(), \"HostInfoStat string is invalid:\\ngot  %v\\nwant %v\", v, e)\n}\n\nfunc TestUserStat_String(t *testing.T) {\n\tv := UserStat{\n\t\tUser:     \"user\",\n\t\tTerminal: \"term\",\n\t\tHost:     \"host\",\n\t\tStarted:  100,\n\t}\n\te := `{\"user\":\"user\",\"terminal\":\"term\",\"host\":\"host\",\"started\":100}`\n\tassert.JSONEqf(t, e, v.String(), \"UserStat string is invalid: %v\", v)\n}\n\nfunc TestGuid(t *testing.T) {\n\tid, err := HostID()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, id, \"Host id is empty\")\n\tt.Logf(\"Host id value: %v\", id)\n}\n\nfunc TestVirtualization(t *testing.T) {\n\twg := sync.WaitGroup{}\n\ttestCount := 10\n\twg.Add(testCount)\n\tfor i := 0; i < testCount; i++ {\n\t\tgo func(j int) {\n\t\t\tsystem, role, err := Virtualization()\n\t\t\tdefer wg.Done()\n\t\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\t\tt.Skip(\"not implemented\")\n\t\t\t}\n\t\t\tassert.NoErrorf(t, err, \"Virtualization() failed, %v\", err)\n\n\t\t\tif j == 9 {\n\t\t\t\tt.Logf(\"Virtualization(): %s, %s\", system, role)\n\t\t\t}\n\t\t}(i)\n\t}\n\twg.Wait()\n}\n\nfunc TestKernelVersion(t *testing.T) {\n\tversion, err := KernelVersion()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"KernelVersion() failed, %v\", err)\n\tassert.NotEmptyf(t, version, \"KernelVersion() returns empty: %s\", version)\n\n\tt.Logf(\"KernelVersion(): %s\", version)\n}\n\nfunc TestPlatformInformation(t *testing.T) {\n\tplatform, family, version, err := PlatformInformation()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"PlatformInformation() failed, %v\", err)\n\tassert.NotEmptyf(t, platform, \"PlatformInformation() returns empty: %v\", platform)\n\n\tt.Logf(\"PlatformInformation(): %v, %v, %v\", platform, family, version)\n}\n\nfunc BenchmarkBootTimeWithCache(b *testing.B) {\n\tEnableBootTimeCache(true)\n\tfor i := 0; i < b.N; i++ {\n\t\tBootTime()\n\t}\n}\n\nfunc BenchmarkBootTimeWithoutCache(b *testing.B) {\n\tEnableBootTimeCache(false)\n\tfor i := 0; i < b.N; i++ {\n\t\tBootTime()\n\t}\n}\n"
  },
  {
    "path": "host/host_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage host\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/process\"\n)\n\nvar (\n\tprocGetSystemTimeAsFileTime = common.Modkernel32.NewProc(\"GetSystemTimeAsFileTime\")\n\tprocGetTickCount32          = common.Modkernel32.NewProc(\"GetTickCount\")\n\tprocGetTickCount64          = common.Modkernel32.NewProc(\"GetTickCount64\")\n\tprocGetNativeSystemInfo     = common.Modkernel32.NewProc(\"GetNativeSystemInfo\")\n\tprocRtlGetVersion           = common.ModNt.NewProc(\"RtlGetVersion\")\n)\n\n// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ns-wdm-_osversioninfoexw\ntype osVersionInfoExW struct {\n\tdwOSVersionInfoSize uint32\n\tdwMajorVersion      uint32\n\tdwMinorVersion      uint32\n\tdwBuildNumber       uint32\n\tdwPlatformId        uint32\n\tszCSDVersion        [128]uint16\n\twServicePackMajor   uint16\n\twServicePackMinor   uint16\n\twSuiteMask          uint16\n\twProductType        uint8\n\twReserved           uint8\n}\n\ntype systemInfo struct {\n\twProcessorArchitecture      uint16\n\twReserved                   uint16\n\tdwPageSize                  uint32\n\tlpMinimumApplicationAddress uintptr\n\tlpMaximumApplicationAddress uintptr\n\tdwActiveProcessorMask       uintptr\n\tdwNumberOfProcessors        uint32\n\tdwProcessorType             uint32\n\tdwAllocationGranularity     uint32\n\twProcessorLevel             uint16\n\twProcessorRevision          uint16\n}\n\nfunc HostIDWithContext(_ context.Context) (string, error) {\n\t// 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\n\t// for rationale of using windows.RegOpenKeyEx/RegQueryValueEx instead of registry.OpenKey/GetStringValue\n\tvar h windows.Handle\n\terr := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\\Microsoft\\Cryptography`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer windows.RegCloseKey(h)\n\n\tconst windowsRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16\n\tconst uuidLen = 36\n\n\tvar regBuf [windowsRegBufLen]uint16\n\tbufLen := uint32(windowsRegBufLen)\n\tvar valType uint32\n\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\thostID := windows.UTF16ToString(regBuf[:])\n\thostIDLen := len(hostID)\n\tif hostIDLen != uuidLen {\n\t\treturn \"\", fmt.Errorf(\"HostID incorrect: %q\", hostID)\n\t}\n\n\treturn strings.ToLower(hostID), nil\n}\n\nfunc numProcs(ctx context.Context) (uint64, error) {\n\tprocs, err := process.PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(len(procs)), nil\n}\n\nfunc UptimeWithContext(_ context.Context) (uint64, error) {\n\tup, err := uptimeMillis()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64((time.Duration(up) * time.Millisecond).Seconds()), nil\n}\n\nfunc uptimeMillis() (uint64, error) {\n\tprocGetTickCount := procGetTickCount64\n\terr := procGetTickCount64.Find()\n\tif err != nil {\n\t\tprocGetTickCount = 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\n\t}\n\tr1, _, lastErr := syscall.Syscall(procGetTickCount.Addr(), 0, 0, 0, 0)\n\tif lastErr != 0 {\n\t\treturn 0, lastErr\n\t}\n\treturn uint64(r1), nil\n}\n\n// cachedBootTime must be accessed via atomic.Load/StoreUint64\nvar cachedBootTime uint64\n\nfunc BootTimeWithContext(_ context.Context) (uint64, error) {\n\tif enableBootTimeCache {\n\t\tt := atomic.LoadUint64(&cachedBootTime)\n\t\tif t != 0 {\n\t\t\treturn t, nil\n\t\t}\n\t}\n\tup, err := uptimeMillis()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tt := uint64((time.Duration(common.TimeSinceMillis(up)) * time.Millisecond).Seconds())\n\tif enableBootTimeCache {\n\t\tatomic.StoreUint64(&cachedBootTime, t)\n\t}\n\treturn t, nil\n}\n\nfunc PlatformInformationWithContext(_ context.Context) (platform, family, version string, err error) {\n\tplatform, family, _, displayVersion, err := platformInformation()\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", err\n\t}\n\treturn platform, family, displayVersion, nil\n}\n\nfunc platformInformation() (platform, family, version, displayVersion string, err error) {\n\t// GetVersionEx lies on Windows 8.1 and returns as Windows 8 if we don't declare compatibility in manifest\n\t// RtlGetVersion bypasses this lying layer and returns the true Windows version\n\t// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-rtlgetversion\n\t// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ns-wdm-_osversioninfoexw\n\tvar osInfo osVersionInfoExW\n\tosInfo.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osInfo))\n\tret, _, err := procRtlGetVersion.Call(uintptr(unsafe.Pointer(&osInfo)))\n\tif ret != 0 {\n\t\treturn platform, family, version, displayVersion, err\n\t}\n\n\t// Platform\n\tvar h windows.Handle // like HostIDWithContext(), we query the registry using the raw windows.RegOpenKeyEx/RegQueryValueEx\n\terr = windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h)\n\tif err != nil {\n\t\treturn platform, family, version, displayVersion, err\n\t}\n\tdefer windows.RegCloseKey(h)\n\tvar bufLen uint32\n\tvar valType uint32\n\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`ProductName`), nil, &valType, nil, &bufLen)\n\tif err != nil {\n\t\treturn platform, family, version, displayVersion, err\n\t}\n\tregBuf := make([]uint16, bufLen/2+1)\n\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`ProductName`), nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)\n\tif err != nil {\n\t\treturn platform, family, version, displayVersion, err\n\t}\n\tplatform = windows.UTF16ToString(regBuf)\n\tif strings.Contains(platform, \"Windows 10\") { // check build number to determine whether it's actually Windows 11\n\t\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CurrentBuildNumber`), nil, &valType, nil, &bufLen)\n\t\tif err == nil {\n\t\t\tregBuf = make([]uint16, bufLen/2+1)\n\t\t\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CurrentBuildNumber`), nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)\n\t\t\tif err == nil {\n\t\t\t\tbuildNumberStr := windows.UTF16ToString(regBuf)\n\t\t\t\tif buildNumber, err := strconv.ParseInt(buildNumberStr, 10, 32); err == nil && buildNumber >= 22000 {\n\t\t\t\t\tplatform = strings.Replace(platform, \"Windows 10\", \"Windows 11\", 1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif !strings.HasPrefix(platform, \"Microsoft\") {\n\t\tplatform = \"Microsoft \" + platform\n\t}\n\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CSDVersion`), nil, &valType, nil, &bufLen) // append Service Pack number, only on success\n\tif err == nil {                                                                                       // don't return an error if only the Service Pack retrieval fails\n\t\tregBuf = make([]uint16, bufLen/2+1)\n\t\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CSDVersion`), nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)\n\t\tif err == nil {\n\t\t\tplatform += \" \" + windows.UTF16ToString(regBuf)\n\t\t}\n\t}\n\n\tvar UBR uint32 // Update Build Revision\n\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`UBR`), nil, &valType, nil, &bufLen)\n\tif err == nil {\n\t\tregBuf := make([]byte, 4)\n\t\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`UBR`), nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)\n\t\tcopy((*[4]byte)(unsafe.Pointer(&UBR))[:], regBuf)\n\t}\n\n\t// Get DisplayVersion(ex: 23H2) as platformVersion\n\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`DisplayVersion`), nil, &valType, nil, &bufLen)\n\tif err == nil {\n\t\tregBuf := make([]uint16, bufLen/2+1)\n\t\terr = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`DisplayVersion`), nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)\n\t\tdisplayVersion = windows.UTF16ToString(regBuf)\n\t}\n\n\t// PlatformFamily\n\tswitch osInfo.wProductType {\n\tcase 1:\n\t\tfamily = \"Standalone Workstation\"\n\tcase 2:\n\t\tfamily = \"Server (Domain Controller)\"\n\tcase 3:\n\t\tfamily = \"Server\"\n\t}\n\n\t// Platform Version\n\tversion = fmt.Sprintf(\"%d.%d.%d.%d Build %d.%d\",\n\t\tosInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.dwBuildNumber, UBR,\n\t\tosInfo.dwBuildNumber, UBR)\n\n\treturn platform, family, version, displayVersion, nil\n}\n\nfunc UsersWithContext(_ context.Context) ([]UserStat, error) {\n\tvar ret []UserStat\n\n\treturn ret, common.ErrNotImplementedError\n}\n\nfunc VirtualizationWithContext(_ context.Context) (string, string, error) {\n\treturn \"\", \"\", common.ErrNotImplementedError\n}\n\nfunc KernelVersionWithContext(_ context.Context) (string, error) {\n\t_, _, version, _, err := platformInformation()\n\treturn version, err\n}\n\nfunc KernelArch() (string, error) {\n\tvar sInfo systemInfo\n\tprocGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sInfo)))\n\n\tconst (\n\t\tPROCESSOR_ARCHITECTURE_INTEL = 0\n\t\tPROCESSOR_ARCHITECTURE_ARM   = 5\n\t\tPROCESSOR_ARCHITECTURE_ARM64 = 12\n\t\tPROCESSOR_ARCHITECTURE_IA64  = 6\n\t\tPROCESSOR_ARCHITECTURE_AMD64 = 9\n\t)\n\tswitch sInfo.wProcessorArchitecture {\n\tcase PROCESSOR_ARCHITECTURE_INTEL:\n\t\tif sInfo.wProcessorLevel < 3 {\n\t\t\treturn \"i386\", nil\n\t\t}\n\t\tif sInfo.wProcessorLevel > 6 {\n\t\t\treturn \"i686\", nil\n\t\t}\n\t\treturn fmt.Sprintf(\"i%d86\", sInfo.wProcessorLevel), nil\n\tcase PROCESSOR_ARCHITECTURE_ARM:\n\t\treturn \"arm\", nil\n\tcase PROCESSOR_ARCHITECTURE_ARM64:\n\t\treturn \"aarch64\", nil\n\tcase PROCESSOR_ARCHITECTURE_IA64:\n\t\treturn \"ia64\", nil\n\tcase PROCESSOR_ARCHITECTURE_AMD64:\n\t\treturn \"x86_64\", nil\n\t}\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "host/testdata/linux/lsbStruct/arch/lsb-release",
    "content": "DISTRIB_ID=\"Arch\"\nDISTRIB_RELEASE=\"rolling\"\nDISTRIB_DESCRIPTION=\"Arch Linux\"\n"
  },
  {
    "path": "host/testdata/linux/lsbStruct/ubuntu_22_04/lsb-release",
    "content": "DISTRIB_ID=Ubuntu\nDISTRIB_RELEASE=22.04\nDISTRIB_CODENAME=jammy\nDISTRIB_DESCRIPTION=\"Ubuntu 22.04.2 LTS\""
  },
  {
    "path": "host/types_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n// plus hand editing about timeval\n\n/*\nInput to cgo -godefs.\n*/\n\npackage host\n\n/*\n#include <utmpx.h>\n#include <sys/_types/_timeval32.h>\n\n// https://github.com/apple-oss-distributions/Libc/blob/55b54c0a0c37b3b24393b42b90a4c561d6c606b1/gen/utmpx-darwin.h#L86\nstruct utmpx32 {\n  char ut_user[_UTX_USERSIZE];\n  char ut_id[_UTX_IDSIZE];\n  char ut_line[_UTX_LINESIZE];\n  pid_t ut_pid;\n  short ut_type;\n  struct timeval32 ut_tv;\n  char ut_host[_UTX_HOSTSIZE];\n  __uint32_t ut_pad[16];\n};\n*/\nimport \"C\"\n\ntype (\n\tutmpx32   C.struct_utmpx32\n\ttimeval32 C.struct_timeval32\n)\n"
  },
  {
    "path": "host/types_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n/*\nInput to cgo -godefs.\n*/\n\npackage host\n\n/*\n#define KERNEL\n#include <sys/types.h>\n#include <sys/time.h>\n#include <utmpx.h>\n#include \"freebsd_headers/utxdb.h\"\n\nenum {\n\tsizeofPtr = sizeof(void*),\n};\n\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tsizeofPtr      = C.sizeofPtr\n\tsizeofShort    = C.sizeof_short\n\tsizeofInt      = C.sizeof_int\n\tsizeofLong     = C.sizeof_long\n\tsizeofLongLong = C.sizeof_longlong\n\tsizeOfUtmpx    = C.sizeof_struct_futx\n)\n\n// Basic types\n\ntype (\n\t_C_short     C.short\n\t_C_int       C.int\n\t_C_long      C.long\n\t_C_long_long C.longlong\n)\n\ntype (\n\tUtmp  C.struct_utmp // for FreeBSD 9.0 compatibility\n\tUtmpx C.struct_futx\n)\n"
  },
  {
    "path": "host/types_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n/*\nInput to cgo -godefs.\n*/\n\npackage host\n\n/*\n#include <sys/types.h>\n#include <utmp.h>\n\nenum {\n       sizeofPtr = sizeof(void*),\n};\n\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tsizeofPtr      = C.sizeofPtr\n\tsizeofShort    = C.sizeof_short\n\tsizeofInt      = C.sizeof_int\n\tsizeofLong     = C.sizeof_long\n\tsizeofLongLong = C.sizeof_longlong\n\tsizeOfUtmp     = C.sizeof_struct_utmp\n)\n\n// Basic types\n\ntype (\n\t_C_short     C.short\n\t_C_int       C.int\n\t_C_long      C.long\n\t_C_long_long C.longlong\n)\n\ntype (\n\tutmp        C.struct_utmp\n\texit_status C.struct_exit_status\n\ttimeval     C.struct_timeval\n)\n"
  },
  {
    "path": "host/types_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n/*\nInput to cgo -godefs.\n*/\n\npackage host\n\n/*\n#define KERNEL\n#include <sys/types.h>\n#include <sys/time.h>\n#include <utmp.h>\n\nenum {\n\tsizeofPtr = sizeof(void*),\n};\n\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tsizeofPtr      = C.sizeofPtr\n\tsizeofShort    = C.sizeof_short\n\tsizeofInt      = C.sizeof_int\n\tsizeofLong     = C.sizeof_long\n\tsizeofLongLong = C.sizeof_longlong\n\tsizeOfUtmp     = C.sizeof_struct_utmp\n)\n\n// Basic types\n\ntype (\n\t_C_short     C.short\n\t_C_int       C.int\n\t_C_long      C.long\n\t_C_long_long C.longlong\n)\n\ntype (\n\tUtmp    C.struct_utmp\n\tTimeval C.struct_timeval\n)\n"
  },
  {
    "path": "internal/common/common.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage common\n\n//\n// gopsutil is a port of psutil(http://pythonhosted.org/psutil/).\n// This covers these architectures.\n//  - linux (amd64, arm)\n//  - freebsd (amd64)\n//  - windows (amd64)\n//  - aix (ppc64)\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/common\"\n)\n\nvar (\n\tTimeout                = 3 * time.Second\n\tErrNotImplementedError = errors.New(\"not implemented yet\")\n\tErrTimeout             = errors.New(\"command timed out\")\n)\n\ntype Invoker interface {\n\tCommand(string, ...string) ([]byte, error)\n\tCommandWithContext(context.Context, string, ...string) ([]byte, error)\n}\n\ntype Invoke struct{}\n\nfunc (i Invoke) Command(name string, arg ...string) ([]byte, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), Timeout)\n\tdefer cancel()\n\treturn i.CommandWithContext(ctx, name, arg...)\n}\n\nfunc (Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {\n\tcmd := exec.CommandContext(ctx, name, arg...)\n\n\tvar buf bytes.Buffer\n\tcmd.Stdout = &buf\n\tcmd.Stderr = &buf\n\n\tif err := cmd.Start(); err != nil {\n\t\treturn buf.Bytes(), err\n\t}\n\n\tif err := cmd.Wait(); err != nil {\n\t\treturn buf.Bytes(), err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\ntype FakeInvoke struct {\n\tSuffix string // Suffix species expected file name suffix such as \"fail\"\n\tError  error  // If Error specified, return the error.\n}\n\n// Command in FakeInvoke returns from expected file if exists.\nfunc (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {\n\tif i.Error != nil {\n\t\treturn []byte{}, i.Error\n\t}\n\n\tarch := runtime.GOOS\n\n\tcommandName := filepath.Base(name)\n\n\tfname := strings.Join(append([]string{commandName}, arg...), \"\")\n\tfname = url.QueryEscape(fname)\n\tfpath := path.Join(\"testdata\", arch, fname)\n\tif i.Suffix != \"\" {\n\t\tfpath += \"_\" + i.Suffix\n\t}\n\tif PathExists(fpath) {\n\t\treturn os.ReadFile(fpath)\n\t}\n\treturn []byte{}, fmt.Errorf(\"could not find testdata: %s\", fpath)\n}\n\nfunc (i FakeInvoke) CommandWithContext(_ context.Context, name string, arg ...string) ([]byte, error) {\n\treturn i.Command(name, arg...)\n}\n\n// ReadFile reads contents from a file\nfunc ReadFile(filename string) (string, error) {\n\tcontent, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn string(content), nil\n}\n\n// ReadLines reads contents from a file and splits them by new lines.\n// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).\nfunc ReadLines(filename string) ([]string, error) {\n\treturn ReadLinesOffsetN(filename, 0, -1)\n}\n\n// ReadLine reads a file and returns the first occurrence of a line that is prefixed with prefix.\nfunc ReadLine(filename, prefix string) (string, error) {\n\tf, err := os.Open(filename)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer f.Close()\n\tr := bufio.NewReader(f)\n\tfor {\n\t\tline, err := r.ReadString('\\n')\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn \"\", err\n\t\t}\n\t\tif strings.HasPrefix(line, prefix) {\n\t\t\treturn line, nil\n\t\t}\n\t}\n\n\treturn \"\", nil\n}\n\n// ReadLinesOffsetN reads contents from file and splits them by new line.\n// The offset tells at which line number to start.\n// The count determines the number of lines to read (starting from offset):\n// n >= 0: at most n lines\n// n < 0: whole file\nfunc ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {\n\tf, err := os.Open(filename)\n\tif err != nil {\n\t\treturn []string{\"\"}, err\n\t}\n\tdefer f.Close()\n\n\tvar ret []string\n\n\tr := bufio.NewReader(f)\n\tfor i := uint(0); i < uint(n)+offset || n < 0; i++ {\n\t\tline, err := r.ReadString('\\n')\n\t\tif err != nil {\n\t\t\tif err == io.EOF && line != \"\" {\n\t\t\t\tret = append(ret, strings.Trim(line, \"\\n\"))\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tif i < offset {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, strings.Trim(line, \"\\n\"))\n\t}\n\n\treturn ret, nil\n}\n\nfunc IntToString(orig []int8) string {\n\tret := make([]byte, len(orig))\n\tsize := -1\n\tfor i, o := range orig {\n\t\tif o == 0 {\n\t\t\tsize = i\n\t\t\tbreak\n\t\t}\n\t\tret[i] = byte(o)\n\t}\n\tif size == -1 {\n\t\tsize = len(orig)\n\t}\n\n\treturn string(ret[0:size])\n}\n\nfunc UintToString(orig []uint8) string {\n\tret := make([]byte, len(orig))\n\tsize := -1\n\tfor i, o := range orig {\n\t\tif o == 0 {\n\t\t\tsize = i\n\t\t\tbreak\n\t\t}\n\t\tret[i] = byte(o)\n\t}\n\tif size == -1 {\n\t\tsize = len(orig)\n\t}\n\n\treturn string(ret[0:size])\n}\n\nfunc ByteToString(orig []byte) string {\n\tn := -1\n\tl := -1\n\tfor i, b := range orig {\n\t\t// skip left side null\n\t\tif l == -1 && b == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif l == -1 {\n\t\t\tl = i\n\t\t}\n\n\t\tif b == 0 {\n\t\t\tbreak\n\t\t}\n\t\tn = i + 1\n\t}\n\tif n == -1 {\n\t\treturn string(orig)\n\t}\n\treturn string(orig[l:n])\n}\n\n// ReadInts reads contents from single line file and returns them as []int32.\nfunc ReadInts(filename string) ([]int64, error) {\n\tf, err := os.Open(filename)\n\tif err != nil {\n\t\treturn []int64{}, err\n\t}\n\tdefer f.Close()\n\n\tvar ret []int64\n\n\tr := bufio.NewReader(f)\n\n\t// The int files that this is concerned with should only be one liners.\n\tline, err := r.ReadString('\\n')\n\tif err != nil {\n\t\treturn []int64{}, err\n\t}\n\n\ti, err := strconv.ParseInt(strings.Trim(line, \"\\n\"), 10, 32)\n\tif err != nil {\n\t\treturn []int64{}, err\n\t}\n\tret = append(ret, i)\n\n\treturn ret, nil\n}\n\n// Parse Hex to uint32 without error\nfunc HexToUint32(hex string) uint32 {\n\tvv, _ := strconv.ParseUint(hex, 16, 32)\n\treturn uint32(vv)\n}\n\n// Parse to int32 without error\nfunc mustParseInt32(val string) int32 {\n\tvv, _ := strconv.ParseInt(val, 10, 32)\n\treturn int32(vv)\n}\n\n// Parse to uint64 without error\nfunc mustParseUint64(val string) uint64 {\n\tvv, _ := strconv.ParseInt(val, 10, 64)\n\treturn uint64(vv)\n}\n\n// Parse to Float64 without error\nfunc mustParseFloat64(val string) float64 {\n\tvv, _ := strconv.ParseFloat(val, 64)\n\treturn vv\n}\n\n// StringsHas checks the target string slice contains src or not\nfunc StringsHas(target []string, src string) bool {\n\tfor _, t := range target {\n\t\tif strings.TrimSpace(t) == src {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// StringsContains checks the src in any string of the target string slice\nfunc StringsContains(target []string, src string) bool {\n\treturn slices.ContainsFunc(target, func(s string) bool {\n\t\treturn strings.Contains(s, src)\n\t})\n}\n\n// IntContains checks the src in any int of the target int slice.\nfunc IntContains(target []int, src int) bool {\n\treturn slices.Contains(target, src)\n}\n\n// get struct attributes.\n// This method is used only for debugging platform dependent code.\nfunc attributes(m any) map[string]reflect.Type {\n\ttyp := reflect.TypeOf(m)\n\tif typ.Kind() == reflect.Ptr {\n\t\ttyp = typ.Elem()\n\t}\n\n\tattrs := make(map[string]reflect.Type)\n\tif typ.Kind() != reflect.Struct {\n\t\treturn nil\n\t}\n\n\tfor i := 0; i < typ.NumField(); i++ {\n\t\tp := typ.Field(i)\n\t\tif !p.Anonymous {\n\t\t\tattrs[p.Name] = p.Type\n\t\t}\n\t}\n\n\treturn attrs\n}\n\nfunc PathExists(filename string) bool {\n\tif _, err := os.Stat(filename); err == nil {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// PathExistsWithContents returns the filename exists and it is not empty\nfunc PathExistsWithContents(filename string) bool {\n\tinfo, err := os.Stat(filename)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn info.Size() > 4 && !info.IsDir() // at least 4 bytes\n}\n\n// GetEnvWithContext retrieves the environment variable key. If it does not exist it returns the default.\n// The context may optionally contain a map superseding os.EnvKey.\nfunc GetEnvWithContext(ctx context.Context, key, dfault string, combineWith ...string) string {\n\tvar value string\n\tif env, ok := ctx.Value(common.EnvKey).(common.EnvMap); ok {\n\t\tvalue = env[common.EnvKeyType(key)]\n\t}\n\tif value == \"\" {\n\t\tvalue = os.Getenv(key)\n\t}\n\tif value == \"\" {\n\t\tvalue = dfault\n\t}\n\n\treturn combine(value, combineWith)\n}\n\n// GetEnv retrieves the environment variable key. If it does not exist it returns the default.\nfunc GetEnv(key, dfault string, combineWith ...string) string {\n\tvalue := os.Getenv(key)\n\tif value == \"\" {\n\t\tvalue = dfault\n\t}\n\n\treturn combine(value, combineWith)\n}\n\nfunc combine(value string, combineWith []string) string {\n\tswitch len(combineWith) {\n\tcase 0:\n\t\treturn value\n\tcase 1:\n\t\treturn filepath.Join(value, combineWith[0])\n\tdefault:\n\t\tall := make([]string, len(combineWith)+1)\n\t\tall[0] = value\n\t\tcopy(all[1:], combineWith)\n\t\treturn filepath.Join(all...)\n\t}\n}\n\nfunc HostProc(combineWith ...string) string {\n\treturn GetEnv(\"HOST_PROC\", \"/proc\", combineWith...)\n}\n\nfunc HostSys(combineWith ...string) string {\n\treturn GetEnv(\"HOST_SYS\", \"/sys\", combineWith...)\n}\n\nfunc HostEtc(combineWith ...string) string {\n\treturn GetEnv(\"HOST_ETC\", \"/etc\", combineWith...)\n}\n\nfunc HostVar(combineWith ...string) string {\n\treturn GetEnv(\"HOST_VAR\", \"/var\", combineWith...)\n}\n\nfunc HostRun(combineWith ...string) string {\n\treturn GetEnv(\"HOST_RUN\", \"/run\", combineWith...)\n}\n\nfunc HostDev(combineWith ...string) string {\n\treturn GetEnv(\"HOST_DEV\", \"/dev\", combineWith...)\n}\n\nfunc HostRoot(combineWith ...string) string {\n\treturn GetEnv(\"HOST_ROOT\", \"/\", combineWith...)\n}\n\nfunc HostProcWithContext(ctx context.Context, combineWith ...string) string {\n\treturn GetEnvWithContext(ctx, \"HOST_PROC\", \"/proc\", combineWith...)\n}\n\nfunc HostProcMountInfoWithContext(ctx context.Context, combineWith ...string) string {\n\treturn GetEnvWithContext(ctx, \"HOST_PROC_MOUNTINFO\", \"\", combineWith...)\n}\n\nfunc HostSysWithContext(ctx context.Context, combineWith ...string) string {\n\treturn GetEnvWithContext(ctx, \"HOST_SYS\", \"/sys\", combineWith...)\n}\n\nfunc HostEtcWithContext(ctx context.Context, combineWith ...string) string {\n\treturn GetEnvWithContext(ctx, \"HOST_ETC\", \"/etc\", combineWith...)\n}\n\nfunc HostVarWithContext(ctx context.Context, combineWith ...string) string {\n\treturn GetEnvWithContext(ctx, \"HOST_VAR\", \"/var\", combineWith...)\n}\n\nfunc HostRunWithContext(ctx context.Context, combineWith ...string) string {\n\treturn GetEnvWithContext(ctx, \"HOST_RUN\", \"/run\", combineWith...)\n}\n\nfunc HostDevWithContext(ctx context.Context, combineWith ...string) string {\n\treturn GetEnvWithContext(ctx, \"HOST_DEV\", \"/dev\", combineWith...)\n}\n\nfunc HostRootWithContext(ctx context.Context, combineWith ...string) string {\n\treturn GetEnvWithContext(ctx, \"HOST_ROOT\", \"/\", combineWith...)\n}\n\n// getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running\n// sysctl commands.\nfunc getSysctrlEnv(env []string) []string {\n\tfoundLC := false\n\tfor i, line := range env {\n\t\tif strings.HasPrefix(line, \"LC_ALL\") {\n\t\t\tenv[i] = \"LC_ALL=C\"\n\t\t\tfoundLC = true\n\t\t}\n\t}\n\tif !foundLC {\n\t\tenv = append(env, \"LC_ALL=C\")\n\t}\n\treturn env\n}\n\n// Round places rounds the number 'val' to 'n' decimal places\nfunc Round(val float64, n int) float64 {\n\t// Calculate the power of 10 to the n\n\tpow10 := math.Pow(10, float64(n))\n\t// Multiply the value by pow10, round it, then divide it by pow10\n\treturn math.Round(val*pow10) / pow10\n}\n\nfunc TimeSince(ts uint64) uint64 {\n\treturn uint64(time.Now().Unix()) - ts\n}\n\nfunc TimeSinceMillis(ts uint64) uint64 {\n\treturn uint64(time.Now().UnixMilli()) - ts\n}\n"
  },
  {
    "path": "internal/common/common_aix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc BootTimeWithContext(ctx context.Context, invoke Invoker) (btime uint64, err error) {\n\tut, err := UptimeWithContext(ctx, invoke)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tif ut <= 0 {\n\t\treturn 0, errors.New(\"uptime was not set, so cannot calculate boot time from it\")\n\t}\n\n\treturn TimeSince(ut), nil\n}\n\n// Uses ps to get the elapsed time for PID 1 in DAYS-HOURS:MINUTES:SECONDS format.\n// Examples of ps -o etimes -p 1 output:\n// 124-01:40:39 (with days)\n// 15:03:02 (without days, hours only)\n// 01:02 (just-rebooted systems, minutes and seconds)\nfunc UptimeWithContext(ctx context.Context, invoke Invoker) (uint64, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", \"-o\", \"etimes\", \"-p\", \"1\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tlines := strings.Split(strings.TrimSpace(string(out)), \"\\n\")\n\tif len(lines) < 2 {\n\t\treturn 0, errors.New(\"ps output has fewer than 2 rows\")\n\t}\n\n\t// Extract the etimes value from the second row, trimming whitespace\n\tetimes := strings.TrimSpace(lines[1])\n\treturn ParseUptime(etimes), nil\n}\n\n// Parses etimes output from ps command into total seconds.\n// Handles formats like:\n// - \"124-01:40:39\" (DAYS-HOURS:MINUTES:SECONDS)\n// - \"15:03:02\" (HOURS:MINUTES:SECONDS)\n// - \"01:02\" (MINUTES:SECONDS, from just-rebooted systems)\nfunc ParseUptime(etimes string) uint64 {\n\tvar days, hours, mins, secs uint64\n\n\t// Check if days component is present (contains a dash)\n\tif strings.Contains(etimes, \"-\") {\n\t\tparts := strings.Split(etimes, \"-\")\n\t\tif len(parts) != 2 {\n\t\t\treturn 0\n\t\t}\n\n\t\tvar err error\n\t\tdays, err = strconv.ParseUint(parts[0], 10, 64)\n\t\tif err != nil {\n\t\t\treturn 0\n\t\t}\n\n\t\t// Parse the HH:MM:SS portion (after days, must have 3 parts)\n\t\tetimes = parts[1]\n\t\ttimeParts := strings.Split(etimes, \":\")\n\t\tif len(timeParts) != 3 {\n\t\t\treturn 0\n\t\t}\n\n\t\tvar err2 error\n\t\thours, err2 = strconv.ParseUint(timeParts[0], 10, 64)\n\t\tif err2 != nil {\n\t\t\treturn 0\n\t\t}\n\n\t\tmins, err2 = strconv.ParseUint(timeParts[1], 10, 64)\n\t\tif err2 != nil {\n\t\t\treturn 0\n\t\t}\n\n\t\tsecs, err2 = strconv.ParseUint(timeParts[2], 10, 64)\n\t\tif err2 != nil {\n\t\t\treturn 0\n\t\t}\n\t} else {\n\t\t// Parse time portions (either HH:MM:SS or MM:SS) when no days present\n\t\ttimeParts := strings.Split(etimes, \":\")\n\t\tswitch len(timeParts) {\n\t\tcase 3:\n\t\t\t// HH:MM:SS format\n\t\t\tvar err error\n\t\t\thours, err = strconv.ParseUint(timeParts[0], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tmins, err = strconv.ParseUint(timeParts[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tsecs, err = strconv.ParseUint(timeParts[2], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0\n\t\t\t}\n\t\tcase 2:\n\t\t\t// MM:SS format (just-rebooted systems)\n\t\t\tvar err error\n\t\t\tmins, err = strconv.ParseUint(timeParts[0], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tsecs, err = strconv.ParseUint(timeParts[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn 0\n\t\t\t}\n\t\tdefault:\n\t\t\treturn 0\n\t\t}\n\t}\n\n\t// Convert to total seconds\n\ttotalSeconds := (days * 24 * 60 * 60) + (hours * 60 * 60) + (mins * 60) + secs\n\treturn totalSeconds\n}\n"
  },
  {
    "path": "internal/common/common_aix_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage common\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestParseUptimeValidInput(t *testing.T) {\n\ttestCases := []struct {\n\t\tinput    string\n\t\texpected uint64\n\t}{\n\t\t// Format: MINUTES:SECONDS (just-rebooted systems, hours dropped when 0)\n\t\t{\"00:13\", 13}, // 13 seconds\n\t\t{\"01:00\", 60}, // 1 minute\n\t\t{\"01:02\", 62}, // 1 minute, 2 seconds\n\t\t// Format: HOURS:MINUTES:SECONDS (no days, hours > 0)\n\t\t{\"01:00:00\", 3600},  // 1 hour\n\t\t{\"05:00:00\", 18000}, // 5 hours\n\t\t{\"15:03:02\", 54182}, // 15 hours, 3 minutes, 2 seconds\n\t\t// Format: DAYS-HOURS:MINUTES:SECONDS (with days)\n\t\t{\"2-20:00:00\", 244800},     // 2 days, 20 hours\n\t\t{\"4-00:29:00\", 347340},     // 4 days, 29 minutes\n\t\t{\"83-18:29:00\", 7237740},   // 83 days, 18 hours, 29 minutes\n\t\t{\"124-01:40:39\", 10719639}, // 124 days, 1 hour, 40 minutes, 39 seconds\n\t}\n\tfor _, tc := range testCases {\n\t\tgot := ParseUptime(tc.input)\n\t\tassert.Equalf(t, tc.expected, got, \"ParseUptime(%q) = %v, want %v\", tc.input, got, tc.expected)\n\t}\n}\n\nfunc TestParseUptimeInvalidInput(t *testing.T) {\n\ttestCases := []string{\n\t\t\"\",             // blank\n\t\t\"invalid\",      // invalid string\n\t\t\"1-2:3\",        // incomplete time format after dash\n\t\t\"abc-01:02:03\", // non-numeric days\n\t\t\"1-ab:02:03\",   // non-numeric hours\n\t}\n\n\tfor _, tc := range testCases {\n\t\tgot := ParseUptime(tc)\n\t\tassert.Equalf(t, uint64(0), got, \"ParseUptime(%q) expected zero to be returned, received %v\", tc, got)\n\t}\n}\n"
  },
  {
    "path": "internal/common/common_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage common\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"unsafe\"\n\n\t\"github.com/ebitengine/purego\"\n)\n\n// Library represents a dynamic library loaded by purego.\ntype library struct {\n\thandle uintptr\n\tfnMap  map[string]any\n}\n\n// library paths\nconst (\n\tIOKitLibPath          = \"/System/Library/Frameworks/IOKit.framework/IOKit\"\n\tCoreFoundationLibPath = \"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation\"\n\tSystemLibPath         = \"/usr/lib/libSystem.B.dylib\"\n)\n\nfunc newLibrary(path string) (*library, error) {\n\tlib, err := purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &library{\n\t\thandle: lib,\n\t\tfnMap:  make(map[string]any),\n\t}, nil\n}\n\nfunc (lib *library) Dlsym(symbol string) (uintptr, error) {\n\treturn purego.Dlsym(lib.handle, symbol)\n}\n\nfunc getFunc[T any](lib *library, symbol string) T {\n\tvar dlfun *dlFunc[T]\n\tif f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok {\n\t\tdlfun = f\n\t} else {\n\t\tdlfun = newDlfunc[T](symbol)\n\t\tdlfun.init(lib.handle)\n\t\tlib.fnMap[symbol] = dlfun\n\t}\n\treturn dlfun.fn\n}\n\nfunc (lib *library) Close() {\n\tpurego.Dlclose(lib.handle)\n}\n\ntype dlFunc[T any] struct {\n\tsym string\n\tfn  T\n}\n\nfunc (d *dlFunc[T]) init(handle uintptr) {\n\tpurego.RegisterLibFunc(&d.fn, handle, d.sym)\n}\n\nfunc newDlfunc[T any](sym string) *dlFunc[T] {\n\treturn &dlFunc[T]{sym: sym}\n}\n\ntype CoreFoundationLib struct {\n\t*library\n}\n\nfunc NewCoreFoundationLib() (*CoreFoundationLib, error) {\n\tlibrary, err := newLibrary(CoreFoundationLibPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &CoreFoundationLib{library}, nil\n}\n\nfunc (c *CoreFoundationLib) CFGetTypeID(cf uintptr) int64 {\n\tfn := getFunc[CFGetTypeIDFunc](c.library, \"CFGetTypeID\")\n\treturn fn(cf)\n}\n\nfunc (c *CoreFoundationLib) CFNumberCreate(allocator uintptr, theType int64, valuePtr uintptr) unsafe.Pointer {\n\tfn := getFunc[CFNumberCreateFunc](c.library, \"CFNumberCreate\")\n\treturn fn(allocator, theType, valuePtr)\n}\n\nfunc (c *CoreFoundationLib) CFNumberGetValue(num uintptr, theType int64, valuePtr uintptr) bool {\n\tfn := getFunc[CFNumberGetValueFunc](c.library, \"CFNumberGetValue\")\n\treturn fn(num, theType, valuePtr)\n}\n\nfunc (c *CoreFoundationLib) CFDictionaryCreate(allocator uintptr, keys, values *unsafe.Pointer, numValues int64,\n\tkeyCallBacks, valueCallBacks uintptr,\n) unsafe.Pointer {\n\tfn := getFunc[CFDictionaryCreateFunc](c.library, \"CFDictionaryCreate\")\n\treturn fn(allocator, keys, values, numValues, keyCallBacks, valueCallBacks)\n}\n\nfunc (c *CoreFoundationLib) CFDictionaryAddValue(theDict, key, value uintptr) {\n\tfn := getFunc[CFDictionaryAddValueFunc](c.library, \"CFDictionaryAddValue\")\n\tfn(theDict, key, value)\n}\n\nfunc (c *CoreFoundationLib) CFDictionaryGetValue(theDict, key uintptr) unsafe.Pointer {\n\tfn := getFunc[CFDictionaryGetValueFunc](c.library, \"CFDictionaryGetValue\")\n\treturn fn(theDict, key)\n}\n\nfunc (c *CoreFoundationLib) CFArrayGetCount(theArray uintptr) int64 {\n\tfn := getFunc[CFArrayGetCountFunc](c.library, \"CFArrayGetCount\")\n\treturn fn(theArray)\n}\n\nfunc (c *CoreFoundationLib) CFArrayGetValueAtIndex(theArray uintptr, index int64) unsafe.Pointer {\n\tfn := getFunc[CFArrayGetValueAtIndexFunc](c.library, \"CFArrayGetValueAtIndex\")\n\treturn fn(theArray, index)\n}\n\nfunc (c *CoreFoundationLib) CFStringCreateMutable(alloc uintptr, maxLength int64) unsafe.Pointer {\n\tfn := getFunc[CFStringCreateMutableFunc](c.library, \"CFStringCreateMutable\")\n\treturn fn(alloc, maxLength)\n}\n\nfunc (c *CoreFoundationLib) CFStringGetLength(theString uintptr) int64 {\n\tfn := getFunc[CFStringGetLengthFunc](c.library, \"CFStringGetLength\")\n\treturn fn(theString)\n}\n\nfunc (c *CoreFoundationLib) CFStringGetCString(theString uintptr, buffer CStr, bufferSize int64, encoding uint32) {\n\tfn := getFunc[CFStringGetCStringFunc](c.library, \"CFStringGetCString\")\n\tfn(theString, buffer, bufferSize, encoding)\n}\n\nfunc (c *CoreFoundationLib) CFStringCreateWithCString(alloc uintptr, cStr string, encoding uint32) unsafe.Pointer {\n\tfn := getFunc[CFStringCreateWithCStringFunc](c.library, \"CFStringCreateWithCString\")\n\treturn fn(alloc, cStr, encoding)\n}\n\nfunc (c *CoreFoundationLib) CFDataGetLength(theData uintptr) int64 {\n\tfn := getFunc[CFDataGetLengthFunc](c.library, \"CFDataGetLength\")\n\treturn fn(theData)\n}\n\nfunc (c *CoreFoundationLib) CFDataGetBytePtr(theData uintptr) unsafe.Pointer {\n\tfn := getFunc[CFDataGetBytePtrFunc](c.library, \"CFDataGetBytePtr\")\n\treturn fn(theData)\n}\n\nfunc (c *CoreFoundationLib) CFRelease(cf uintptr) {\n\tfn := getFunc[CFReleaseFunc](c.library, \"CFRelease\")\n\tfn(cf)\n}\n\ntype IOKitLib struct {\n\t*library\n}\n\nfunc NewIOKitLib() (*IOKitLib, error) {\n\tlibrary, err := newLibrary(IOKitLibPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &IOKitLib{library}, nil\n}\n\nfunc (l *IOKitLib) IOServiceGetMatchingService(mainPort uint32, matching uintptr) uint32 {\n\tfn := getFunc[IOServiceGetMatchingServiceFunc](l.library, \"IOServiceGetMatchingService\")\n\treturn fn(mainPort, matching)\n}\n\nfunc (l *IOKitLib) IOServiceGetMatchingServices(mainPort uint32, matching uintptr, existing *uint32) int32 {\n\tfn := getFunc[IOServiceGetMatchingServicesFunc](l.library, \"IOServiceGetMatchingServices\")\n\treturn fn(mainPort, matching, existing)\n}\n\nfunc (l *IOKitLib) IOServiceMatching(name string) unsafe.Pointer {\n\tfn := getFunc[IOServiceMatchingFunc](l.library, \"IOServiceMatching\")\n\treturn fn(name)\n}\n\nfunc (l *IOKitLib) IOServiceOpen(service, owningTask, connType uint32, connect *uint32) int32 {\n\tfn := getFunc[IOServiceOpenFunc](l.library, \"IOServiceOpen\")\n\treturn fn(service, owningTask, connType, connect)\n}\n\nfunc (l *IOKitLib) IOServiceClose(connect uint32) int32 {\n\tfn := getFunc[IOServiceCloseFunc](l.library, \"IOServiceClose\")\n\treturn fn(connect)\n}\n\nfunc (l *IOKitLib) IOIteratorNext(iterator uint32) uint32 {\n\tfn := getFunc[IOIteratorNextFunc](l.library, \"IOIteratorNext\")\n\treturn fn(iterator)\n}\n\nfunc (l *IOKitLib) IORegistryEntryGetName(entry uint32, name CStr) int32 {\n\tfn := getFunc[IORegistryEntryGetNameFunc](l.library, \"IORegistryEntryGetName\")\n\treturn fn(entry, name)\n}\n\nfunc (l *IOKitLib) IORegistryEntryGetParentEntry(entry uint32, plane string, parent *uint32) int32 {\n\tfn := getFunc[IORegistryEntryGetParentEntryFunc](l.library, \"IORegistryEntryGetParentEntry\")\n\treturn fn(entry, plane, parent)\n}\n\nfunc (l *IOKitLib) IORegistryEntryCreateCFProperty(entry uint32, key, allocator uintptr, options uint32) unsafe.Pointer {\n\tfn := getFunc[IORegistryEntryCreateCFPropertyFunc](l.library, \"IORegistryEntryCreateCFProperty\")\n\treturn fn(entry, key, allocator, options)\n}\n\nfunc (l *IOKitLib) IORegistryEntryCreateCFProperties(entry uint32, properties unsafe.Pointer, allocator uintptr, options uint32) int32 {\n\tfn := getFunc[IORegistryEntryCreateCFPropertiesFunc](l.library, \"IORegistryEntryCreateCFProperties\")\n\treturn fn(entry, properties, allocator, options)\n}\n\nfunc (l *IOKitLib) IOObjectConformsTo(object uint32, className string) bool {\n\tfn := getFunc[IOObjectConformsToFunc](l.library, \"IOObjectConformsTo\")\n\treturn fn(object, className)\n}\n\nfunc (l *IOKitLib) IOObjectRelease(object uint32) int32 {\n\tfn := getFunc[IOObjectReleaseFunc](l.library, \"IOObjectRelease\")\n\treturn fn(object)\n}\n\nfunc (l *IOKitLib) IOConnectCallStructMethod(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int32 {\n\tfn := getFunc[IOConnectCallStructMethodFunc](l.library, \"IOConnectCallStructMethod\")\n\treturn fn(connection, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt)\n}\n\nfunc (l *IOKitLib) IOHIDEventSystemClientCreate(allocator uintptr) unsafe.Pointer {\n\tfn := getFunc[IOHIDEventSystemClientCreateFunc](l.library, \"IOHIDEventSystemClientCreate\")\n\treturn fn(allocator)\n}\n\nfunc (l *IOKitLib) IOHIDEventSystemClientSetMatching(client, match uintptr) int32 {\n\tfn := getFunc[IOHIDEventSystemClientSetMatchingFunc](l.library, \"IOHIDEventSystemClientSetMatching\")\n\treturn fn(client, match)\n}\n\nfunc (l *IOKitLib) IOHIDServiceClientCopyEvent(service uintptr, eventType int64, options int32, timeout int64) unsafe.Pointer {\n\tfn := getFunc[IOHIDServiceClientCopyEventFunc](l.library, \"IOHIDServiceClientCopyEvent\")\n\treturn fn(service, eventType, options, timeout)\n}\n\nfunc (l *IOKitLib) IOHIDServiceClientCopyProperty(service, property uintptr) unsafe.Pointer {\n\tfn := getFunc[IOHIDServiceClientCopyPropertyFunc](l.library, \"IOHIDServiceClientCopyProperty\")\n\treturn fn(service, property)\n}\n\nfunc (l *IOKitLib) IOHIDEventGetFloatValue(event uintptr, field int32) float64 {\n\tfn := getFunc[IOHIDEventGetFloatValueFunc](l.library, \"IOHIDEventGetFloatValue\")\n\treturn fn(event, field)\n}\n\nfunc (l *IOKitLib) IOHIDEventSystemClientCopyServices(client uintptr) unsafe.Pointer {\n\tfn := getFunc[IOHIDEventSystemClientCopyServicesFunc](l.library, \"IOHIDEventSystemClientCopyServices\")\n\treturn fn(client)\n}\n\ntype SystemLib struct {\n\t*library\n}\n\nfunc NewSystemLib() (*SystemLib, error) {\n\tlibrary, err := newLibrary(SystemLibPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &SystemLib{library}, nil\n}\n\nfunc (s *SystemLib) HostProcessorInfo(host uint32, flavor int32, outProcessorCount *uint32, outProcessorInfo uintptr,\n\toutProcessorInfoCnt *uint32,\n) int32 {\n\tfn := getFunc[HostProcessorInfoFunc](s.library, \"host_processor_info\")\n\treturn fn(host, flavor, outProcessorCount, outProcessorInfo, outProcessorInfoCnt)\n}\n\nfunc (s *SystemLib) HostStatistics(host uint32, flavor int32, hostInfoOut uintptr, hostInfoOutCnt *uint32) int32 {\n\tfn := getFunc[HostStatisticsFunc](s.library, \"host_statistics\")\n\treturn fn(host, flavor, hostInfoOut, hostInfoOutCnt)\n}\n\nfunc (s *SystemLib) MachHostSelf() uint32 {\n\tfn := getFunc[MachHostSelfFunc](s.library, \"mach_host_self\")\n\treturn fn()\n}\n\nfunc (s *SystemLib) MachTaskSelf() uint32 {\n\tfn := getFunc[MachTaskSelfFunc](s.library, \"mach_task_self\")\n\treturn fn()\n}\n\nfunc (s *SystemLib) MachTimeBaseInfo(info uintptr) int32 {\n\tfn := getFunc[MachTimeBaseInfoFunc](s.library, \"mach_timebase_info\")\n\treturn fn(info)\n}\n\nfunc (s *SystemLib) VMDeallocate(targetTask uint32, vmAddress, vmSize uintptr) int32 {\n\tfn := getFunc[VMDeallocateFunc](s.library, \"vm_deallocate\")\n\treturn fn(targetTask, vmAddress, vmSize)\n}\n\nfunc (s *SystemLib) ProcPidPath(pid int32, buffer uintptr, bufferSize uint32) int32 {\n\tfn := getFunc[ProcPidPathFunc](s.library, \"proc_pidpath\")\n\treturn fn(pid, buffer, bufferSize)\n}\n\nfunc (s *SystemLib) ProcPidInfo(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32 {\n\tfn := getFunc[ProcPidInfoFunc](s.library, \"proc_pidinfo\")\n\treturn fn(pid, flavor, arg, buffer, bufferSize)\n}\n\n// status codes\nconst (\n\tKERN_SUCCESS = 0\n)\n\n// IOKit types and constants.\ntype (\n\tIOServiceGetMatchingServiceFunc       func(mainPort uint32, matching uintptr) uint32\n\tIOServiceGetMatchingServicesFunc      func(mainPort uint32, matching uintptr, existing *uint32) int32\n\tIOServiceMatchingFunc                 func(name string) unsafe.Pointer\n\tIOServiceOpenFunc                     func(service, owningTask, connType uint32, connect *uint32) int32\n\tIOServiceCloseFunc                    func(connect uint32) int32\n\tIOIteratorNextFunc                    func(iterator uint32) uint32\n\tIORegistryEntryGetNameFunc            func(entry uint32, name CStr) int32\n\tIORegistryEntryGetParentEntryFunc     func(entry uint32, plane string, parent *uint32) int32\n\tIORegistryEntryCreateCFPropertyFunc   func(entry uint32, key, allocator uintptr, options uint32) unsafe.Pointer\n\tIORegistryEntryCreateCFPropertiesFunc func(entry uint32, properties unsafe.Pointer, allocator uintptr, options uint32) int32\n\tIOObjectConformsToFunc                func(object uint32, className string) bool\n\tIOObjectReleaseFunc                   func(object uint32) int32\n\tIOConnectCallStructMethodFunc         func(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int32\n\n\tIOHIDEventSystemClientCreateFunc      func(allocator uintptr) unsafe.Pointer\n\tIOHIDEventSystemClientSetMatchingFunc func(client, match uintptr) int32\n\tIOHIDServiceClientCopyEventFunc       func(service uintptr, eventType int64,\n\t\toptions int32, timeout int64) unsafe.Pointer\n\tIOHIDServiceClientCopyPropertyFunc     func(service, property uintptr) unsafe.Pointer\n\tIOHIDEventGetFloatValueFunc            func(event uintptr, field int32) float64\n\tIOHIDEventSystemClientCopyServicesFunc func(client uintptr) unsafe.Pointer\n)\n\nconst (\n\tKIOMainPortDefault = 0\n\n\tKIOHIDEventTypeTemperature = 15\n\n\tKNilOptions = 0\n)\n\nconst (\n\tKIOMediaWholeKey = \"Media\"\n\tKIOServicePlane  = \"IOService\"\n)\n\n// CoreFoundation types and constants.\ntype (\n\tCFGetTypeIDFunc        func(cf uintptr) int64\n\tCFNumberCreateFunc     func(allocator uintptr, theType int64, valuePtr uintptr) unsafe.Pointer\n\tCFNumberGetValueFunc   func(num uintptr, theType int64, valuePtr uintptr) bool\n\tCFDictionaryCreateFunc func(allocator uintptr, keys, values *unsafe.Pointer, numValues int64,\n\t\tkeyCallBacks, valueCallBacks uintptr) unsafe.Pointer\n\tCFDictionaryAddValueFunc      func(theDict, key, value uintptr)\n\tCFDictionaryGetValueFunc      func(theDict, key uintptr) unsafe.Pointer\n\tCFArrayGetCountFunc           func(theArray uintptr) int64\n\tCFArrayGetValueAtIndexFunc    func(theArray uintptr, index int64) unsafe.Pointer\n\tCFStringCreateMutableFunc     func(alloc uintptr, maxLength int64) unsafe.Pointer\n\tCFStringGetLengthFunc         func(theString uintptr) int64\n\tCFStringGetCStringFunc        func(theString uintptr, buffer CStr, bufferSize int64, encoding uint32)\n\tCFStringCreateWithCStringFunc func(alloc uintptr, cStr string, encoding uint32) unsafe.Pointer\n\tCFDataGetLengthFunc           func(theData uintptr) int64\n\tCFDataGetBytePtrFunc          func(theData uintptr) unsafe.Pointer\n\tCFReleaseFunc                 func(cf uintptr)\n)\n\nconst (\n\tKCFStringEncodingUTF8 = 0x08000100\n\tKCFNumberSInt64Type   = 4\n\tKCFNumberIntType      = 9\n\tKCFAllocatorDefault   = 0\n\tKCFNotFound           = -1\n)\n\n// libSystem types and constants.\ntype MachTimeBaseInfo struct {\n\tNumer uint32\n\tDenom uint32\n}\n\ntype (\n\tHostProcessorInfoFunc func(host uint32, flavor int32, outProcessorCount *uint32, outProcessorInfo uintptr,\n\t\toutProcessorInfoCnt *uint32) int32\n\tHostStatisticsFunc   func(host uint32, flavor int32, hostInfoOut uintptr, hostInfoOutCnt *uint32) int32\n\tMachHostSelfFunc     func() uint32\n\tMachTaskSelfFunc     func() uint32\n\tMachTimeBaseInfoFunc func(info uintptr) int32\n\tVMDeallocateFunc     func(targetTask uint32, vmAddress, vmSize uintptr) int32\n)\n\nconst (\n\tHostProcessorInfoSym = \"host_processor_info\"\n\tHostStatisticsSym    = \"host_statistics\"\n\tMachHostSelfSym      = \"mach_host_self\"\n\tMachTaskSelfSym      = \"mach_task_self\"\n\tMachTimeBaseInfoSym  = \"mach_timebase_info\"\n\tVMDeallocateSym      = \"vm_deallocate\"\n)\n\nconst (\n\tHOST_VM_INFO       = 2\n\tHOST_CPU_LOAD_INFO = 3\n\n\tHOST_VM_INFO_COUNT = 0xf\n)\n\ntype (\n\tProcPidPathFunc func(pid int32, buffer uintptr, bufferSize uint32) int32\n\tProcPidInfoFunc func(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32\n)\n\nconst (\n\tSysctlSym      = \"sysctl\"\n\tProcPidPathSym = \"proc_pidpath\"\n\tProcPidInfoSym = \"proc_pidinfo\"\n)\n\nconst (\n\tMAXPATHLEN               = 1024\n\tPROC_PIDLISTFDS          = 1\n\tPROC_PIDPATHINFO_MAXSIZE = 4 * MAXPATHLEN\n\tPROC_PIDTASKINFO         = 4\n\tPROC_PIDVNODEPATHINFO    = 9\n)\n\n// SMC represents a SMC instance.\ntype SMC struct {\n\tlib  *IOKitLib\n\tconn uint32\n}\n\nconst ioServiceSMC = \"AppleSMC\"\n\nconst (\n\tKSMCUserClientOpen  = 0\n\tKSMCUserClientClose = 1\n\tKSMCHandleYPCEvent  = 2\n\tKSMCReadKey         = 5\n\tKSMCWriteKey        = 6\n\tKSMCGetKeyCount     = 7\n\tKSMCGetKeyFromIndex = 8\n\tKSMCGetKeyInfo      = 9\n)\n\nconst (\n\tKSMCSuccess     = 0\n\tKSMCError       = 1\n\tKSMCKeyNotFound = 132\n)\n\nfunc NewSMC() (*SMC, error) {\n\tiokit, err := NewIOKitLib()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tservice := iokit.IOServiceGetMatchingService(0, uintptr(iokit.IOServiceMatching(ioServiceSMC)))\n\tif service == 0 {\n\t\treturn nil, fmt.Errorf(\"ERROR: %s NOT FOUND\", ioServiceSMC)\n\t}\n\n\tvar conn uint32\n\tmachTaskSelf := getFunc[MachTaskSelfFunc](iokit.library, \"mach_task_self\")\n\tif result := iokit.IOServiceOpen(service, machTaskSelf(), 0, &conn); result != 0 {\n\t\treturn nil, errors.New(\"ERROR: IOServiceOpen failed\")\n\t}\n\n\tiokit.IOObjectRelease(service)\n\treturn &SMC{\n\t\tlib:  iokit,\n\t\tconn: conn,\n\t}, nil\n}\n\nfunc (s *SMC) CallStruct(selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int32 {\n\treturn s.lib.IOConnectCallStructMethod(s.conn, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt)\n}\n\nfunc (s *SMC) Close() error {\n\tif result := s.lib.IOServiceClose(s.conn); result != 0 {\n\t\treturn errors.New(\"ERROR: IOServiceClose failed\")\n\t}\n\ts.lib.Close()\n\treturn nil\n}\n\ntype CStr []byte\n\nfunc NewCStr(length int64) CStr {\n\treturn make(CStr, length)\n}\n\nfunc (s CStr) Length() int64 {\n\treturn int64(len(s))\n}\n\nfunc (s CStr) Ptr() *byte {\n\tif len(s) < 1 {\n\t\treturn nil\n\t}\n\n\treturn &s[0]\n}\n\nfunc (s CStr) Addr() uintptr {\n\treturn uintptr(unsafe.Pointer(s.Ptr()))\n}\n\nfunc (s CStr) GoString() string {\n\tif s == nil {\n\t\treturn \"\"\n\t}\n\n\tvar length int\n\tfor _, char := range s {\n\t\tif char == '\\x00' {\n\t\t\tbreak\n\t\t}\n\t\tlength++\n\t}\n\treturn string(s[:length])\n}\n\n// https://github.com/ebitengine/purego/blob/main/internal/strings/strings.go#L26\nfunc GoString(cStr *byte) string {\n\tif cStr == nil {\n\t\treturn \"\"\n\t}\n\tvar length int\n\tfor *(*byte)(unsafe.Add(unsafe.Pointer(cStr), uintptr(length))) != '\\x00' {\n\t\tlength++\n\t}\n\treturn string(unsafe.Slice(cStr, length))\n}\n\n// https://github.com/apple-oss-distributions/CF/blob/dc54c6bb1c1e5e0b9486c1d26dd5bef110b20bf3/CFString.c#L463\nfunc GetCFStringBufLengthForUTF8(length int64) int64 {\n\tif length > (math.MaxInt64 / 3) {\n\t\treturn KCFNotFound\n\t}\n\treturn length*3 + 1 // includes null terminator\n}\n"
  },
  {
    "path": "internal/common/common_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd || openbsd\n\npackage common\n\nimport (\n\t\"fmt\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc SysctlUint(mib string) (uint64, error) {\n\tbuf, err := unix.SysctlRaw(mib)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif len(buf) == 8 { // 64 bit\n\t\treturn *(*uint64)(unsafe.Pointer(&buf[0])), nil\n\t}\n\tif len(buf) == 4 { // 32bit\n\t\tt := *(*uint32)(unsafe.Pointer(&buf[0]))\n\t\treturn uint64(t), nil\n\t}\n\treturn 0, fmt.Errorf(\"unexpected size: %s, %d\", mib, len(buf))\n}\n\nfunc CallSyscall(mib []int32) ([]byte, uint64, error) {\n\tmibptr := unsafe.Pointer(&mib[0])\n\tmiblen := uint64(len(mib))\n\n\t// get required buffer size\n\tlength := uint64(0)\n\t_, _, err := unix.Syscall6(\n\t\tunix.SYS___SYSCTL,\n\t\tuintptr(mibptr),\n\t\tuintptr(miblen),\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\t0,\n\t\t0)\n\tif err != 0 {\n\t\tvar b []byte\n\t\treturn b, length, err\n\t}\n\tif length == 0 {\n\t\tvar b []byte\n\t\treturn b, length, err\n\t}\n\t// get proc info itself\n\tbuf := make([]byte, length)\n\t_, _, err = unix.Syscall6(\n\t\tunix.SYS___SYSCTL,\n\t\tuintptr(mibptr),\n\t\tuintptr(miblen),\n\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\t0,\n\t\t0)\n\tif err != 0 {\n\t\treturn buf, length, err\n\t}\n\n\treturn buf, length, nil\n}\n"
  },
  {
    "path": "internal/common/common_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"time\"\n)\n\n// cachedBootTime must be accessed via atomic.Load/StoreUint64\nvar cachedBootTime uint64\n\nfunc NumProcs() (uint64, error) {\n\treturn NumProcsWithContext(context.Background())\n}\n\nfunc NumProcsWithContext(ctx context.Context) (uint64, error) {\n\tf, err := os.Open(HostProcWithContext(ctx))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer f.Close()\n\n\tlist, err := f.Readdirnames(-1)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tvar cnt uint64\n\n\tfor _, v := range list {\n\t\tif _, err = strconv.ParseUint(v, 10, 64); err == nil {\n\t\t\tcnt++\n\t\t}\n\t}\n\n\treturn cnt, nil\n}\n\nfunc BootTimeWithContext(ctx context.Context, enableCache bool) (uint64, error) {\n\tif enableCache {\n\t\tt := atomic.LoadUint64(&cachedBootTime)\n\t\tif t != 0 {\n\t\t\treturn t, nil\n\t\t}\n\t}\n\n\tsystem, role, err := VirtualizationWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tuseStatFile := true\n\tif system == \"lxc\" && role == \"guest\" {\n\t\t// if lxc, /proc/uptime is used.\n\t\tuseStatFile = false\n\t} else if system == \"docker\" && role == \"guest\" {\n\t\t// also docker, guest\n\t\tuseStatFile = false\n\t}\n\n\tif useStatFile {\n\t\tt, err := readBootTimeStat(ctx)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tif enableCache {\n\t\t\tatomic.StoreUint64(&cachedBootTime, t)\n\t\t}\n\n\t\treturn t, nil\n\t}\n\n\tfilename := HostProcWithContext(ctx, \"uptime\")\n\tlines, err := ReadLines(filename)\n\tif err != nil {\n\t\treturn handleBootTimeFileReadErr(err)\n\t}\n\tcurrentTime := float64(time.Now().UnixNano()) / float64(time.Second)\n\n\tif len(lines) != 1 {\n\t\treturn 0, errors.New(\"wrong uptime format\")\n\t}\n\tf := strings.Fields(lines[0])\n\tb, err := strconv.ParseFloat(f[0], 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tt := currentTime - b\n\n\tif enableCache {\n\t\tatomic.StoreUint64(&cachedBootTime, uint64(t))\n\t}\n\n\treturn uint64(t), nil\n}\n\nfunc handleBootTimeFileReadErr(err error) (uint64, error) {\n\tif !os.IsPermission(err) {\n\t\treturn 0, err\n\t}\n\tvar info syscall.Sysinfo_t\n\terr = syscall.Sysinfo(&info)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tcurrentTime := time.Now().UnixNano() / int64(time.Second)\n\tt := currentTime - int64(info.Uptime)\n\treturn uint64(t), nil\n}\n\nfunc readBootTimeStat(ctx context.Context) (uint64, error) {\n\tfilename := HostProcWithContext(ctx, \"stat\")\n\tline, err := ReadLine(filename, \"btime\")\n\tif err != nil {\n\t\treturn handleBootTimeFileReadErr(err)\n\t}\n\tif strings.HasPrefix(line, \"btime\") {\n\t\tf := strings.Fields(line)\n\t\tif len(f) != 2 {\n\t\t\treturn 0, errors.New(\"wrong btime format\")\n\t\t}\n\t\tb, err := strconv.ParseInt(f[1], 10, 64)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tt := uint64(b)\n\t\treturn t, nil\n\t}\n\treturn 0, errors.New(\"could not find btime\")\n}\n\nfunc Virtualization() (string, string, error) {\n\treturn VirtualizationWithContext(context.Background())\n}\n\n// required variables for concurrency safe virtualization caching\nvar (\n\tcachedVirtMap   map[string]string\n\tcachedVirtMutex sync.RWMutex\n\tcachedVirtOnce  sync.Once\n)\n\nfunc VirtualizationWithContext(ctx context.Context) (string, string, error) {\n\tvar system, role string\n\n\t// if cached already, return from cache\n\tcachedVirtMutex.RLock() // unlock won't be deferred so concurrent reads don't wait for long\n\tif cachedVirtMap != nil {\n\t\tcachedSystem, cachedRole := cachedVirtMap[\"system\"], cachedVirtMap[\"role\"]\n\t\tcachedVirtMutex.RUnlock()\n\t\treturn cachedSystem, cachedRole, nil\n\t}\n\tcachedVirtMutex.RUnlock()\n\n\tfilename := HostProcWithContext(ctx, \"xen\")\n\tif PathExists(filename) {\n\t\tsystem = \"xen\"\n\t\trole = \"guest\" // assume guest\n\n\t\tif PathExists(filepath.Join(filename, \"capabilities\")) {\n\t\t\tcontents, err := ReadLines(filepath.Join(filename, \"capabilities\"))\n\t\t\tif err == nil {\n\t\t\t\tif StringsContains(contents, \"control_d\") {\n\t\t\t\t\trole = \"host\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfilename = HostProcWithContext(ctx, \"modules\")\n\tif PathExists(filename) {\n\t\tcontents, err := ReadLines(filename)\n\t\tif err == nil {\n\t\t\tswitch {\n\t\t\tcase StringsContains(contents, \"kvm\"):\n\t\t\t\tsystem = \"kvm\"\n\t\t\t\trole = \"host\"\n\t\t\tcase StringsContains(contents, \"hv_util\"):\n\t\t\t\tsystem = \"hyperv\"\n\t\t\t\trole = \"guest\"\n\t\t\tcase StringsContains(contents, \"vboxdrv\"):\n\t\t\t\tsystem = \"vbox\"\n\t\t\t\trole = \"host\"\n\t\t\tcase StringsContains(contents, \"vboxguest\"):\n\t\t\t\tsystem = \"vbox\"\n\t\t\t\trole = \"guest\"\n\t\t\tcase StringsContains(contents, \"vmware\"):\n\t\t\t\tsystem = \"vmware\"\n\t\t\t\trole = \"guest\"\n\t\t\t}\n\t\t}\n\t}\n\n\tfilename = HostProcWithContext(ctx, \"cpuinfo\")\n\tif PathExists(filename) {\n\t\tcontents, err := ReadLines(filename)\n\t\tif err == nil {\n\t\t\tif StringsContains(contents, \"QEMU Virtual CPU\") ||\n\t\t\t\tStringsContains(contents, \"Common KVM processor\") ||\n\t\t\t\tStringsContains(contents, \"Common 32-bit KVM processor\") {\n\t\t\t\tsystem = \"kvm\"\n\t\t\t\trole = \"guest\"\n\t\t\t}\n\t\t}\n\t}\n\n\tfilename = HostProcWithContext(ctx, \"bus/pci/devices\")\n\tif PathExists(filename) {\n\t\tcontents, err := ReadLines(filename)\n\t\tif err == nil {\n\t\t\tif StringsContains(contents, \"virtio-pci\") {\n\t\t\t\trole = \"guest\"\n\t\t\t}\n\t\t}\n\t}\n\n\tfilename = HostProcWithContext(ctx)\n\tif PathExists(filepath.Join(filename, \"bc\", \"0\")) {\n\t\tsystem = \"openvz\"\n\t\trole = \"host\"\n\t} else if PathExists(filepath.Join(filename, \"vz\")) {\n\t\tsystem = \"openvz\"\n\t\trole = \"guest\"\n\t}\n\n\t// not use dmidecode because it requires root\n\tif PathExists(filepath.Join(filename, \"self\", \"status\")) {\n\t\tcontents, err := ReadLines(filepath.Join(filename, \"self\", \"status\"))\n\t\tif err == nil {\n\t\t\tif StringsContains(contents, \"s_context:\") ||\n\t\t\t\tStringsContains(contents, \"VxID:\") {\n\t\t\t\tsystem = \"linux-vserver\"\n\t\t\t}\n\t\t\t// TODO: guest or host\n\t\t}\n\t}\n\n\tif PathExists(filepath.Join(filename, \"1\", \"environ\")) {\n\t\tcontents, err := ReadFile(filepath.Join(filename, \"1\", \"environ\"))\n\n\t\tif err == nil {\n\t\t\tif strings.Contains(contents, \"container=lxc\") {\n\t\t\t\tsystem = \"lxc\"\n\t\t\t\trole = \"guest\"\n\t\t\t}\n\t\t}\n\t}\n\n\tif PathExists(filepath.Join(filename, \"self\", \"cgroup\")) {\n\t\tcontents, err := ReadLines(filepath.Join(filename, \"self\", \"cgroup\"))\n\t\tif err == nil {\n\t\t\tswitch {\n\t\t\tcase StringsContains(contents, \"lxc\"):\n\t\t\t\tsystem = \"lxc\"\n\t\t\t\trole = \"guest\"\n\t\t\tcase StringsContains(contents, \"docker\"):\n\t\t\t\tsystem = \"docker\"\n\t\t\t\trole = \"guest\"\n\t\t\tcase StringsContains(contents, \"machine-rkt\"):\n\t\t\t\tsystem = \"rkt\"\n\t\t\t\trole = \"guest\"\n\t\t\tcase PathExists(\"/usr/bin/lxc-version\"):\n\t\t\t\tsystem = \"lxc\"\n\t\t\t\trole = \"host\"\n\t\t\t}\n\t\t}\n\t}\n\n\tif PathExists(HostEtcWithContext(ctx, \"os-release\")) {\n\t\tp, _, err := GetOSReleaseWithContext(ctx)\n\t\tif err == nil && p == \"coreos\" {\n\t\t\tsystem = \"rkt\" // Is it true?\n\t\t\trole = \"host\"\n\t\t}\n\t}\n\n\tif PathExists(HostRootWithContext(ctx, \".dockerenv\")) {\n\t\tsystem = \"docker\"\n\t\trole = \"guest\"\n\t}\n\n\t// before returning for the first time, cache the system and role\n\tcachedVirtOnce.Do(func() {\n\t\tcachedVirtMutex.Lock()\n\t\tdefer cachedVirtMutex.Unlock()\n\t\tcachedVirtMap = map[string]string{\n\t\t\t\"system\": system,\n\t\t\t\"role\":   role,\n\t\t}\n\t})\n\n\treturn system, role, nil\n}\n\nfunc GetOSRelease() (platform, version string, err error) {\n\treturn GetOSReleaseWithContext(context.Background())\n}\n\nfunc GetOSReleaseWithContext(ctx context.Context) (platform, version string, err error) {\n\tcontents, err := ReadLines(HostEtcWithContext(ctx, \"os-release\"))\n\tif err != nil {\n\t\treturn \"\", \"\", nil // return empty\n\t}\n\tfor _, line := range contents {\n\t\tfield := strings.Split(line, \"=\")\n\t\tif len(field) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tswitch field[0] {\n\t\tcase \"ID\": // use ID for lowercase\n\t\t\tplatform = trimQuotes(field[1])\n\t\tcase \"VERSION_ID\":\n\t\t\tversion = trimQuotes(field[1])\n\t\t}\n\t}\n\n\t// cleanup amazon ID\n\tif platform == \"amzn\" {\n\t\tplatform = \"amazon\"\n\t}\n\n\treturn platform, version, nil\n}\n\n// Remove quotes of the source string\nfunc trimQuotes(s string) string {\n\tif len(s) >= 2 {\n\t\tif s[0] == '\"' && s[len(s)-1] == '\"' {\n\t\t\treturn s[1 : len(s)-1]\n\t\t}\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "internal/common/common_netbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build netbsd\n\npackage common\n\nimport (\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc CallSyscall(mib []int32) ([]byte, uint64, error) {\n\tmibptr := unsafe.Pointer(&mib[0])\n\tmiblen := uint64(len(mib))\n\n\t// get required buffer size\n\tlength := uint64(0)\n\t_, _, err := unix.Syscall6(\n\t\tunix.SYS___SYSCTL,\n\t\tuintptr(mibptr),\n\t\tuintptr(miblen),\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\t0,\n\t\t0)\n\tif err != 0 {\n\t\tvar b []byte\n\t\treturn b, length, err\n\t}\n\tif length == 0 {\n\t\tvar b []byte\n\t\treturn b, length, err\n\t}\n\t// get proc info itself\n\tbuf := make([]byte, length)\n\t_, _, err = unix.Syscall6(\n\t\tunix.SYS___SYSCTL,\n\t\tuintptr(mibptr),\n\t\tuintptr(miblen),\n\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\t0,\n\t\t0)\n\tif err != 0 {\n\t\treturn buf, length, err\n\t}\n\n\treturn buf, length, nil\n}\n"
  },
  {
    "path": "internal/common/common_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage common\n\nimport (\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc CallSyscall(mib []int32) ([]byte, uint64, error) {\n\tmibptr := unsafe.Pointer(&mib[0])\n\tmiblen := uint64(len(mib))\n\n\t// get required buffer size\n\tlength := uint64(0)\n\t_, _, err := unix.Syscall6(\n\t\tunix.SYS___SYSCTL,\n\t\tuintptr(mibptr),\n\t\tuintptr(miblen),\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\t0,\n\t\t0)\n\tif err != 0 {\n\t\tvar b []byte\n\t\treturn b, length, err\n\t}\n\tif length == 0 {\n\t\tvar b []byte\n\t\treturn b, length, err\n\t}\n\t// get proc info itself\n\tbuf := make([]byte, length)\n\t_, _, err = unix.Syscall6(\n\t\tunix.SYS___SYSCTL,\n\t\tuintptr(mibptr),\n\t\tuintptr(miblen),\n\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\t0,\n\t\t0)\n\tif err != 0 {\n\t\treturn buf, length, err\n\t}\n\n\treturn buf, length, nil\n}\n"
  },
  {
    "path": "internal/common/common_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage common\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/common\"\n)\n\nfunc TestReadlines(t *testing.T) {\n\tret, err := ReadLines(\"common_test.go\")\n\trequire.NoError(t, err)\n\tassert.Containsf(t, ret[1], \"package common\", \"could not read correctly\")\n}\n\nfunc TestReadLinesOffsetN(t *testing.T) {\n\tret, err := ReadLinesOffsetN(\"common_test.go\", 3, 1)\n\trequire.NoError(t, err)\n\tassert.Containsf(t, ret[0], `import (`, \"could not read correctly\")\n}\n\nfunc TestIntToString(t *testing.T) {\n\tassert.Equalf(t, \"ABC\", IntToString([]int8{65, 66, 67}), \"could not convert\")\n}\n\nfunc TestByteToString(t *testing.T) {\n\tassert.Equalf(t, \"ABC\", ByteToString([]byte{65, 66, 67}), \"could not convert\")\n\n\tassert.Equalf(t, \"ABC\", ByteToString([]byte{0, 65, 66, 67}), \"could not convert\")\n}\n\nfunc TestHexToUint32(t *testing.T) {\n\tassert.Equalf(t, uint32(4294967295), HexToUint32(\"FFFFFFFF\"), \"Could not convert\")\n}\n\nfunc TestMustParseInt32(t *testing.T) {\n\tassert.Equalf(t, int32(11111), mustParseInt32(\"11111\"), \"could not parse\")\n}\n\nfunc TestMustParseUint64(t *testing.T) {\n\tassert.Equalf(t, uint64(11111), mustParseUint64(\"11111\"), \"could not parse\")\n}\n\nfunc TestMustParseFloat64(t *testing.T) {\n\trequire.InDeltaf(t, float64(11111.11), mustParseFloat64(\"11111.11\"), 0.01, \"could not parse\")\n\trequire.InDeltaf(t, float64(11111), mustParseFloat64(\"11111\"), 0.01, \"could not parse\")\n}\n\nfunc TestStringsContains(t *testing.T) {\n\ttarget, err := ReadLines(\"common_test.go\")\n\trequire.NoError(t, err)\n\tassert.Truef(t, StringsContains(target, \"func TestStringsContains(t *testing.T) {\"), \"cloud not test correctly\")\n}\n\nfunc TestPathExists(t *testing.T) {\n\tassert.Truef(t, PathExists(\"common_test.go\"), \"exists but return not exists\")\n\tassert.Falsef(t, PathExists(\"should_not_exists.go\"), \"not exists but return exists\")\n}\n\nfunc TestPathExistsWithContents(t *testing.T) {\n\tassert.Truef(t, PathExistsWithContents(\"common_test.go\"), \"exists but return not exists\")\n\tassert.Falsef(t, PathExistsWithContents(\"should_not_exists.go\"), \"not exists but return exists\")\n\n\tf, err := os.CreateTemp(\"\", \"empty_test.txt\")\n\trequire.NoErrorf(t, err, \"CreateTemp failed, %s\", err)\n\tdefer os.Remove(f.Name()) // clean up\n\n\tassert.Falsef(t, PathExistsWithContents(f.Name()), \"exists but no content file return true\")\n}\n\nfunc TestHostEtc(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"windows doesn't have etc\")\n\t}\n\tp := HostEtcWithContext(context.Background(), \"mtab\")\n\tassert.Equalf(t, \"/etc/mtab\", p, \"invalid HostEtc, %s\", p)\n}\n\nfunc TestGetSysctrlEnv(t *testing.T) {\n\t// Append case\n\tenv := getSysctrlEnv([]string{\"FOO=bar\"})\n\tassert.Truef(t, reflect.DeepEqual(env, []string{\"FOO=bar\", \"LC_ALL=C\"}), \"unexpected append result from getSysctrlEnv: %q\", env)\n\n\t// Replace case\n\tenv = getSysctrlEnv([]string{\"FOO=bar\", \"LC_ALL=en_US.UTF-8\"})\n\tassert.Truef(t, reflect.DeepEqual(env, []string{\"FOO=bar\", \"LC_ALL=C\"}), \"unexpected replace result from getSysctrlEnv: %q\", env)\n\n\t// Test against real env\n\tenv = getSysctrlEnv(os.Environ())\n\tfound := false\n\tfor _, v := range env {\n\t\tif v == \"LC_ALL=C\" {\n\t\t\tfound = true\n\t\t\tcontinue\n\t\t}\n\t\trequire.Falsef(t, strings.HasPrefix(v, \"LC_ALL\"), \"unexpected LC_ALL value: %q\", v)\n\t}\n\tassert.Truef(t, found, \"unexpected real result from getSysctrlEnv: %q\", env)\n}\n\nfunc TestGetEnvDefault(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"windows doesn't have etc\")\n\t}\n\tp := HostEtcWithContext(context.Background(), \"mtab\")\n\tassert.Equalf(t, \"/etc/mtab\", p, \"invalid HostEtc, %s\", p)\n}\n\nfunc TestGetEnvWithNoContext(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"windows doesn't have etc\")\n\t}\n\tt.Setenv(\"HOST_ETC\", \"/bar\")\n\tp := HostEtcWithContext(context.Background(), \"mtab\")\n\tassert.Equalf(t, \"/bar/mtab\", p, \"invalid HostEtc, %s\", p)\n}\n\nfunc TestGetEnvWithContextOverride(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"windows doesn't have etc\")\n\t}\n\tt.Setenv(\"HOST_ETC\", \"/bar\")\n\tctx := context.WithValue(context.Background(), common.EnvKey, common.EnvMap{common.HostEtcEnvKey: \"/foo\"})\n\tp := HostEtcWithContext(ctx, \"mtab\")\n\tassert.Equalf(t, \"/foo/mtab\", p, \"invalid HostEtc, %s\", p)\n}\n"
  },
  {
    "path": "internal/common/common_unix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux || freebsd || darwin || openbsd\n\npackage common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc CallLsofWithContext(ctx context.Context, invoke Invoker, pid int32, args ...string) ([]string, error) {\n\tvar cmd []string\n\tif pid == 0 { // will get from all processes.\n\t\tcmd = []string{\"-a\", \"-n\", \"-P\"}\n\t} else {\n\t\tcmd = []string{\"-a\", \"-n\", \"-P\", \"-p\", strconv.Itoa(int(pid))}\n\t}\n\tcmd = append(cmd, args...)\n\tout, err := invoke.CommandWithContext(ctx, \"lsof\", cmd...)\n\tif err != nil {\n\t\tif errors.Is(err, exec.ErrNotFound) {\n\t\t\treturn []string{}, err\n\t\t}\n\t\t// if no pid found, lsof returns code 1.\n\t\tif err.Error() == \"exit status 1\" && len(out) == 0 {\n\t\t\treturn []string{}, nil\n\t\t}\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\n\tvar ret []string\n\tfor _, l := range lines[1:] {\n\t\tif l == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, l)\n\t}\n\treturn ret, nil\n}\n"
  },
  {
    "path": "internal/common/common_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"strings\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/yusufpapurcu/wmi\"\n\t\"golang.org/x/sys/windows\"\n)\n\n// for double values\ntype PDH_FMT_COUNTERVALUE_DOUBLE struct { //nolint:revive //FIXME\n\tCStatus     uint32\n\tDoubleValue float64\n}\n\n// for 64 bit integer values\ntype PDH_FMT_COUNTERVALUE_LARGE struct { //nolint:revive //FIXME\n\tCStatus    uint32\n\tLargeValue int64\n}\n\n// for long values\ntype PDH_FMT_COUNTERVALUE_LONG struct { //nolint:revive //FIXME\n\tCStatus   uint32\n\tLongValue int32\n\tpadding   [4]byte\n}\n\n// windows system const\nconst (\n\tERROR_SUCCESS        = 0\n\tERROR_FILE_NOT_FOUND = 2\n\tDRIVE_REMOVABLE      = 2\n\tDRIVE_FIXED          = 3\n\tHKEY_LOCAL_MACHINE   = 0x80000002\n\tRRF_RT_REG_SZ        = 0x00000002\n\tRRF_RT_REG_DWORD     = 0x00000010\n\tPDH_FMT_LONG         = 0x00000100\n\tPDH_FMT_DOUBLE       = 0x00000200\n\tPDH_FMT_LARGE        = 0x00000400\n\tPDH_INVALID_DATA     = 0xc0000bc6\n\tPDH_INVALID_HANDLE   = 0xC0000bbc\n\tPDH_NO_DATA          = 0x800007d5\n\n\tSTATUS_BUFFER_OVERFLOW      = 0x80000005\n\tSTATUS_BUFFER_TOO_SMALL     = 0xC0000023\n\tSTATUS_INFO_LENGTH_MISMATCH = 0xC0000004\n)\n\nconst (\n\tProcessBasicInformation = 0\n\tProcessWow64Information = 26\n\tProcessQueryInformation = windows.PROCESS_DUP_HANDLE | windows.PROCESS_QUERY_INFORMATION\n\n\tSystemExtendedHandleInformationClass = 64\n)\n\nvar (\n\tModkernel32 = windows.NewLazySystemDLL(\"kernel32.dll\")\n\tModNt       = windows.NewLazySystemDLL(\"ntdll.dll\")\n\tModPdh      = windows.NewLazySystemDLL(\"pdh.dll\")\n\tModPsapi    = windows.NewLazySystemDLL(\"psapi.dll\")\n\tModPowrProf = windows.NewLazySystemDLL(\"powrprof.dll\")\n\n\tProcGetSystemTimes                   = Modkernel32.NewProc(\"GetSystemTimes\")\n\tProcNtQuerySystemInformation         = ModNt.NewProc(\"NtQuerySystemInformation\")\n\tProcRtlGetNativeSystemInformation    = ModNt.NewProc(\"RtlGetNativeSystemInformation\")\n\tProcRtlNtStatusToDosError            = ModNt.NewProc(\"RtlNtStatusToDosError\")\n\tProcNtQueryInformationProcess        = ModNt.NewProc(\"NtQueryInformationProcess\")\n\tProcNtReadVirtualMemory              = ModNt.NewProc(\"NtReadVirtualMemory\")\n\tProcNtWow64QueryInformationProcess64 = ModNt.NewProc(\"NtWow64QueryInformationProcess64\")\n\tProcNtWow64ReadVirtualMemory64       = ModNt.NewProc(\"NtWow64ReadVirtualMemory64\")\n\n\tPdhOpenQuery                = ModPdh.NewProc(\"PdhOpenQuery\")\n\tPdhAddEnglishCounterW       = ModPdh.NewProc(\"PdhAddEnglishCounterW\")\n\tPdhCollectQueryData         = ModPdh.NewProc(\"PdhCollectQueryData\")\n\tPdhGetFormattedCounterValue = ModPdh.NewProc(\"PdhGetFormattedCounterValue\")\n\tPdhCloseQuery               = ModPdh.NewProc(\"PdhCloseQuery\")\n\n\tprocQueryDosDeviceW = Modkernel32.NewProc(\"QueryDosDeviceW\")\n)\n\ntype FILETIME struct {\n\tDwLowDateTime  uint32\n\tDwHighDateTime uint32\n}\n\n// borrowed from net/interface_windows.go\nfunc BytePtrToString(p *uint8) string {\n\ta := (*[10000]uint8)(unsafe.Pointer(p))\n\ti := 0\n\tfor a[i] != 0 {\n\t\ti++\n\t}\n\treturn string(a[:i])\n}\n\n// CounterInfo struct is used to track a windows performance counter\n// copied from https://github.com/mackerelio/mackerel-agent/\ntype CounterInfo struct {\n\tPostName    string\n\tCounterName string\n\tCounter     windows.Handle\n}\n\n// CreateQuery with a PdhOpenQuery call\n// copied from https://github.com/mackerelio/mackerel-agent/\nfunc CreateQuery() (windows.Handle, error) {\n\tvar query windows.Handle\n\tr, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query)))\n\tif r != 0 {\n\t\treturn 0, err\n\t}\n\treturn query, nil\n}\n\n// CreateCounter with a PdhAddEnglishCounterW call\nfunc CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) {\n\tvar counter windows.Handle\n\tr, _, err := PdhAddEnglishCounterW.Call(\n\t\tuintptr(query),\n\t\tuintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cname))),\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&counter)))\n\tif r != 0 {\n\t\treturn nil, err\n\t}\n\treturn &CounterInfo{\n\t\tPostName:    pname,\n\t\tCounterName: cname,\n\t\tCounter:     counter,\n\t}, nil\n}\n\n// GetCounterValue get counter value from handle\n// adapted from https://github.com/mackerelio/mackerel-agent/\nfunc GetCounterValue(counter windows.Handle) (float64, error) {\n\tvar value PDH_FMT_COUNTERVALUE_DOUBLE\n\tr, _, err := PdhGetFormattedCounterValue.Call(uintptr(counter), PDH_FMT_DOUBLE, uintptr(0), uintptr(unsafe.Pointer(&value)))\n\tif r != 0 && r != PDH_INVALID_DATA {\n\t\treturn 0.0, err\n\t}\n\treturn value.DoubleValue, nil\n}\n\ntype Win32PerformanceCounter struct {\n\tPostName    string\n\tCounterName string\n\tQuery       windows.Handle\n\tCounter     windows.Handle\n}\n\nfunc NewWin32PerformanceCounter(postName, counterName string) (*Win32PerformanceCounter, error) {\n\tquery, err := CreateQuery()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcounter := Win32PerformanceCounter{\n\t\tQuery:       query,\n\t\tPostName:    postName,\n\t\tCounterName: counterName,\n\t}\n\tr, _, err := PdhAddEnglishCounterW.Call(\n\t\tuintptr(counter.Query),\n\t\tuintptr(unsafe.Pointer(windows.StringToUTF16Ptr(counter.CounterName))),\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&counter.Counter)),\n\t)\n\tif r != 0 {\n\t\treturn nil, err\n\t}\n\treturn &counter, nil\n}\n\nfunc (w *Win32PerformanceCounter) GetValue() (float64, error) {\n\tr, _, err := PdhCollectQueryData.Call(uintptr(w.Query))\n\tif r != 0 && err != nil {\n\t\tif r == PDH_NO_DATA {\n\t\t\treturn 0.0, fmt.Errorf(\"%w: this counter has not data\", err)\n\t\t}\n\t\treturn 0.0, err\n\t}\n\n\treturn GetCounterValue(w.Counter)\n}\n\nfunc ProcessorQueueLengthCounter() (*Win32PerformanceCounter, error) {\n\treturn NewWin32PerformanceCounter(\"processor_queue_length\", `\\System\\Processor Queue Length`)\n}\n\n// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging\nfunc WMIQueryWithContext(ctx context.Context, query string, dst any, connectServerArgs ...any) error {\n\tif _, ok := ctx.Deadline(); !ok {\n\t\tctxTimeout, cancel := context.WithTimeout(ctx, Timeout)\n\t\tdefer cancel()\n\t\tctx = ctxTimeout\n\t}\n\n\terrChan := make(chan error, 1)\n\tgo func() {\n\t\terrChan <- wmi.Query(query, dst, connectServerArgs...)\n\t}()\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase err := <-errChan:\n\t\treturn err\n\t}\n}\n\n// Convert paths using native DOS format like:\n//\n//\t\"\\Device\\HarddiskVolume1\\Windows\\systemew\\file.txt\"\n//\n// into:\n//\n//\t\"C:\\Windows\\systemew\\file.txt\"\nfunc ConvertDOSPath(p string) string {\n\trawDrive := strings.Join(strings.Split(p, `\\`)[:3], `\\`)\n\n\tfor d := 'A'; d <= 'Z'; d++ {\n\t\tszDeviceName := string(d) + \":\"\n\t\tszTarget := make([]uint16, 512)\n\t\tret, _, _ := procQueryDosDeviceW.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(szDeviceName))),\n\t\t\tuintptr(unsafe.Pointer(&szTarget[0])),\n\t\t\tuintptr(len(szTarget)))\n\t\tif ret != 0 && windows.UTF16ToString(szTarget) == rawDrive {\n\t\t\treturn filepath.Join(szDeviceName, p[len(rawDrive):])\n\t\t}\n\t}\n\treturn p\n}\n\ntype NtStatus uint32\n\nfunc (s NtStatus) Error() error {\n\tif s == 0 {\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"NtStatus 0x%08x\", uint32(s))\n}\n\nfunc (s NtStatus) IsError() bool {\n\treturn s>>30 == 3\n}\n\ntype SystemExtendedHandleTableEntryInformation struct {\n\tObject                uintptr\n\tUniqueProcessId       uintptr\n\tHandleValue           uintptr\n\tGrantedAccess         uint32\n\tCreatorBackTraceIndex uint16\n\tObjectTypeIndex       uint16\n\tHandleAttributes      uint32\n\tReserved              uint32\n}\n\ntype SystemExtendedHandleInformation struct {\n\tNumberOfHandles uintptr\n\tReserved        uintptr\n\tHandles         [1]SystemExtendedHandleTableEntryInformation\n}\n\n// CallWithExpandingBuffer https://github.com/hillu/go-ntdll\nfunc CallWithExpandingBuffer(fn func() NtStatus, buf *[]byte, resultLength *uint32) NtStatus {\n\tfor {\n\t\tst := fn()\n\t\tif st == STATUS_BUFFER_OVERFLOW || st == STATUS_BUFFER_TOO_SMALL || st == STATUS_INFO_LENGTH_MISMATCH {\n\t\t\tif int(*resultLength) <= cap(*buf) {\n\t\t\t\t(*reflect.SliceHeader)(unsafe.Pointer(buf)).Len = int(*resultLength)\n\t\t\t} else {\n\t\t\t\t*buf = make([]byte, int(*resultLength))\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif !st.IsError() {\n\t\t\t*buf = (*buf)[:int(*resultLength)]\n\t\t}\n\t\treturn st\n\t}\n}\n\nfunc NtQuerySystemInformation(\n\tSystemInformationClass uint32,\n\tSystemInformation *byte,\n\tSystemInformationLength uint32,\n\tReturnLength *uint32,\n) NtStatus {\n\tr0, _, _ := ProcNtQuerySystemInformation.Call(\n\t\tuintptr(SystemInformationClass),\n\t\tuintptr(unsafe.Pointer(SystemInformation)),\n\t\tuintptr(SystemInformationLength),\n\t\tuintptr(unsafe.Pointer(ReturnLength)))\n\treturn NtStatus(r0)\n}\n"
  },
  {
    "path": "internal/common/endian.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage common\n\nimport \"unsafe\"\n\n// IsLittleEndian checks if the current platform uses little-endian.\n// copied from https://github.com/ntrrg/ntgo/blob/v0.8.0/runtime/infrastructure.go#L16 (MIT License)\nfunc IsLittleEndian() bool {\n\tvar x int16 = 0x0011\n\treturn *(*byte)(unsafe.Pointer(&x)) == 0x11\n}\n"
  },
  {
    "path": "internal/common/readlink_linux.go",
    "content": "package common\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"sync\"\n\t\"syscall\"\n)\n\nvar bufferPool = sync.Pool{\n\tNew: func() any {\n\t\tb := make([]byte, syscall.PathMax)\n\t\treturn &b\n\t},\n}\n\n// The following three functions are copied from stdlib.\n\n// ignoringEINTR2 is ignoringEINTR, but returning an additional value.\nfunc ignoringEINTR2[T any](fn func() (T, error)) (T, error) {\n\tfor {\n\t\tv, err := fn()\n\t\tif !errors.Is(err, syscall.EINTR) {\n\t\t\treturn v, err\n\t\t}\n\t}\n}\n\n// Many functions in package syscall return a count of -1 instead of 0.\n// Using fixCount(call()) instead of call() corrects the count.\nfunc fixCount(n int, err error) (int, error) {\n\tif n < 0 {\n\t\tn = 0\n\t}\n\treturn n, err\n}\n\n// Readlink behaves like os.Readlink but caches the buffer passed to syscall.Readlink.\nfunc Readlink(name string) (string, error) {\n\tb := bufferPool.Get().(*[]byte)\n\n\tn, err := ignoringEINTR2(func() (int, error) {\n\t\treturn fixCount(syscall.Readlink(name, *b))\n\t})\n\tif err != nil {\n\t\tbufferPool.Put(b)\n\t\treturn \"\", &os.PathError{Op: \"readlink\", Path: name, Err: err}\n\t}\n\n\tresult := string((*b)[:n])\n\tbufferPool.Put(b)\n\treturn result, nil\n}\n"
  },
  {
    "path": "internal/common/sleep.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage common\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\n// Sleep awaits for provided interval.\n// Can be interrupted by context cancellation.\nfunc Sleep(ctx context.Context, interval time.Duration) error {\n\ttimer := time.NewTimer(interval)\n\tselect {\n\tcase <-ctx.Done():\n\t\tif !timer.Stop() {\n\t\t\t<-timer.C\n\t\t}\n\t\treturn ctx.Err()\n\tcase <-timer.C:\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/common/sleep_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage common_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestSleep(test *testing.T) {\n\tconst dt = 50 * time.Millisecond\n\tt := func(name string, ctx context.Context, expected error) {\n\t\ttest.Run(name, func(test *testing.T) {\n\t\t\terr := common.Sleep(ctx, dt)\n\t\t\tif !errors.Is(err, expected) {\n\t\t\t\ttest.Errorf(\"expected %v, got %v\", expected, err)\n\t\t\t}\n\t\t})\n\t}\n\n\tctx := context.Background()\n\tcanceled, cancel := context.WithCancel(ctx)\n\tcancel()\n\n\tt(\"background context\", ctx, nil)\n\tt(\"canceled context\", canceled, context.Canceled)\n}\n"
  },
  {
    "path": "internal/common/warnings.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage common\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst (\n\tmaxWarnings             = 100 // An arbitrary limit to avoid excessive memory usage, it has no sense to store hundreds of errors\n\ttooManyErrorsMessage    = \"too many errors reported, next errors were discarded\"\n\tnumberOfWarningsMessage = \"Number of warnings:\"\n)\n\ntype Warnings struct {\n\tList          []error\n\ttooManyErrors bool\n\tVerbose       bool\n}\n\nfunc (w *Warnings) Add(err error) {\n\tif len(w.List) >= maxWarnings {\n\t\tw.tooManyErrors = true\n\t\treturn\n\t}\n\tw.List = append(w.List, err)\n}\n\nfunc (w *Warnings) Reference() error {\n\tif len(w.List) > 0 {\n\t\treturn w\n\t}\n\treturn nil\n}\n\nfunc (w *Warnings) Error() string {\n\tif w.Verbose {\n\t\tstr := \"\"\n\t\tvar sb strings.Builder\n\t\tfor i, e := range w.List {\n\t\t\tfmt.Fprintf(&sb, \"\\tError %d: %s\\n\", i, e.Error())\n\t\t}\n\t\tstr += sb.String()\n\t\tif w.tooManyErrors {\n\t\t\tstr += fmt.Sprintf(\"\\t%s\\n\", tooManyErrorsMessage)\n\t\t}\n\t\treturn str\n\t}\n\tif w.tooManyErrors {\n\t\treturn fmt.Sprintf(\"%s > %v - %s\", numberOfWarningsMessage, maxWarnings, tooManyErrorsMessage)\n\t}\n\treturn fmt.Sprintf(\"%s %v\", numberOfWarningsMessage, len(w.List))\n}\n"
  },
  {
    "path": "internal/common/warnings_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage common\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestWarnings_AddAndReference(t *testing.T) {\n\tw := &Warnings{}\n\trequire.NoError(t, w.Reference(), \"Expected nil reference for empty warnings\")\n\tw.Add(errors.New(\"first error\"))\n\trequire.Error(t, w.Reference(), \"Expected non-nil reference after adding error\")\n\tassert.Len(t, w.List, 1, \"Expected 1 warning\")\n}\n\nfunc TestWarnings_MaxLimit(t *testing.T) {\n\tw := &Warnings{}\n\tfor i := range maxWarnings + 10 {\n\t\tw.Add(fmt.Errorf(\"error %d\", i))\n\t}\n\tassert.Len(t, w.List, maxWarnings, \"Expected maxWarnings warnings\")\n\tassert.True(t, w.tooManyErrors, \"Expected tooManyErrors to be true after exceeding maxWarnings\")\n}\n\nfunc TestWarnings_ErrorVerbose(t *testing.T) {\n\tw := &Warnings{Verbose: true}\n\tw.Add(errors.New(\"err1\"))\n\tw.Add(errors.New(\"err2\"))\n\tmsg := w.Error()\n\tassert.NotEmpty(t, msg, \"Expected verbose error string\")\n\tassert.NotEqual(t, tooManyErrorsMessage, msg, \"Expected verbose error string, not tooManyErrorsMessage\")\n\tassert.Contains(t, msg, \"Error 0: err1\", \"Verbose error string missing expected error 0\")\n\tassert.Contains(t, msg, \"Error 1: err2\", \"Verbose error string missing expected error 1\")\n}\n\nfunc TestWarnings_ErrorNonVerbose(t *testing.T) {\n\tw := &Warnings{}\n\tw.Add(errors.New(\"err1\"))\n\tmsg := w.Error()\n\tassert.Equal(t, fmt.Sprintf(\"Number of warnings: %v\", len(w.List)), msg, \"Expected non-verbose error string\")\n}\n\nfunc TestWarnings_ErrorTooMany(t *testing.T) {\n\tw := &Warnings{Verbose: true}\n\tfor i := range maxWarnings + 1 {\n\t\tw.Add(fmt.Errorf(\"err%d\", i))\n\t}\n\tmsg := w.Error()\n\tassert.Contains(t, msg, tooManyErrorsMessage, \"Expected too many errors message in verbose output\")\n\tw.Verbose = false\n\tmsg = w.Error()\n\texpected := fmt.Sprintf(\"%s > %v - %s\", numberOfWarningsMessage, maxWarnings, tooManyErrorsMessage)\n\tassert.Equal(t, expected, msg, \"Expected too many errors message in non-verbose output\")\n}\n"
  },
  {
    "path": "load/load.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage load\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar invoke common.Invoker = common.Invoke{}\n\ntype AvgStat struct {\n\tLoad1  float64 `json:\"load1\"`\n\tLoad5  float64 `json:\"load5\"`\n\tLoad15 float64 `json:\"load15\"`\n}\n\nfunc (l AvgStat) String() string {\n\ts, _ := json.Marshal(l)\n\treturn string(s)\n}\n\ntype MiscStat struct {\n\tProcsTotal   int `json:\"procsTotal\"`\n\tProcsCreated int `json:\"procsCreated\"`\n\tProcsRunning int `json:\"procsRunning\"`\n\tProcsBlocked int `json:\"procsBlocked\"`\n\tCtxt         int `json:\"ctxt\"`\n}\n\nfunc (m MiscStat) String() string {\n\ts, _ := json.Marshal(m)\n\treturn string(s)\n}\n"
  },
  {
    "path": "load/load_aix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage load\n\nimport (\n\t\"context\"\n)\n\nfunc Avg() (*AvgStat, error) {\n\treturn AvgWithContext(context.Background())\n}\n\n// Misc returns miscellaneous host-wide statistics.\n// darwin use ps command to get process running/blocked count.\n// Almost same as Darwin implementation, but state is different.\nfunc Misc() (*MiscStat, error) {\n\treturn MiscWithContext(context.Background())\n}\n"
  },
  {
    "path": "load/load_aix_cgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && cgo\n\npackage load\n\n/*\n#cgo LDFLAGS: -L/usr/lib -lperfstat\n\n#include <libperfstat.h>\n#include <procinfo.h>\n#include <sys/thread.h>\n*/\nimport \"C\"\n\nimport (\n\t\"context\"\n\t\"unsafe\"\n\n\t\"github.com/power-devops/perfstat\"\n)\n\nfunc AvgWithContext(ctx context.Context) (*AvgStat, error) {\n\tc, err := perfstat.CpuTotalStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := &AvgStat{\n\t\tLoad1:  float64(c.LoadAvg1),\n\t\tLoad5:  float64(c.LoadAvg5),\n\t\tLoad15: float64(c.LoadAvg15),\n\t}\n\n\treturn ret, nil\n}\n\nfunc MiscWithContext(ctx context.Context) (*MiscStat, error) {\n\t// Count total processes and collect PIDs for thread-state enumeration.\n\tpinfo := C.struct_procentry64{}\n\tcpid := C.pid_t(0)\n\n\tret := MiscStat{}\n\tvar pids []C.pid_t\n\tfor {\n\t\tnum, err := C.getprocs64(unsafe.Pointer(&pinfo), C.sizeof_struct_procentry64, nil, 0, &cpid, 1)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif num == 0 {\n\t\t\tbreak\n\t\t}\n\t\tret.ProcsTotal++\n\t\tpids = append(pids, pinfo.pi_pid)\n\t}\n\n\t// Count threads in TSRUN state (runnable/running) across all processes.\n\t// SACTIVE at the process level means \"active in memory\" which includes\n\t// sleeping processes and is not a useful proxy for ProcsRunning.\n\ttinfo := C.struct_thrdentry64{}\n\tfor _, pid := range pids {\n\t\tctid := C.tid64_t(0)\n\t\tfor {\n\t\t\tn, err := C.getthrds64(pid, unsafe.Pointer(&tinfo), C.sizeof_struct_thrdentry64, &ctid, 1)\n\t\t\tif err != nil {\n\t\t\t\tbreak // process may have exited\n\t\t\t}\n\t\t\tif n == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif tinfo.ti_state == C.TSRUN {\n\t\t\t\tret.ProcsRunning++\n\t\t\t}\n\t\t}\n\t}\n\n\t// ProcsBlocked: processes sleeping waiting for I/O, equivalent to Linux D state.\n\t// perfstat IOWait and PhysIO are instantaneous counts, matching vmstat's b column.\n\tvar cpuStat C.perfstat_cpu_total_t\n\tif rc := C.perfstat_cpu_total(nil, &cpuStat, C.sizeof_perfstat_cpu_total_t, 1); rc == 1 {\n\t\tret.ProcsBlocked = int(cpuStat.iowait) + int(cpuStat.physio)\n\t}\n\n\treturn &ret, nil\n}\n"
  },
  {
    "path": "load/load_aix_nocgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && !cgo\n\npackage load\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar separator = regexp.MustCompile(`,?\\s+`)\n\nfunc AvgWithContext(ctx context.Context) (*AvgStat, error) {\n\tline, err := invoke.CommandWithContext(ctx, \"uptime\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tidx := bytes.Index(line, []byte(\"load average:\"))\n\tif idx < 0 {\n\t\treturn nil, common.ErrNotImplementedError\n\t}\n\tret := &AvgStat{}\n\n\tp := separator.Split(string(line[idx:]), 5)\n\tif 4 < len(p) && p[0] == \"load\" && p[1] == \"average:\" {\n\t\tif t, err := strconv.ParseFloat(p[2], 64); err == nil {\n\t\t\tret.Load1 = t\n\t\t}\n\t\tif t, err := strconv.ParseFloat(p[3], 64); err == nil {\n\t\t\tret.Load5 = t\n\t\t}\n\t\tif t, err := strconv.ParseFloat(p[4], 64); err == nil {\n\t\t\tret.Load15 = t\n\t\t}\n\t\treturn ret, nil\n\t}\n\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc MiscWithContext(ctx context.Context) (*MiscStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", \"-Ao\", \"state\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := &MiscStat{}\n\tfor _, line := range strings.Split(string(out), \"\\n\") {\n\t\tret.ProcsTotal++\n\t\tswitch line {\n\t\tcase \"R\":\n\t\tcase \"A\":\n\t\t\tret.ProcsRunning++\n\t\tcase \"T\":\n\t\t\tret.ProcsBlocked++\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t}\n\treturn ret, nil\n}\n"
  },
  {
    "path": "load/load_bsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd || openbsd\n\npackage load\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc Avg() (*AvgStat, error) {\n\treturn AvgWithContext(context.Background())\n}\n\nfunc AvgWithContext(_ context.Context) (*AvgStat, error) {\n\t// This SysctlRaw method borrowed from\n\t// https://github.com/prometheus/node_exporter/blob/master/collector/loadavg_freebsd.go\n\ttype loadavg struct {\n\t\tload  [3]uint32\n\t\tscale int\n\t}\n\tb, err := unix.SysctlRaw(\"vm.loadavg\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tload := *(*loadavg)(unsafe.Pointer((&b[0])))\n\tscale := float64(load.scale)\n\tret := &AvgStat{\n\t\tLoad1:  float64(load.load[0]) / scale,\n\t\tLoad5:  float64(load.load[1]) / scale,\n\t\tLoad15: float64(load.load[2]) / scale,\n\t}\n\n\treturn ret, nil\n}\n\ntype forkstat struct {\n\tforks    int\n\tvforks   int\n\t__tforks int //nolint:revive //FIXME\n}\n\n// Misc returns miscellaneous host-wide statistics.\n// darwin use ps command to get process running/blocked count.\n// Almost same as Darwin implementation, but state is different.\nfunc Misc() (*MiscStat, error) {\n\treturn MiscWithContext(context.Background())\n}\n\nfunc MiscWithContext(ctx context.Context) (*MiscStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", \"axo\", \"state\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\n\tret := MiscStat{}\n\tfor _, l := range lines {\n\t\tif strings.Contains(l, \"R\") {\n\t\t\tret.ProcsRunning++\n\t\t} else if strings.Contains(l, \"D\") {\n\t\t\tret.ProcsBlocked++\n\t\t}\n\t}\n\n\tf, err := getForkStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret.ProcsCreated = f.forks\n\n\treturn &ret, nil\n}\n"
  },
  {
    "path": "load/load_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage load\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc Avg() (*AvgStat, error) {\n\treturn AvgWithContext(context.Background())\n}\n\nfunc AvgWithContext(_ context.Context) (*AvgStat, error) {\n\t// This SysctlRaw method borrowed from\n\t// https://github.com/prometheus/node_exporter/blob/master/collector/loadavg_freebsd.go\n\t// this implementation is common with BSDs\n\ttype loadavg struct {\n\t\tload  [3]uint32\n\t\tscale int\n\t}\n\tb, err := unix.SysctlRaw(\"vm.loadavg\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tload := *(*loadavg)(unsafe.Pointer((&b[0])))\n\tscale := float64(load.scale)\n\tret := &AvgStat{\n\t\tLoad1:  float64(load.load[0]) / scale,\n\t\tLoad5:  float64(load.load[1]) / scale,\n\t\tLoad15: float64(load.load[2]) / scale,\n\t}\n\n\treturn ret, nil\n}\n\n// Misc returns miscellaneous host-wide statistics.\n// darwin use ps command to get process running/blocked count.\n// Almost same as FreeBSD implementation, but state is different.\n// U means 'Uninterruptible Sleep'.\nfunc Misc() (*MiscStat, error) {\n\treturn MiscWithContext(context.Background())\n}\n\nfunc MiscWithContext(ctx context.Context) (*MiscStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", \"axo\", \"state\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\n\tret := MiscStat{}\n\tfor _, l := range lines {\n\t\tif strings.Contains(l, \"R\") {\n\t\t\tret.ProcsRunning++\n\t\t} else if strings.Contains(l, \"U\") {\n\t\t\t// uninterruptible sleep == blocked\n\t\t\tret.ProcsBlocked++\n\t\t}\n\t}\n\n\treturn &ret, nil\n}\n"
  },
  {
    "path": "load/load_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !aix\n\npackage load\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc Avg() (*AvgStat, error) {\n\treturn AvgWithContext(context.Background())\n}\n\nfunc AvgWithContext(_ context.Context) (*AvgStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc Misc() (*MiscStat, error) {\n\treturn MiscWithContext(context.Background())\n}\n\nfunc MiscWithContext(_ context.Context) (*MiscStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "load/load_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd\n\npackage load\n\nfunc getForkStat() (forkstat, error) {\n\treturn forkstat{}, nil\n}\n"
  },
  {
    "path": "load/load_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage load\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc Avg() (*AvgStat, error) {\n\treturn AvgWithContext(context.Background())\n}\n\nfunc AvgWithContext(ctx context.Context) (*AvgStat, error) {\n\tstat, err := fileAvgWithContext(ctx)\n\tif err != nil {\n\t\tstat, err = sysinfoAvgWithContext()\n\t}\n\treturn stat, err\n}\n\nfunc sysinfoAvgWithContext() (*AvgStat, error) {\n\tvar info syscall.Sysinfo_t\n\terr := syscall.Sysinfo(&info)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconst siLoadShift = 16\n\treturn &AvgStat{\n\t\tLoad1:  float64(info.Loads[0]) / float64(1<<siLoadShift),\n\t\tLoad5:  float64(info.Loads[1]) / float64(1<<siLoadShift),\n\t\tLoad15: float64(info.Loads[2]) / float64(1<<siLoadShift),\n\t}, nil\n}\n\nfunc fileAvgWithContext(ctx context.Context) (*AvgStat, error) {\n\tvalues, err := readLoadAvgFromFile(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tload1, err := strconv.ParseFloat(values[0], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tload5, err := strconv.ParseFloat(values[1], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tload15, err := strconv.ParseFloat(values[2], 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := &AvgStat{\n\t\tLoad1:  load1,\n\t\tLoad5:  load5,\n\t\tLoad15: load15,\n\t}\n\n\treturn ret, nil\n}\n\n// Misc returns miscellaneous host-wide statistics.\n// Note: the name should be changed near future.\nfunc Misc() (*MiscStat, error) {\n\treturn MiscWithContext(context.Background())\n}\n\nfunc MiscWithContext(ctx context.Context) (*MiscStat, error) {\n\tfilename := common.HostProcWithContext(ctx, \"stat\")\n\tout, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := &MiscStat{}\n\tlines := strings.Split(string(out), \"\\n\")\n\tfor _, line := range lines {\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) != 2 {\n\t\t\tcontinue\n\t\t}\n\t\tv, err := strconv.ParseInt(fields[1], 10, 64)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tswitch fields[0] {\n\t\tcase \"processes\":\n\t\t\tret.ProcsCreated = int(v)\n\t\tcase \"procs_running\":\n\t\t\tret.ProcsRunning = int(v)\n\t\tcase \"procs_blocked\":\n\t\t\tret.ProcsBlocked = int(v)\n\t\tcase \"ctxt\":\n\t\t\tret.Ctxt = int(v)\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t}\n\n\tprocsTotal, err := common.NumProcsWithContext(ctx)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tret.ProcsTotal = int(procsTotal)\n\n\treturn ret, nil\n}\n\nfunc readLoadAvgFromFile(ctx context.Context) ([]string, error) {\n\tloadavgFilename := common.HostProcWithContext(ctx, \"loadavg\")\n\tline, err := os.ReadFile(loadavgFilename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvalues := strings.Fields(string(line))\n\treturn values, nil\n}\n"
  },
  {
    "path": "load/load_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage load\n\nimport (\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc getForkStat() (forkstat, error) {\n\tb, err := unix.SysctlRaw(\"kern.forkstat\")\n\tif err != nil {\n\t\treturn forkstat{}, err\n\t}\n\treturn *(*forkstat)(unsafe.Pointer((&b[0]))), nil\n}\n"
  },
  {
    "path": "load/load_solaris.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build solaris\n\npackage load\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc Avg() (*AvgStat, error) {\n\treturn AvgWithContext(context.Background())\n}\n\nfunc AvgWithContext(ctx context.Context) (*AvgStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"kstat\", \"-p\", \"unix:0:system_misc:avenrun_*\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tavg := &AvgStat{}\n\tscanner := bufio.NewScanner(bytes.NewReader(out))\n\tfor scanner.Scan() {\n\t\tflds := strings.Fields(scanner.Text())\n\t\tif len(flds) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tvar tgt *float64\n\t\tswitch {\n\t\tcase strings.HasSuffix(flds[0], \":avenrun_1min\"):\n\t\t\ttgt = &avg.Load1\n\t\tcase strings.HasSuffix(flds[0], \":avenrun_5min\"):\n\t\t\ttgt = &avg.Load5\n\t\tcase strings.HasSuffix(flds[0], \":avenrun_15min\"):\n\t\t\ttgt = &avg.Load15\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t\tv, err := strconv.ParseInt(flds[1], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t*tgt = float64(v) / (1 << 8)\n\t}\n\terr = scanner.Err()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn avg, nil\n}\n\nfunc Misc() (*MiscStat, error) {\n\treturn MiscWithContext(context.Background())\n}\n\nfunc MiscWithContext(ctx context.Context) (*MiscStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", \"-efo\", \"s\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\n\tret := MiscStat{}\n\tfor _, l := range lines {\n\t\tif l == \"O\" {\n\t\t\tret.ProcsRunning++\n\t\t}\n\t}\n\n\treturn &ret, nil\n}\n"
  },
  {
    "path": "load/load_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage load\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestAvg(t *testing.T) {\n\tv, err := Avg()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tempty := &AvgStat{}\n\tassert.NotSamef(t, v, empty, \"error load: %v\", v)\n\tt.Log(v)\n}\n\nfunc TestAvgStat_String(t *testing.T) {\n\tv := AvgStat{\n\t\tLoad1:  10.1,\n\t\tLoad5:  20.1,\n\t\tLoad15: 30.1,\n\t}\n\te := `{\"load1\":10.1,\"load5\":20.1,\"load15\":30.1}`\n\tassert.JSONEqf(t, e, v.String(), \"LoadAvgStat string is invalid: %v\", v)\n\tt.Log(e)\n}\n\nfunc TestMisc(t *testing.T) {\n\tv, err := Misc()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tempty := &MiscStat{}\n\tassert.NotSamef(t, v, empty, \"error load: %v\", v)\n\tt.Log(v)\n}\n\nfunc TestMiscStatString(t *testing.T) {\n\tv := MiscStat{\n\t\tProcsTotal:   4,\n\t\tProcsCreated: 5,\n\t\tProcsRunning: 1,\n\t\tProcsBlocked: 2,\n\t\tCtxt:         3,\n\t}\n\te := `{\"procsTotal\":4,\"procsCreated\":5,\"procsRunning\":1,\"procsBlocked\":2,\"ctxt\":3}`\n\tassert.JSONEqf(t, e, v.String(), \"TestMiscString string is invalid: %v\", v)\n\tt.Log(e)\n}\n\nfunc BenchmarkLoad(b *testing.B) {\n\tloadAvg := func(tb testing.TB) {\n\t\ttb.Helper()\n\t\tv, err := Avg()\n\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\ttb.Skip(\"not implemented\")\n\t\t}\n\t\trequire.NoErrorf(tb, err, \"error %v\", err)\n\t\tempty := &AvgStat{}\n\t\tassert.NotSamef(tb, v, empty, \"error load: %v\", v)\n\t}\n\n\tb.Run(\"FirstCall\", func(b *testing.B) {\n\t\tloadAvg(b)\n\t})\n\n\tb.Run(\"SubsequentCalls\", func(b *testing.B) {\n\t\tfor i := 0; i < b.N; i++ {\n\t\t\tloadAvg(b)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "load/load_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage load\n\nimport (\n\t\"context\"\n\t\"math\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar (\n\tloadErr              error\n\tloadAvg1M            = 0.0\n\tloadAvg5M            = 0.0\n\tloadAvg15M           = 0.0\n\tloadAvgMutex         sync.RWMutex\n\tloadAvgGoroutineOnce sync.Once\n)\n\n// loadAvgGoroutine updates avg data by fetching current load by interval\n// TODO instead of this goroutine, we can register a Win32 counter just as psutil does\n// see https://psutil.readthedocs.io/en/latest/#psutil.getloadavg\n// code https://github.com/giampaolo/psutil/blob/8415355c8badc9c94418b19bdf26e622f06f0cce/psutil/arch/windows/wmi.c\nfunc loadAvgGoroutine(ctx context.Context) {\n\tvar (\n\t\tsamplingFrequency = 5 * time.Second\n\t\tloadAvgFactor1M   = 1 / math.Exp(samplingFrequency.Seconds()/time.Minute.Seconds())\n\t\tloadAvgFactor5M   = 1 / math.Exp(samplingFrequency.Seconds()/(5*time.Minute).Seconds())\n\t\tloadAvgFactor15M  = 1 / math.Exp(samplingFrequency.Seconds()/(15*time.Minute).Seconds())\n\t\tcurrentLoad       float64\n\t)\n\n\tcounter, err := common.ProcessorQueueLengthCounter()\n\tif err != nil || counter == nil {\n\t\treturn\n\t}\n\n\ttick := time.NewTicker(samplingFrequency).C\n\n\tf := func() {\n\t\tcurrentLoad, err = counter.GetValue()\n\t\tloadAvgMutex.Lock()\n\t\tloadErr = err\n\t\tloadAvg1M = loadAvg1M*loadAvgFactor1M + currentLoad*(1-loadAvgFactor1M)\n\t\tloadAvg5M = loadAvg5M*loadAvgFactor5M + currentLoad*(1-loadAvgFactor5M)\n\t\tloadAvg15M = loadAvg15M*loadAvgFactor15M + currentLoad*(1-loadAvgFactor15M)\n\t\tloadAvgMutex.Unlock()\n\t}\n\n\tf() // run first time\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-tick:\n\t\t\tf()\n\t\t}\n\t}\n}\n\n// Avg for Windows may return 0 values for the first few 5 second intervals\nfunc Avg() (*AvgStat, error) {\n\treturn AvgWithContext(context.Background())\n}\n\nfunc AvgWithContext(ctx context.Context) (*AvgStat, error) {\n\tloadAvgGoroutineOnce.Do(func() {\n\t\tgo loadAvgGoroutine(ctx)\n\t})\n\tloadAvgMutex.RLock()\n\tdefer loadAvgMutex.RUnlock()\n\tret := AvgStat{\n\t\tLoad1:  loadAvg1M,\n\t\tLoad5:  loadAvg5M,\n\t\tLoad15: loadAvg15M,\n\t}\n\n\treturn &ret, loadErr\n}\n\nfunc Misc() (*MiscStat, error) {\n\treturn MiscWithContext(context.Background())\n}\n\nfunc MiscWithContext(_ context.Context) (*MiscStat, error) {\n\tret := MiscStat{}\n\n\treturn &ret, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "mem/ex_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n)\n\ntype ExVirtualMemory struct {\n\tActiveFile   uint64 `json:\"activefile\"`\n\tInactiveFile uint64 `json:\"inactivefile\"`\n\tActiveAnon   uint64 `json:\"activeanon\"`\n\tInactiveAnon uint64 `json:\"inactiveanon\"`\n\tUnevictable  uint64 `json:\"unevictable\"`\n\tPercpu       uint64 `json:\"percpu\"`\n\tKernelStack  uint64 `json:\"kernelstack\"`\n}\n\nfunc (v ExVirtualMemory) String() string {\n\ts, _ := json.Marshal(v)\n\treturn string(s)\n}\n\ntype ExLinux struct{}\n\nfunc NewExLinux() *ExLinux {\n\treturn &ExLinux{}\n}\n\nfunc (ex *ExLinux) VirtualMemory() (*ExVirtualMemory, error) {\n\treturn ex.VirtualMemoryWithContext(context.Background())\n}\n\nfunc (*ExLinux) VirtualMemoryWithContext(ctx context.Context) (*ExVirtualMemory, error) {\n\t_, vmEx, err := fillFromMeminfoWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn vmEx, nil\n}\n"
  },
  {
    "path": "mem/ex_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage mem\n\nimport (\n\t\"unsafe\"\n)\n\n// ExVirtualMemory represents Windows specific information\n// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex\n// https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-performance_information\ntype ExVirtualMemory struct {\n\tCommitLimit   uint64 `json:\"commitLimit\"`\n\tCommitTotal   uint64 `json:\"commitTotal\"`\n\tVirtualTotal  uint64 `json:\"virtualTotal\"`\n\tVirtualAvail  uint64 `json:\"virtualAvail\"`\n\tPhysTotal     uint64 `json:\"physTotal\"`\n\tPhysAvail     uint64 `json:\"physAvail\"`\n\tPageFileTotal uint64 `json:\"pageFileTotal\"`\n\tPageFileAvail uint64 `json:\"pageFileAvail\"`\n}\n\ntype ExWindows struct{}\n\nfunc NewExWindows() *ExWindows {\n\treturn &ExWindows{}\n}\n\nfunc (*ExWindows) VirtualMemory() (*ExVirtualMemory, error) {\n\tvar memInfo memoryStatusEx\n\tmemInfo.cbSize = uint32(unsafe.Sizeof(memInfo))\n\t// If mem == 0 since this is an error according to GlobalMemoryStatusEx documentation\n\t// In that case, use err which is constructed from GetLastError(),\n\t// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call\n\tmem, _, err := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))\n\tif mem == 0 {\n\t\treturn nil, err\n\t}\n\n\tvar perfInfo performanceInformation\n\tperfInfo.cb = uint32(unsafe.Sizeof(perfInfo))\n\t// Analogous to above: perf == 0 is an error according to the GetPerformanceInfo documentation,\n\t// use err in that case\n\tperf, _, err := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))\n\tif perf == 0 {\n\t\treturn nil, err\n\t}\n\n\tret := &ExVirtualMemory{\n\t\tCommitLimit:   perfInfo.commitLimit * perfInfo.pageSize,\n\t\tCommitTotal:   perfInfo.commitTotal * perfInfo.pageSize,\n\t\tVirtualTotal:  memInfo.ullTotalVirtual,\n\t\tVirtualAvail:  memInfo.ullAvailVirtual,\n\t\tPhysTotal:     memInfo.ullTotalPhys,\n\t\tPhysAvail:     memInfo.ullAvailPhys,\n\t\tPageFileTotal: memInfo.ullTotalPageFile,\n\t\tPageFileAvail: memInfo.ullAvailPageFile,\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "mem/mem.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage mem\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar invoke common.Invoker = common.Invoke{}\n\n// Memory usage statistics. Total, Available and Used contain numbers of bytes\n// for human consumption.\n//\n// The other fields in this struct contain kernel specific values.\ntype VirtualMemoryStat struct {\n\t// Total amount of RAM on this system\n\tTotal uint64 `json:\"total\"`\n\n\t// RAM available for programs to allocate\n\t//\n\t// This value is computed from the kernel specific values.\n\tAvailable uint64 `json:\"available\"`\n\n\t// RAM used by programs\n\t//\n\t// This value is computed from the kernel specific values.\n\tUsed uint64 `json:\"used\"`\n\n\t// Percentage of RAM used by programs\n\t//\n\t// This value is computed from the kernel specific values.\n\tUsedPercent float64 `json:\"usedPercent\"`\n\n\t// This is the kernel's notion of free memory; RAM chips whose bits nobody\n\t// cares about the value of right now. For a human consumable number,\n\t// Available is what you really want.\n\tFree uint64 `json:\"free\"`\n\n\t// OS X / BSD specific numbers:\n\t// http://www.macyourself.com/2010/02/17/what-is-free-wired-active-and-inactive-system-memory-ram/\n\tActive   uint64 `json:\"active\"`\n\tInactive uint64 `json:\"inactive\"`\n\tWired    uint64 `json:\"wired\"`\n\n\t// FreeBSD specific numbers:\n\t// https://reviews.freebsd.org/D8467\n\tLaundry uint64 `json:\"laundry\"`\n\n\t// Linux specific numbers\n\t// https://blogs.oracle.com/linux/understanding-linux-kernel-memory-statistics\n\t// https://www.kernel.org/doc/Documentation/filesystems/proc.txt\n\t// https://www.kernel.org/doc/Documentation/vm/overcommit-accounting\n\t// https://www.kernel.org/doc/Documentation/vm/transhuge.txt\n\t//\n\tBuffers        uint64 `json:\"buffers\"`\n\tCached         uint64 `json:\"cached\"`\n\tWriteBack      uint64 `json:\"writeBack\"`\n\tDirty          uint64 `json:\"dirty\"`\n\tWriteBackTmp   uint64 `json:\"writeBackTmp\"`\n\tShared         uint64 `json:\"shared\"`\n\tSlab           uint64 `json:\"slab\"`\n\tSreclaimable   uint64 `json:\"sreclaimable\"`\n\tSunreclaim     uint64 `json:\"sunreclaim\"`\n\tPageTables     uint64 `json:\"pageTables\"`\n\tSwapCached     uint64 `json:\"swapCached\"`\n\tCommitLimit    uint64 `json:\"commitLimit\"`\n\tCommittedAS    uint64 `json:\"committedAS\"`\n\tHighTotal      uint64 `json:\"highTotal\"`\n\tHighFree       uint64 `json:\"highFree\"`\n\tLowTotal       uint64 `json:\"lowTotal\"`\n\tLowFree        uint64 `json:\"lowFree\"`\n\tSwapTotal      uint64 `json:\"swapTotal\"`\n\tSwapFree       uint64 `json:\"swapFree\"`\n\tMapped         uint64 `json:\"mapped\"`\n\tVmallocTotal   uint64 `json:\"vmallocTotal\"`\n\tVmallocUsed    uint64 `json:\"vmallocUsed\"`\n\tVmallocChunk   uint64 `json:\"vmallocChunk\"`\n\tHugePagesTotal uint64 `json:\"hugePagesTotal\"`\n\tHugePagesFree  uint64 `json:\"hugePagesFree\"`\n\tHugePagesRsvd  uint64 `json:\"hugePagesRsvd\"`\n\tHugePagesSurp  uint64 `json:\"hugePagesSurp\"`\n\tHugePageSize   uint64 `json:\"hugePageSize\"`\n\tAnonHugePages  uint64 `json:\"anonHugePages\"`\n}\n\ntype SwapMemoryStat struct {\n\tTotal       uint64  `json:\"total\"`\n\tUsed        uint64  `json:\"used\"`\n\tFree        uint64  `json:\"free\"`\n\tUsedPercent float64 `json:\"usedPercent\"`\n\tSin         uint64  `json:\"sin\"`\n\tSout        uint64  `json:\"sout\"`\n\tPgIn        uint64  `json:\"pgIn\"`\n\tPgOut       uint64  `json:\"pgOut\"`\n\tPgFault     uint64  `json:\"pgFault\"`\n\n\t// Linux specific numbers\n\t// https://www.kernel.org/doc/Documentation/cgroup-v2.txt\n\tPgMajFault uint64 `json:\"pgMajFault\"`\n}\n\nfunc (m VirtualMemoryStat) String() string {\n\ts, _ := json.Marshal(m)\n\treturn string(s)\n}\n\nfunc (m SwapMemoryStat) String() string {\n\ts, _ := json.Marshal(m)\n\treturn string(s)\n}\n\ntype SwapDevice struct {\n\tName      string `json:\"name\"`\n\tUsedBytes uint64 `json:\"usedBytes\"`\n\tFreeBytes uint64 `json:\"freeBytes\"`\n}\n\nfunc (m SwapDevice) String() string {\n\ts, _ := json.Marshal(m)\n\treturn string(s)\n}\n"
  },
  {
    "path": "mem/mem_aix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage mem\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapDevices() ([]*SwapDevice, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "mem/mem_aix_cgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && cgo\n\npackage mem\n\nimport (\n\t\"context\"\n\n\t\"github.com/power-devops/perfstat\"\n)\n\nfunc VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {\n\tm, err := perfstat.MemoryTotalStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpagesize := uint64(4096)\n\tret := VirtualMemoryStat{\n\t\tTotal:       uint64(m.RealTotal) * pagesize,\n\t\tAvailable:   uint64(m.RealAvailable) * pagesize,\n\t\tFree:        uint64(m.RealFree) * pagesize,\n\t\tUsed:        uint64(m.RealInUse) * pagesize,\n\t\tUsedPercent: 100 * float64(m.RealInUse) / float64(m.RealTotal),\n\t\tActive:      uint64(m.VirtualActive) * pagesize,\n\t\tSwapTotal:   uint64(m.PgSpTotal) * pagesize,\n\t\tSwapFree:    uint64(m.PgSpFree) * pagesize,\n\t}\n\treturn &ret, nil\n}\n\nfunc SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {\n\tm, err := perfstat.MemoryTotalStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpagesize := uint64(4096)\n\tswapUsed := uint64(m.PgSpTotal-m.PgSpFree-m.PgSpRsvd) * pagesize\n\tswapTotal := uint64(m.PgSpTotal) * pagesize\n\tret := SwapMemoryStat{\n\t\tTotal:       swapTotal,\n\t\tFree:        uint64(m.PgSpFree) * pagesize,\n\t\tUsed:        swapUsed,\n\t\tUsedPercent: float64(100*swapUsed) / float64(swapTotal),\n\t\tSin:         uint64(m.PgSpIn),\n\t\tSout:        uint64(m.PgSpOut),\n\t\tPgIn:        uint64(m.PageIn),\n\t\tPgOut:       uint64(m.PageOut),\n\t\tPgFault:     uint64(m.PageFaults),\n\t}\n\treturn &ret, nil\n}\n"
  },
  {
    "path": "mem/mem_aix_nocgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && !cgo\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {\n\tvmem, swap, err := callSVMon(ctx, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif vmem.Total == 0 {\n\t\treturn nil, common.ErrNotImplementedError\n\t}\n\tvmem.SwapTotal = swap.Total\n\tvmem.SwapFree = swap.Free\n\treturn vmem, nil\n}\n\nfunc SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {\n\t_, swap, err := callSVMon(ctx, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif swap.Total == 0 {\n\t\treturn nil, common.ErrNotImplementedError\n\t}\n\treturn swap, nil\n}\n\nfunc callSVMon(ctx context.Context, virt bool) (*VirtualMemoryStat, *SwapMemoryStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"svmon\", \"-G\")\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tpagesize := uint64(4096)\n\tvmem := &VirtualMemoryStat{}\n\tswap := &SwapMemoryStat{}\n\tfor _, line := range strings.Split(string(out), \"\\n\") {\n\t\tif virt && strings.HasPrefix(line, \"memory\") {\n\t\t\tp := strings.Fields(line)\n\t\t\tif len(p) > 2 {\n\t\t\t\tif t, err := strconv.ParseUint(p[1], 10, 64); err == nil {\n\t\t\t\t\tvmem.Total = t * pagesize\n\t\t\t\t}\n\t\t\t\tif t, err := strconv.ParseUint(p[2], 10, 64); err == nil {\n\t\t\t\t\tvmem.Used = t * pagesize\n\t\t\t\t\tif vmem.Total > 0 {\n\t\t\t\t\t\tvmem.UsedPercent = 100 * float64(vmem.Used) / float64(vmem.Total)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif t, err := strconv.ParseUint(p[3], 10, 64); err == nil {\n\t\t\t\t\tvmem.Free = t * pagesize\n\t\t\t\t}\n\t\t\t}\n\t\t} else if strings.HasPrefix(line, \"pg space\") {\n\t\t\tp := strings.Fields(line)\n\t\t\tif len(p) > 3 {\n\t\t\t\tif t, err := strconv.ParseUint(p[2], 10, 64); err == nil {\n\t\t\t\t\tswap.Total = t * pagesize\n\t\t\t\t}\n\t\t\t\tif t, err := strconv.ParseUint(p[3], 10, 64); err == nil {\n\t\t\t\t\tswap.Free = swap.Total - t*pagesize\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\treturn vmem, swap, nil\n}\n"
  },
  {
    "path": "mem/mem_bsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd || openbsd || netbsd\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nconst swapCommand = \"swapctl\"\n\n// swapctl column indexes\nconst (\n\tnameCol     = 0\n\ttotalKiBCol = 1\n\tusedKiBCol  = 2\n)\n\nfunc SwapDevices() ([]*SwapDevice, error) {\n\treturn SwapDevicesWithContext(context.Background())\n}\n\nfunc SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {\n\toutput, err := invoke.CommandWithContext(ctx, swapCommand, \"-lk\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not execute %q: %w\", swapCommand, err)\n\t}\n\n\treturn parseSwapctlOutput(string(output))\n}\n\nfunc parseSwapctlOutput(output string) ([]*SwapDevice, error) {\n\tlines := strings.Split(output, \"\\n\")\n\tif len(lines) == 0 {\n\t\treturn nil, fmt.Errorf(\"could not parse output of %q: no lines in %q\", swapCommand, output)\n\t}\n\n\t// Check header headerFields are as expected.\n\theader := lines[0]\n\theader = strings.ToLower(header)\n\theader = strings.ReplaceAll(header, \":\", \"\")\n\theaderFields := strings.Fields(header)\n\tif len(headerFields) < usedKiBCol {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: too few fields in header %q\", swapCommand, header)\n\t}\n\tif headerFields[nameCol] != \"device\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapCommand, headerFields[nameCol], \"device\")\n\t}\n\tif headerFields[totalKiBCol] != \"1kb-blocks\" && headerFields[totalKiBCol] != \"1k-blocks\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapCommand, headerFields[totalKiBCol], \"1kb-blocks\")\n\t}\n\tif headerFields[usedKiBCol] != \"used\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapCommand, headerFields[usedKiBCol], \"used\")\n\t}\n\n\tvar swapDevices []*SwapDevice\n\tfor _, line := range lines[1:] {\n\t\tif line == \"\" {\n\t\t\tcontinue // the terminal line is typically empty\n\t\t}\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) < usedKiBCol {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse %q: too few fields\", swapCommand)\n\t\t}\n\n\t\ttotalKiB, err := strconv.ParseUint(fields[totalKiBCol], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse 'Size' column in %q: %w\", swapCommand, err)\n\t\t}\n\n\t\tusedKiB, err := strconv.ParseUint(fields[usedKiBCol], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse 'Used' column in %q: %w\", swapCommand, err)\n\t\t}\n\n\t\tswapDevices = append(swapDevices, &SwapDevice{\n\t\t\tName:      fields[nameCol],\n\t\t\tUsedBytes: usedKiB * 1024,\n\t\t\tFreeBytes: (totalKiB - usedKiB) * 1024,\n\t\t})\n\t}\n\n\treturn swapDevices, nil\n}\n"
  },
  {
    "path": "mem/mem_bsd_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd || openbsd\n\npackage mem\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst validFreeBSD = `Device:       1kB-blocks      Used:\n/dev/gpt/swapfs    1048576          1234\n/dev/md0         1048576          666\n`\n\nconst validOpenBSD = `Device       1K-blocks      Used\tAvail\tCapacity\tPriority\n/dev/wd0b    655025          1234\t653791\t1%\t0\n`\n\nconst invalid = `Device:       512-blocks      Used:\n/dev/gpt/swapfs    1048576          1234\n/dev/md0         1048576          666\n`\n\nfunc TestParseSwapctlOutput_FreeBSD(t *testing.T) {\n\tstats, err := parseSwapctlOutput(validFreeBSD)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, SwapDevice{\n\t\tName:      \"/dev/gpt/swapfs\",\n\t\tUsedBytes: 1263616,\n\t\tFreeBytes: 1072478208,\n\t}, *stats[0])\n\n\tassert.Equal(t, SwapDevice{\n\t\tName:      \"/dev/md0\",\n\t\tUsedBytes: 681984,\n\t\tFreeBytes: 1073059840,\n\t}, *stats[1])\n}\n\nfunc TestParseSwapctlOutput_OpenBSD(t *testing.T) {\n\tstats, err := parseSwapctlOutput(validOpenBSD)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, SwapDevice{\n\t\tName:      \"/dev/wd0b\",\n\t\tUsedBytes: 1234 * 1024,\n\t\tFreeBytes: 653791 * 1024,\n\t}, *stats[0])\n}\n\nfunc TestParseSwapctlOutput_Invalid(t *testing.T) {\n\t_, err := parseSwapctlOutput(invalid)\n\tassert.Error(t, err)\n}\n\nfunc TestParseSwapctlOutput_Empty(t *testing.T) {\n\t_, err := parseSwapctlOutput(\"\")\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "mem/mem_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc getHwMemsize() (uint64, error) {\n\ttotal, err := unix.SysctlUint64(\"hw.memsize\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn total, nil\n}\n\n// xsw_usage in sys/sysctl.h\ntype swapUsage struct {\n\tTotal     uint64\n\tAvail     uint64\n\tUsed      uint64\n\tPagesize  int32\n\tEncrypted bool\n}\n\n// SwapMemory returns swapinfo.\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {\n\t// https://github.com/yanllearnn/go-osstat/blob/ae8a279d26f52ec946a03698c7f50a26cfb427e3/memory/memory_darwin.go\n\tvar ret *SwapMemoryStat\n\n\tvalue, err := unix.SysctlRaw(\"vm.swapusage\")\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tif len(value) != 32 {\n\t\treturn ret, fmt.Errorf(\"unexpected output of sysctl vm.swapusage: %v (len: %d)\", value, len(value))\n\t}\n\tswap := (*swapUsage)(unsafe.Pointer(&value[0]))\n\n\tu := float64(0)\n\tif swap.Total != 0 {\n\t\tu = ((float64(swap.Total) - float64(swap.Avail)) / float64(swap.Total)) * 100.0\n\t}\n\n\tret = &SwapMemoryStat{\n\t\tTotal:       swap.Total,\n\t\tUsed:        swap.Used,\n\t\tFree:        swap.Avail,\n\t\tUsedPercent: u,\n\t}\n\n\treturn ret, nil\n}\n\nfunc SwapDevices() ([]*SwapDevice, error) {\n\treturn SwapDevicesWithContext(context.Background())\n}\n\nfunc SwapDevicesWithContext(_ context.Context) ([]*SwapDevice, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\ntype vmStatisticsData struct {\n\tfreeCount     uint32\n\tactiveCount   uint32\n\tinactiveCount uint32\n\twireCount     uint32\n\t_             [44]byte // Not used here\n}\n\n// VirtualMemory returns VirtualmemoryStat.\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {\n\tsys, err := common.NewSystemLib()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer sys.Close()\n\n\tcount := uint32(common.HOST_VM_INFO_COUNT)\n\tvar vmstat vmStatisticsData\n\n\tstatus := sys.HostStatistics(sys.MachHostSelf(), common.HOST_VM_INFO,\n\t\tuintptr(unsafe.Pointer(&vmstat)), &count)\n\n\tif status != common.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"host_statistics error=%d\", status)\n\t}\n\n\tpageSizeAddr, _ := sys.Dlsym(\"vm_kernel_page_size\")\n\tpageSize := **(**uint64)(unsafe.Pointer(&pageSizeAddr))\n\ttotal, err := getHwMemsize()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttotalCount := uint32(total / pageSize)\n\n\tavailableCount := vmstat.inactiveCount + vmstat.freeCount\n\tusedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount)\n\n\tusedCount := totalCount - availableCount\n\n\treturn &VirtualMemoryStat{\n\t\tTotal:       total,\n\t\tAvailable:   pageSize * uint64(availableCount),\n\t\tUsed:        pageSize * uint64(usedCount),\n\t\tUsedPercent: usedPercent,\n\t\tFree:        pageSize * uint64(vmstat.freeCount),\n\t\tActive:      pageSize * uint64(vmstat.activeCount),\n\t\tInactive:    pageSize * uint64(vmstat.inactiveCount),\n\t\tWired:       pageSize * uint64(vmstat.wireCount),\n\t}, nil\n}\n"
  },
  {
    "path": "mem/mem_darwin_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage mem\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestVirtualMemoryDarwin(t *testing.T) {\n\tv, err := VirtualMemory()\n\trequire.NoError(t, err)\n\n\toutBytes, err := invoke.Command(\"/usr/sbin/sysctl\", \"hw.memsize\")\n\trequire.NoError(t, err)\n\toutString := string(outBytes)\n\toutString = strings.TrimSpace(outString)\n\toutParts := strings.Split(outString, \" \")\n\tactualTotal, err := strconv.ParseInt(outParts[1], 10, 64)\n\trequire.NoError(t, err)\n\tassert.Equal(t, uint64(actualTotal), v.Total)\n\n\tassert.Positive(t, v.Available)\n\tassert.Equalf(t, v.Available, v.Free+v.Inactive, \"%v\", v)\n\n\tassert.Positive(t, v.Used)\n\tassert.Less(t, v.Used, v.Total)\n\n\tassert.Positive(t, v.UsedPercent)\n\tassert.Less(t, v.UsedPercent, 100.0)\n\n\tassert.Positive(t, v.Free)\n\tassert.Less(t, v.Free, v.Available)\n\n\tassert.Positive(t, v.Active)\n\tassert.Less(t, v.Active, v.Total)\n\n\tassert.Positive(t, v.Inactive)\n\tassert.Less(t, v.Inactive, v.Total)\n\n\tassert.Positive(t, v.Wired)\n\tassert.Less(t, v.Wired, v.Total)\n}\n"
  },
  {
    "path": "mem/mem_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !plan9 && !aix && !netbsd\n\npackage mem\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc SwapDevices() ([]*SwapDevice, error) {\n\treturn SwapDevicesWithContext(context.Background())\n}\n\nfunc SwapDevicesWithContext(_ context.Context) ([]*SwapDevice, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "mem/mem_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {\n\tpageSize, err := common.SysctlUint(\"vm.stats.vm.v_page_size\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tphysmem, err := common.SysctlUint(\"hw.physmem\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfree, err := common.SysctlUint(\"vm.stats.vm.v_free_count\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tactive, err := common.SysctlUint(\"vm.stats.vm.v_active_count\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tinactive, err := common.SysctlUint(\"vm.stats.vm.v_inactive_count\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuffers, err := common.SysctlUint(\"vfs.bufspace\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\twired, err := common.SysctlUint(\"vm.stats.vm.v_wire_count\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar cached, laundry uint64\n\tosreldate, _ := common.SysctlUint(\"kern.osreldate\")\n\tif osreldate < 1102000 {\n\t\tcached, err = common.SysctlUint(\"vm.stats.vm.v_cache_count\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tlaundry, err = common.SysctlUint(\"vm.stats.vm.v_laundry_count\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tp := pageSize\n\tret := &VirtualMemoryStat{\n\t\tTotal:    physmem,\n\t\tFree:     free * p,\n\t\tActive:   active * p,\n\t\tInactive: inactive * p,\n\t\tCached:   cached * p,\n\t\tBuffers:  buffers,\n\t\tWired:    wired * p,\n\t\tLaundry:  laundry * p,\n\t}\n\n\tret.Available = ret.Inactive + ret.Cached + ret.Free + ret.Laundry\n\tret.Used = ret.Total - ret.Available\n\tret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0\n\n\treturn ret, nil\n}\n\n// Return swapinfo\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\n// Constants from vm/vm_param.h\nconst (\n\tXSWDEV_VERSION11 = 1\n\tXSWDEV_VERSION   = 2\n)\n\n// Types from vm/vm_param.h\ntype xswdev struct {\n\tVersion uint32 // Version is the version\n\tDev     uint64 // Dev is the device identifier\n\tFlags   int32  // Flags is the swap flags applied to the device\n\tNBlks   int32  // NBlks is the total number of blocks\n\tUsed    int32  // Used is the number of blocks used\n}\n\n// xswdev11 is a compatibility for under FreeBSD 11\n// sys/vm/swap_pager.c\ntype xswdev11 struct {\n\tVersion uint32 // Version is the version\n\tDev     uint32 // Dev is the device identifier\n\tFlags   int32  // Flags is the swap flags applied to the device\n\tNBlks   int32  // NBlks is the total number of blocks\n\tUsed    int32  // Used is the number of blocks used\n}\n\nfunc SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {\n\t// FreeBSD can have multiple swap devices so we total them up\n\ti, err := common.SysctlUint(\"vm.nswapdev\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif i == 0 {\n\t\treturn nil, errors.New(\"no swap devices found\")\n\t}\n\n\tc := int(i)\n\n\ti, err = common.SysctlUint(\"vm.stats.vm.v_page_size\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpageSize := i\n\n\tvar buf []byte\n\ts := &SwapMemoryStat{}\n\tfor n := 0; n < c; n++ {\n\t\tbuf, err = unix.SysctlRaw(\"vm.swap_info\", n)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// first, try to parse with version 2\n\t\txsw := (*xswdev)(unsafe.Pointer(&buf[0]))\n\t\tswitch {\n\t\tcase xsw.Version == XSWDEV_VERSION11:\n\t\t\t// this is version 1, so try to parse again\n\t\t\txsw := (*xswdev11)(unsafe.Pointer(&buf[0]))\n\t\t\tif xsw.Version != XSWDEV_VERSION11 {\n\t\t\t\treturn nil, errors.New(\"xswdev version mismatch(11)\")\n\t\t\t}\n\t\t\ts.Total += uint64(xsw.NBlks)\n\t\t\ts.Used += uint64(xsw.Used)\n\t\tcase xsw.Version != XSWDEV_VERSION:\n\t\t\treturn nil, errors.New(\"xswdev version mismatch\")\n\t\tdefault:\n\t\t\ts.Total += uint64(xsw.NBlks)\n\t\t\ts.Used += uint64(xsw.Used)\n\t\t}\n\n\t}\n\n\tif s.Total != 0 {\n\t\ts.UsedPercent = float64(s.Used) / float64(s.Total) * 100\n\t}\n\ts.Total *= pageSize\n\ts.Used *= pageSize\n\ts.Free = s.Total - s.Used\n\n\treturn s, nil\n}\n"
  },
  {
    "path": "mem/mem_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage mem\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// WillBeDeletedOptOutMemAvailableCalc is a context key to opt out of calculating Mem.Used.\n// This is not documented, and will be removed in Mar. 2026. This constant will be removed\n// in the future, but it is currently public. The reason is that making it public allows\n// developers to notice its removal when their build fails.\n// See https://github.com/shirou/gopsutil/issues/1873\nconst WillBeDeletedOptOutMemAvailableCalc = \"optOutMemAvailableCalc\"\n\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {\n\tvm, _, err := fillFromMeminfoWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn vm, nil\n}\n\nfunc fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *ExVirtualMemory, error) {\n\tfilename := common.HostProcWithContext(ctx, \"meminfo\")\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"couldn't read %s: %w\", filename, err)\n\t}\n\n\t// flag if MemAvailable is in /proc/meminfo (kernel 3.14+)\n\tmemavail := false\n\tactiveFile := false   // \"Active(file)\" not available: 2.6.28 / Dec 2008\n\tinactiveFile := false // \"Inactive(file)\" not available: 2.6.28 / Dec 2008\n\tsReclaimable := false // \"Sreclaimable:\" not available: 2.6.19 / Nov 2006\n\n\tret := &VirtualMemoryStat{}\n\tretEx := &ExVirtualMemory{}\n\n\tfor _, line := range lines {\n\t\tfields := strings.Split(line, \":\")\n\t\tif len(fields) != 2 {\n\t\t\tcontinue\n\t\t}\n\t\tkey := strings.TrimSpace(fields[0])\n\t\tvalue := strings.TrimSpace(fields[1])\n\t\tvalue = strings.ReplaceAll(value, \" kB\", \"\")\n\n\t\tswitch key {\n\t\tcase \"MemTotal\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Total = t * 1024\n\t\tcase \"MemFree\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Free = t * 1024\n\t\tcase \"MemAvailable\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tmemavail = true\n\t\t\tret.Available = t * 1024\n\t\tcase \"Buffers\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Buffers = t * 1024\n\t\tcase \"Cached\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Cached = t * 1024\n\t\tcase \"Active\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Active = t * 1024\n\t\tcase \"Inactive\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Inactive = t * 1024\n\t\tcase \"Active(anon)\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tretEx.ActiveAnon = t * 1024\n\t\tcase \"Inactive(anon)\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tretEx.InactiveAnon = t * 1024\n\t\tcase \"Active(file)\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tactiveFile = true\n\t\t\tretEx.ActiveFile = t * 1024\n\t\tcase \"Inactive(file)\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tinactiveFile = true\n\t\t\tretEx.InactiveFile = t * 1024\n\t\tcase \"Unevictable\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tretEx.Unevictable = t * 1024\n\t\tcase \"Percpu\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tretEx.Percpu = t * 1024\n\t\tcase \"Writeback\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.WriteBack = t * 1024\n\t\tcase \"WritebackTmp\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.WriteBackTmp = t * 1024\n\t\tcase \"Dirty\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Dirty = t * 1024\n\t\tcase \"Shmem\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Shared = t * 1024\n\t\tcase \"Slab\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Slab = t * 1024\n\t\tcase \"SReclaimable\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tsReclaimable = true\n\t\t\tret.Sreclaimable = t * 1024\n\t\tcase \"SUnreclaim\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Sunreclaim = t * 1024\n\t\tcase \"KernelStack\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tretEx.KernelStack = t * 1024\n\t\tcase \"PageTables\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.PageTables = t * 1024\n\t\tcase \"SwapCached\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.SwapCached = t * 1024\n\t\tcase \"CommitLimit\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.CommitLimit = t * 1024\n\t\tcase \"Committed_AS\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.CommittedAS = t * 1024\n\t\tcase \"HighTotal\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.HighTotal = t * 1024\n\t\tcase \"HighFree\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.HighFree = t * 1024\n\t\tcase \"LowTotal\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.LowTotal = t * 1024\n\t\tcase \"LowFree\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.LowFree = t * 1024\n\t\tcase \"SwapTotal\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.SwapTotal = t * 1024\n\t\tcase \"SwapFree\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.SwapFree = t * 1024\n\t\tcase \"Mapped\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.Mapped = t * 1024\n\t\tcase \"VmallocTotal\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.VmallocTotal = t * 1024\n\t\tcase \"VmallocUsed\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.VmallocUsed = t * 1024\n\t\tcase \"VmallocChunk\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.VmallocChunk = t * 1024\n\t\tcase \"HugePages_Total\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.HugePagesTotal = t\n\t\tcase \"HugePages_Free\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.HugePagesFree = t\n\t\tcase \"HugePages_Rsvd\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.HugePagesRsvd = t\n\t\tcase \"HugePages_Surp\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.HugePagesSurp = t\n\t\tcase \"Hugepagesize\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.HugePageSize = t * 1024\n\t\tcase \"AnonHugePages\":\n\t\t\tt, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn ret, retEx, err\n\t\t\t}\n\t\t\tret.AnonHugePages = t * 1024\n\t\t}\n\t}\n\n\tret.Cached += ret.Sreclaimable\n\n\tif !memavail {\n\t\tif activeFile && inactiveFile && sReclaimable {\n\t\t\tret.Available = calculateAvailVmem(ctx, ret, retEx)\n\t\t} else {\n\t\t\tret.Available = ret.Cached + ret.Free\n\t\t}\n\t}\n\t// Opt-Out of calculating Mem.Used if the context has the context key set to true.\n\t// This is used for backward compatibility with applications that expect the old calculation method.\n\t// However, we plan to standardize on using MemAvailable in the future.\n\t// Therefore, please avoid using this opt-out unless it is absolutely necessary.\n\t// see https://github.com/shirou/gopsutil/issues/1873\n\tif val, ok := ctx.Value(WillBeDeletedOptOutMemAvailableCalc).(bool); ok && val {\n\t\tret.Used = ret.Total - ret.Free - ret.Buffers - ret.Cached\n\t} else {\n\t\tret.Used = ret.Total - ret.Available\n\t}\n\n\tret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0\n\n\treturn ret, retEx, nil\n}\n\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {\n\tsysinfo := &unix.Sysinfo_t{}\n\n\tif err := unix.Sysinfo(sysinfo); err != nil {\n\t\treturn nil, err\n\t}\n\tret := &SwapMemoryStat{\n\t\tTotal: uint64(sysinfo.Totalswap) * uint64(sysinfo.Unit),\n\t\tFree:  uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit),\n\t}\n\tret.Used = ret.Total - ret.Free\n\t// check Infinity\n\tif ret.Total != 0 {\n\t\tret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0\n\t} else {\n\t\tret.UsedPercent = 0\n\t}\n\tfilename := common.HostProcWithContext(ctx, \"vmstat\")\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"couldn't read %s: %w\", filename, err)\n\t}\n\tfor _, l := range lines {\n\t\tfields := strings.Fields(l)\n\t\tif len(fields) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tswitch fields[0] {\n\t\tcase \"pswpin\":\n\t\t\tvalue, err := strconv.ParseUint(fields[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret.Sin = value * 4 * 1024\n\t\tcase \"pswpout\":\n\t\t\tvalue, err := strconv.ParseUint(fields[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret.Sout = value * 4 * 1024\n\t\tcase \"pgpgin\":\n\t\t\tvalue, err := strconv.ParseUint(fields[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret.PgIn = value * 4 * 1024\n\t\tcase \"pgpgout\":\n\t\t\tvalue, err := strconv.ParseUint(fields[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret.PgOut = value * 4 * 1024\n\t\tcase \"pgfault\":\n\t\t\tvalue, err := strconv.ParseUint(fields[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret.PgFault = value * 4 * 1024\n\t\tcase \"pgmajfault\":\n\t\t\tvalue, err := strconv.ParseUint(fields[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret.PgMajFault = value * 4 * 1024\n\t\t}\n\t}\n\treturn ret, nil\n}\n\n// calculateAvailVmem is a fallback under kernel 3.14 where /proc/meminfo does not provide\n// \"MemAvailable:\" column. It reimplements an algorithm from the link below\n// https://github.com/giampaolo/psutil/pull/890\nfunc calculateAvailVmem(ctx context.Context, ret *VirtualMemoryStat, retEx *ExVirtualMemory) uint64 {\n\tvar watermarkLow uint64\n\n\tfn := common.HostProcWithContext(ctx, \"zoneinfo\")\n\tlines, err := common.ReadLines(fn)\n\tif err != nil {\n\t\treturn ret.Free + ret.Cached // fallback under kernel 2.6.13\n\t}\n\n\tpagesize := uint64(os.Getpagesize())\n\twatermarkLow = 0\n\n\tfor _, line := range lines {\n\t\tfields := strings.Fields(line)\n\n\t\tif strings.HasPrefix(fields[0], \"low\") {\n\t\t\tlowValue, err := strconv.ParseUint(fields[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tlowValue = 0\n\t\t\t}\n\t\t\twatermarkLow += lowValue\n\t\t}\n\t}\n\n\twatermarkLow *= pagesize\n\n\tavailMemory := ret.Free - watermarkLow\n\tpageCache := retEx.ActiveFile + retEx.InactiveFile\n\tpageCache -= uint64(math.Min(float64(pageCache/2), float64(watermarkLow)))\n\tavailMemory += pageCache\n\tavailMemory += ret.Sreclaimable - uint64(math.Min(float64(ret.Sreclaimable/2.0), float64(watermarkLow)))\n\n\tif availMemory < 0 {\n\t\tavailMemory = 0\n\t}\n\n\treturn availMemory\n}\n\nconst swapsFilename = \"swaps\"\n\n// swaps file column indexes\nconst (\n\tnameCol = 0\n\t// typeCol     = 1\n\ttotalCol = 2\n\tusedCol  = 3\n\t// priorityCol = 4\n)\n\nfunc SwapDevices() ([]*SwapDevice, error) {\n\treturn SwapDevicesWithContext(context.Background())\n}\n\nfunc SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {\n\tswapsFilePath := common.HostProcWithContext(ctx, swapsFilename)\n\tf, err := os.Open(swapsFilePath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\n\treturn parseSwapsFile(ctx, f)\n}\n\nfunc parseSwapsFile(ctx context.Context, r io.Reader) ([]*SwapDevice, error) {\n\tswapsFilePath := common.HostProcWithContext(ctx, swapsFilename)\n\tscanner := bufio.NewScanner(r)\n\tif !scanner.Scan() {\n\t\tif err := scanner.Err(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"couldn't read file %q: %w\", swapsFilePath, err)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"unexpected end-of-file in %q\", swapsFilePath)\n\n\t}\n\n\t// Check header headerFields are as expected\n\theaderFields := strings.Fields(scanner.Text())\n\tif len(headerFields) < usedCol {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: too few fields in header\", swapsFilePath)\n\t}\n\tif headerFields[nameCol] != \"Filename\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapsFilePath, headerFields[nameCol], \"Filename\")\n\t}\n\tif headerFields[totalCol] != \"Size\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapsFilePath, headerFields[totalCol], \"Size\")\n\t}\n\tif headerFields[usedCol] != \"Used\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapsFilePath, headerFields[usedCol], \"Used\")\n\t}\n\n\tvar swapDevices []*SwapDevice\n\tfor scanner.Scan() {\n\t\tfields := strings.Fields(scanner.Text())\n\t\tif len(fields) < usedCol {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse %q: too few fields\", swapsFilePath)\n\t\t}\n\n\t\ttotalKiB, err := strconv.ParseUint(fields[totalCol], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse 'Size' column in %q: %w\", swapsFilePath, err)\n\t\t}\n\n\t\tusedKiB, err := strconv.ParseUint(fields[usedCol], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse 'Used' column in %q: %w\", swapsFilePath, err)\n\t\t}\n\n\t\tswapDevices = append(swapDevices, &SwapDevice{\n\t\t\tName:      fields[nameCol],\n\t\t\tUsedBytes: usedKiB * 1024,\n\t\t\tFreeBytes: (totalKiB - usedKiB) * 1024,\n\t\t})\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"couldn't read file %q: %w\", swapsFilePath, err)\n\t}\n\n\treturn swapDevices, nil\n}\n"
  },
  {
    "path": "mem/mem_linux_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestExVirtualMemory(t *testing.T) {\n\tex := NewExLinux()\n\n\tv, err := ex.VirtualMemory()\n\trequire.NoError(t, err)\n\n\tt.Log(v)\n}\n\nvar virtualMemoryTests = []struct {\n\tmockedRootFS string\n\tstat         *VirtualMemoryStat\n\texStat       *ExVirtualMemory\n}{\n\t{\n\t\t\"intelcorei5\", &VirtualMemoryStat{\n\t\t\tTotal:          16502300672,\n\t\t\tAvailable:      11495358464,\n\t\t\tUsed:           5006942208,\n\t\t\tUsedPercent:    30.340873721295385,\n\t\t\tFree:           8783491072,\n\t\t\tActive:         4347392000,\n\t\t\tInactive:       2938834944,\n\t\t\tWired:          0,\n\t\t\tLaundry:        0,\n\t\t\tBuffers:        212496384,\n\t\t\tCached:         4069036032,\n\t\t\tWriteBack:      0,\n\t\t\tDirty:          176128,\n\t\t\tWriteBackTmp:   0,\n\t\t\tShared:         1222402048,\n\t\t\tSlab:           253771776,\n\t\t\tSreclaimable:   186470400,\n\t\t\tSunreclaim:     67301376,\n\t\t\tPageTables:     65241088,\n\t\t\tSwapCached:     0,\n\t\t\tCommitLimit:    16509730816,\n\t\t\tCommittedAS:    12360818688,\n\t\t\tHighTotal:      0,\n\t\t\tHighFree:       0,\n\t\t\tLowTotal:       0,\n\t\t\tLowFree:        0,\n\t\t\tSwapTotal:      8258580480,\n\t\t\tSwapFree:       8258580480,\n\t\t\tMapped:         1172627456,\n\t\t\tVmallocTotal:   35184372087808,\n\t\t\tVmallocUsed:    0,\n\t\t\tVmallocChunk:   0,\n\t\t\tHugePagesTotal: 0,\n\t\t\tHugePagesFree:  0,\n\t\t\tHugePagesRsvd:  0,\n\t\t\tHugePagesSurp:  0,\n\t\t\tHugePageSize:   2097152,\n\t\t},\n\t\t&ExVirtualMemory{\n\t\t\tActiveFile:   1121992 * 1024,\n\t\t\tInactiveFile: 1683344 * 1024,\n\t\t\tActiveAnon:   3123508 * 1024,\n\t\t\tInactiveAnon: 1186612 * 1024,\n\t\t\tUnevictable:  32 * 1024,\n\t\t\tPercpu:       19136 * 1024,\n\t\t\tKernelStack:  14224 * 1024,\n\t\t},\n\t},\n\t{\n\t\t\"issue1002\", &VirtualMemoryStat{\n\t\t\tTotal:          260579328,\n\t\t\tAvailable:      215199744,\n\t\t\tUsed:           45379584,\n\t\t\tUsedPercent:    17.414882580401773,\n\t\t\tFree:           124506112,\n\t\t\tActive:         108785664,\n\t\t\tInactive:       8581120,\n\t\t\tWired:          0,\n\t\t\tLaundry:        0,\n\t\t\tBuffers:        4915200,\n\t\t\tCached:         96829440,\n\t\t\tWriteBack:      0,\n\t\t\tDirty:          0,\n\t\t\tWriteBackTmp:   0,\n\t\t\tShared:         0,\n\t\t\tSlab:           9293824,\n\t\t\tSreclaimable:   2764800,\n\t\t\tSunreclaim:     6529024,\n\t\t\tPageTables:     405504,\n\t\t\tSwapCached:     0,\n\t\t\tCommitLimit:    130289664,\n\t\t\tCommittedAS:    25567232,\n\t\t\tHighTotal:      134217728,\n\t\t\tHighFree:       67784704,\n\t\t\tLowTotal:       126361600,\n\t\t\tLowFree:        56721408,\n\t\t\tSwapTotal:      0,\n\t\t\tSwapFree:       0,\n\t\t\tMapped:         38793216,\n\t\t\tVmallocTotal:   1996488704,\n\t\t\tVmallocUsed:    0,\n\t\t\tVmallocChunk:   0,\n\t\t\tHugePagesTotal: 0,\n\t\t\tHugePagesFree:  0,\n\t\t\tHugePagesRsvd:  0,\n\t\t\tHugePagesSurp:  0,\n\t\t\tHugePageSize:   0,\n\t\t},\n\t\t&ExVirtualMemory{\n\t\t\tActiveFile:   88280 * 1024,\n\t\t\tInactiveFile: 8380 * 1024,\n\t\t\tActiveAnon:   17956 * 1024,\n\t\t\tInactiveAnon: 0,\n\t\t\tUnevictable:  0,\n\t\t\tPercpu:       0,\n\t\t\tKernelStack:  624 * 1024,\n\t\t},\n\t},\n\t{\n\t\t\"anonhugepages\", &VirtualMemoryStat{\n\t\t\tTotal:         260799420 * 1024,\n\t\t\tAvailable:     127880216 * 1024,\n\t\t\tFree:          119443248 * 1024,\n\t\t\tAnonHugePages: 50409472 * 1024,\n\t\t\tUsed:          136109264896,\n\t\t\tUsedPercent:   50.96606579876596,\n\t\t},\n\t\t&ExVirtualMemory{\n\t\t\tActiveFile:   0,\n\t\t\tInactiveFile: 0,\n\t\t\tActiveAnon:   0,\n\t\t\tInactiveAnon: 0,\n\t\t\tUnevictable:  0,\n\t\t\tPercpu:       0,\n\t\t},\n\t},\n}\n\nfunc TestVirtualMemoryLinux(t *testing.T) {\n\tfor _, tt := range virtualMemoryTests {\n\t\tt.Run(tt.mockedRootFS, func(t *testing.T) {\n\t\t\tt.Setenv(\"HOST_PROC\", filepath.Join(\"testdata\", \"linux\", \"virtualmemory\", tt.mockedRootFS, \"proc\"))\n\n\t\t\tstat, err := VirtualMemory()\n\t\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\t\tt.Skip(\"not implemented\")\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Truef(t, reflect.DeepEqual(stat, tt.stat), \"got: %+v\\nwant: %+v\", stat, tt.stat)\n\t\t})\n\t}\n}\n\nfunc TestExVirtualMemoryLinux(t *testing.T) {\n\tfor _, tt := range virtualMemoryTests {\n\t\tt.Run(tt.mockedRootFS, func(t *testing.T) {\n\t\t\tt.Setenv(\"HOST_PROC\", filepath.Join(\"testdata\", \"linux\", \"virtualmemory\", tt.mockedRootFS, \"proc\"))\n\n\t\t\tex := NewExLinux()\n\t\t\texStat, err := ex.VirtualMemory()\n\t\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\t\tt.Skip(\"not implemented\")\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Truef(t, reflect.DeepEqual(exStat, tt.exStat), \"got: %+v\\nwant: %+v\", exStat, tt.exStat)\n\t\t})\n\t}\n}\n\nconst validFile = `Filename\t\t\t\tType\t\tSize\t\tUsed\t\tPriority\n/dev/dm-2                               partition\t67022844\t490788\t\t-2\n/swapfile                               file\t\t2\t\t1\t\t-3\n`\n\nconst invalidFile = `INVALID\t\t\t\tType\t\tSize\t\tUsed\t\tPriority\n/dev/dm-2                               partition\t67022844\t490788\t\t-2\n/swapfile                               file\t\t1048572\t\t0\t\t-3\n`\n\nfunc TestParseSwapsFile_ValidFile(t *testing.T) {\n\tstats, err := parseSwapsFile(context.Background(), strings.NewReader(validFile))\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, SwapDevice{\n\t\tName:      \"/dev/dm-2\",\n\t\tUsedBytes: 502566912,\n\t\tFreeBytes: 68128825344,\n\t}, *stats[0])\n\n\tassert.Equal(t, SwapDevice{\n\t\tName:      \"/swapfile\",\n\t\tUsedBytes: 1024,\n\t\tFreeBytes: 1024,\n\t}, *stats[1])\n}\n\nfunc TestParseSwapsFile_InvalidFile(t *testing.T) {\n\t_, err := parseSwapsFile(context.Background(), strings.NewReader(invalidFile))\n\tassert.Error(t, err)\n}\n\nfunc TestParseSwapsFile_EmptyFile(t *testing.T) {\n\t_, err := parseSwapsFile(context.Background(), strings.NewReader(\"\"))\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "mem/mem_netbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build netbsd\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc GetPageSize() (uint64, error) {\n\treturn GetPageSizeWithContext(context.Background())\n}\n\nfunc GetPageSizeWithContext(_ context.Context) (uint64, error) {\n\tuvmexp, err := unix.SysctlUvmexp(\"vm.uvmexp2\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(uvmexp.Pagesize), nil\n}\n\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {\n\tuvmexp, err := unix.SysctlUvmexp(\"vm.uvmexp2\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tp := uint64(uvmexp.Pagesize)\n\n\tret := &VirtualMemoryStat{\n\t\tTotal:    uint64(uvmexp.Npages) * p,\n\t\tFree:     uint64(uvmexp.Free) * p,\n\t\tActive:   uint64(uvmexp.Active) * p,\n\t\tInactive: uint64(uvmexp.Inactive) * p,\n\t\tCached:   0, // not available\n\t\tWired:    uint64(uvmexp.Wired) * p,\n\t}\n\n\tret.Available = ret.Inactive + ret.Cached + ret.Free\n\tret.Used = ret.Total - ret.Available\n\tret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0\n\n\t// Get buffers from vm.bufmem sysctl\n\tret.Buffers, err = unix.SysctlUint64(\"vm.bufmem\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ret, nil\n}\n\n// Return swapctl summary info\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"swapctl\", \"-sk\")\n\tif err != nil {\n\t\treturn &SwapMemoryStat{}, nil\n\t}\n\n\tline := string(out)\n\tvar total, used, free uint64\n\n\t_, err = fmt.Sscanf(line,\n\t\t\"total: %d 1K-blocks allocated, %d used, %d available\",\n\t\t&total, &used, &free)\n\tif err != nil {\n\t\treturn nil, errors.New(\"failed to parse swapctl output\")\n\t}\n\n\tpercent := float64(used) / float64(total) * 100\n\treturn &SwapMemoryStat{\n\t\tTotal:       total * 1024,\n\t\tUsed:        used * 1024,\n\t\tFree:        free * 1024,\n\t\tUsedPercent: percent,\n\t}, nil\n}\n"
  },
  {
    "path": "mem/mem_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage mem\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc GetPageSize() (uint64, error) {\n\treturn GetPageSizeWithContext(context.Background())\n}\n\nfunc GetPageSizeWithContext(_ context.Context) (uint64, error) {\n\tuvmexp, err := unix.SysctlUvmexp(\"vm.uvmexp\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn uint64(uvmexp.Pagesize), nil\n}\n\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {\n\tuvmexp, err := unix.SysctlUvmexp(\"vm.uvmexp\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tp := uint64(uvmexp.Pagesize)\n\n\tret := &VirtualMemoryStat{\n\t\tTotal:    uint64(uvmexp.Npages) * p,\n\t\tFree:     uint64(uvmexp.Free) * p,\n\t\tActive:   uint64(uvmexp.Active) * p,\n\t\tInactive: uint64(uvmexp.Inactive) * p,\n\t\tCached:   0, // not available\n\t\tWired:    uint64(uvmexp.Wired) * p,\n\t}\n\n\tret.Available = ret.Inactive + ret.Cached + ret.Free\n\tret.Used = ret.Total - ret.Available\n\tret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0\n\n\tmib := []int32{CTLVfs, VfsGeneric, VfsBcacheStat}\n\tbuf, length, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif length < sizeOfBcachestats {\n\t\treturn nil, fmt.Errorf(\"short syscall ret %d bytes\", length)\n\t}\n\tvar bcs Bcachestats\n\tbr := bytes.NewReader(buf)\n\tif err := binary.Read(br, binary.LittleEndian, &bcs); err != nil {\n\t\treturn nil, err\n\t}\n\tret.Buffers = uint64(bcs.Numbufpages) * p\n\n\treturn ret, nil\n}\n\n// Return swapctl summary info\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"swapctl\", \"-sk\")\n\tif err != nil {\n\t\treturn &SwapMemoryStat{}, nil\n\t}\n\n\tline := string(out)\n\tvar total, used, free uint64\n\n\t_, err = fmt.Sscanf(line,\n\t\t\"total: %d 1K-blocks allocated, %d used, %d available\",\n\t\t&total, &used, &free)\n\tif err != nil {\n\t\treturn nil, errors.New(\"failed to parse swapctl output\")\n\t}\n\n\tpercent := float64(used) / float64(total) * 100\n\treturn &SwapMemoryStat{\n\t\tTotal:       total * 1024,\n\t\tUsed:        used * 1024,\n\t\tFree:        free * 1024,\n\t\tUsedPercent: percent,\n\t}, nil\n}\n"
  },
  {
    "path": "mem/mem_openbsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && 386\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs mem/types_openbsd.go\n\npackage mem\n\nconst (\n\tCTLVfs        = 10\n\tVfsGeneric    = 0\n\tVfsBcacheStat = 3\n)\n\nconst (\n\tsizeOfBcachestats = 0x90\n)\n\ntype Bcachestats struct {\n\tNumbufs       int64\n\tNumbufpages   int64\n\tNumdirtypages int64\n\tNumcleanpages int64\n\tPendingwrites int64\n\tPendingreads  int64\n\tNumwrites     int64\n\tNumreads      int64\n\tCachehits     int64\n\tBusymapped    int64\n\tDmapages      int64\n\tHighpages     int64\n\tDelwribufs    int64\n\tKvaslots      int64\n\tAvail         int64\n\tHighflips     int64\n\tHighflops     int64\n\tDmaflips      int64\n}\n"
  },
  {
    "path": "mem/mem_openbsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_openbsd.go\n\npackage mem\n\nconst (\n\tCTLVfs        = 10\n\tVfsGeneric    = 0\n\tVfsBcacheStat = 3\n)\n\nconst (\n\tsizeOfBcachestats = 0x78\n)\n\ntype Bcachestats struct {\n\tNumbufs       int64\n\tNumbufpages   int64\n\tNumdirtypages int64\n\tNumcleanpages int64\n\tPendingwrites int64\n\tPendingreads  int64\n\tNumwrites     int64\n\tNumreads      int64\n\tCachehits     int64\n\tBusymapped    int64\n\tDmapages      int64\n\tHighpages     int64\n\tDelwribufs    int64\n\tKvaslots      int64\n\tAvail         int64\n}\n"
  },
  {
    "path": "mem/mem_openbsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && arm\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs mem/types_openbsd.go\n\npackage mem\n\nconst (\n\tCTLVfs        = 10\n\tVfsGeneric    = 0\n\tVfsBcacheStat = 3\n)\n\nconst (\n\tsizeOfBcachestats = 0x90\n)\n\ntype Bcachestats struct {\n\tNumbufs       int64\n\tNumbufpages   int64\n\tNumdirtypages int64\n\tNumcleanpages int64\n\tPendingwrites int64\n\tPendingreads  int64\n\tNumwrites     int64\n\tNumreads      int64\n\tCachehits     int64\n\tBusymapped    int64\n\tDmapages      int64\n\tHighpages     int64\n\tDelwribufs    int64\n\tKvaslots      int64\n\tAvail         int64\n\tHighflips     int64\n\tHighflops     int64\n\tDmaflips      int64\n}\n"
  },
  {
    "path": "mem/mem_openbsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs mem/types_openbsd.go\n\npackage mem\n\nconst (\n\tCTLVfs        = 10\n\tVfsGeneric    = 0\n\tVfsBcacheStat = 3\n)\n\nconst (\n\tsizeOfBcachestats = 0x90\n)\n\ntype Bcachestats struct {\n\tNumbufs       int64\n\tNumbufpages   int64\n\tNumdirtypages int64\n\tNumcleanpages int64\n\tPendingwrites int64\n\tPendingreads  int64\n\tNumwrites     int64\n\tNumreads      int64\n\tCachehits     int64\n\tBusymapped    int64\n\tDmapages      int64\n\tHighpages     int64\n\tDelwribufs    int64\n\tKvaslots      int64\n\tAvail         int64\n\tHighflips     int64\n\tHighflops     int64\n\tDmaflips      int64\n}\n"
  },
  {
    "path": "mem/mem_openbsd_riscv64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && riscv64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs mem/types_openbsd.go\n\npackage mem\n\nconst (\n\tCTLVfs        = 10\n\tVfsGeneric    = 0\n\tVfsBcacheStat = 3\n)\n\nconst (\n\tsizeOfBcachestats = 0x90\n)\n\ntype Bcachestats struct {\n\tNumbufs       int64\n\tNumbufpages   int64\n\tNumdirtypages int64\n\tNumcleanpages int64\n\tPendingwrites int64\n\tPendingreads  int64\n\tNumwrites     int64\n\tNumreads      int64\n\tCachehits     int64\n\tBusymapped    int64\n\tDmapages      int64\n\tHighpages     int64\n\tDelwribufs    int64\n\tKvaslots      int64\n\tAvail         int64\n\tHighflips     int64\n\tHighflops     int64\n\tDmaflips      int64\n}\n"
  },
  {
    "path": "mem/mem_plan9.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build plan9\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\tstats \"github.com/lufia/plan9stats\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {\n\troot := os.Getenv(\"HOST_ROOT\")\n\tm, err := stats.ReadMemStats(ctx, stats.WithRootDir(root))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tu := 0.0\n\tif m.SwapPages.Avail != 0 {\n\t\tu = float64(m.SwapPages.Used) / float64(m.SwapPages.Avail) * 100.0\n\t}\n\treturn &SwapMemoryStat{\n\t\tTotal:       uint64(m.SwapPages.Avail * m.PageSize),\n\t\tUsed:        uint64(m.SwapPages.Used * m.PageSize),\n\t\tFree:        uint64(m.SwapPages.Free() * m.PageSize),\n\t\tUsedPercent: u,\n\t}, nil\n}\n\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {\n\troot := os.Getenv(\"HOST_ROOT\")\n\tm, err := stats.ReadMemStats(ctx, stats.WithRootDir(root))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tu := 0.0\n\tif m.UserPages.Avail != 0 {\n\t\tu = float64(m.UserPages.Used) / float64(m.UserPages.Avail) * 100.0\n\t}\n\treturn &VirtualMemoryStat{\n\t\tTotal:       uint64(m.Total),\n\t\tAvailable:   uint64(m.UserPages.Free() * m.PageSize),\n\t\tUsed:        uint64(m.UserPages.Used * m.PageSize),\n\t\tUsedPercent: u,\n\t\tFree:        uint64(m.UserPages.Free() * m.PageSize),\n\n\t\tSwapTotal: uint64(m.SwapPages.Avail * m.PageSize),\n\t\tSwapFree:  uint64(m.SwapPages.Free() * m.PageSize),\n\t}, nil\n}\n\nfunc SwapDevices() ([]*SwapDevice, error) {\n\treturn SwapDevicesWithContext(context.Background())\n}\n\nfunc SwapDevicesWithContext(_ context.Context) ([]*SwapDevice, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "mem/mem_plan9_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build plan9\n\npackage mem\n\nimport (\n\t\"errors\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar virtualMemoryTests = []struct {\n\tmockedRootFS string\n\tstat         *VirtualMemoryStat\n}{\n\t{\n\t\t\"swap\", &VirtualMemoryStat{\n\t\t\tTotal:       1071185920,\n\t\t\tAvailable:   808370176,\n\t\t\tUsed:        11436032,\n\t\t\tUsedPercent: 1.3949677238843257,\n\t\t\tFree:        808370176,\n\t\t\tSwapTotal:   655360000,\n\t\t\tSwapFree:    655360000,\n\t\t},\n\t},\n}\n\nfunc TestVirtualMemoryPlan9(t *testing.T) {\n\tfor _, tt := range virtualMemoryTests {\n\t\tt.Run(tt.mockedRootFS, func(t *testing.T) {\n\t\t\tt.Setenv(\"HOST_ROOT\", \"testdata/plan9/virtualmemory/\")\n\n\t\t\tstat, err := VirtualMemory()\n\t\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\t\tt.Skip(\"not implemented\")\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Truef(t, reflect.DeepEqual(stat, tt.stat), \"got: %+v\\nwant: %+v\", stat, tt.stat)\n\t\t})\n\t}\n}\n\nvar swapMemoryTests = []struct {\n\tmockedRootFS string\n\tswap         *SwapMemoryStat\n}{\n\t{\n\t\t\"swap\", &SwapMemoryStat{\n\t\t\tTotal: 655360000,\n\t\t\tUsed:  0,\n\t\t\tFree:  655360000,\n\t\t},\n\t},\n}\n\nfunc TestSwapMemoryPlan9(t *testing.T) {\n\tfor _, tt := range swapMemoryTests {\n\t\tt.Run(tt.mockedRootFS, func(t *testing.T) {\n\t\t\tt.Setenv(\"HOST_ROOT\", \"testdata/plan9/virtualmemory/\")\n\n\t\t\tswap, err := SwapMemory()\n\t\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\t\tt.Skip(\"not implemented\")\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Truef(t, reflect.DeepEqual(swap, tt.swap), \"got: %+v\\nwant: %+v\", swap, tt.swap)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "mem/mem_solaris.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build solaris\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/tklauser/go-sysconf\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// VirtualMemory for Solaris is a minimal implementation which only returns\n// what Nomad needs. It does take into account global vs zone, however.\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {\n\tresult := &VirtualMemoryStat{}\n\n\tzoneName, err := zoneName(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif zoneName == \"global\" {\n\t\tcapacity, err := globalZoneMemoryCapacity(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult.Total = capacity\n\t\tfreemem, err := globalZoneFreeMemory(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult.Available = freemem\n\t\tresult.Free = freemem\n\t\tresult.Used = result.Total - result.Free\n\t} else {\n\t\tcapacity, err := nonGlobalZoneMemoryCapacity(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult.Total = capacity\n\t}\n\n\treturn result, nil\n}\n\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc zoneName(ctx context.Context) (string, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"zonename\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn strings.TrimSpace(string(out)), nil\n}\n\nvar globalZoneMemoryCapacityMatch = regexp.MustCompile(`[Mm]emory size: (\\d+) Megabytes`)\n\nfunc globalZoneMemoryCapacity(ctx context.Context) (uint64, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"prtconf\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tmatch := globalZoneMemoryCapacityMatch.FindAllStringSubmatch(string(out), -1)\n\tif len(match) != 1 {\n\t\treturn 0, errors.New(\"memory size not contained in output of prtconf\")\n\t}\n\n\ttotalMB, err := strconv.ParseUint(match[0][1], 10, 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn totalMB * 1024 * 1024, nil\n}\n\nfunc globalZoneFreeMemory(ctx context.Context) (uint64, error) {\n\toutput, err := invoke.CommandWithContext(ctx, \"pagesize\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tpagesize, err := strconv.ParseUint(strings.TrimSpace(string(output)), 10, 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tfree, err := sysconf.Sysconf(sysconf.SC_AVPHYS_PAGES)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn uint64(free) * pagesize, nil\n}\n\nvar kstatMatch = regexp.MustCompile(`(\\S+)\\s+(\\S*)`)\n\nfunc nonGlobalZoneMemoryCapacity(ctx context.Context) (uint64, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"kstat\", \"-p\", \"-c\", \"zone_memory_cap\", \"memory_cap:*:*:physcap\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tkstats := kstatMatch.FindAllStringSubmatch(string(out), -1)\n\tif len(kstats) != 1 {\n\t\treturn 0, fmt.Errorf(\"expected 1 kstat, found %d\", len(kstats))\n\t}\n\n\tmemSizeBytes, err := strconv.ParseUint(kstats[0][2], 10, 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn memSizeBytes, nil\n}\n\nconst swapCommand = \"swap\"\n\n// The blockSize as reported by `swap -l`. See https://docs.oracle.com/cd/E23824_01/html/821-1459/fsswap-52195.html\nconst blockSize = 512\n\n// swapctl column indexes\nconst (\n\tnameCol = 0\n\t// devCol = 1\n\t// swaploCol = 2\n\ttotalBlocksCol = 3\n\tfreeBlocksCol  = 4\n)\n\nfunc SwapDevices() ([]*SwapDevice, error) {\n\treturn SwapDevicesWithContext(context.Background())\n}\n\nfunc SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {\n\toutput, err := invoke.CommandWithContext(ctx, swapCommand, \"-l\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not execute %q: %w\", swapCommand, err)\n\t}\n\n\treturn parseSwapsCommandOutput(string(output))\n}\n\nfunc parseSwapsCommandOutput(output string) ([]*SwapDevice, error) {\n\tlines := strings.Split(output, \"\\n\")\n\tif len(lines) == 0 {\n\t\treturn nil, fmt.Errorf(\"could not parse output of %q: no lines in %q\", swapCommand, output)\n\t}\n\n\t// Check header headerFields are as expected.\n\theaderFields := strings.Fields(lines[0])\n\tif len(headerFields) < freeBlocksCol {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: too few fields in header %q\", swapCommand, lines[0])\n\t}\n\tif headerFields[nameCol] != \"swapfile\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapCommand, headerFields[nameCol], \"swapfile\")\n\t}\n\tif headerFields[totalBlocksCol] != \"blocks\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapCommand, headerFields[totalBlocksCol], \"blocks\")\n\t}\n\tif headerFields[freeBlocksCol] != \"free\" {\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q: expected %q to be %q\", swapCommand, headerFields[freeBlocksCol], \"free\")\n\t}\n\n\tvar swapDevices []*SwapDevice\n\tfor _, line := range lines[1:] {\n\t\tif line == \"\" {\n\t\t\tcontinue // the terminal line is typically empty\n\t\t}\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) < freeBlocksCol {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse %q: too few fields\", swapCommand)\n\t\t}\n\n\t\ttotalBlocks, err := strconv.ParseUint(fields[totalBlocksCol], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse 'Size' column in %q: %w\", swapCommand, err)\n\t\t}\n\n\t\tfreeBlocks, err := strconv.ParseUint(fields[freeBlocksCol], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"couldn't parse 'Used' column in %q: %w\", swapCommand, err)\n\t\t}\n\n\t\tswapDevices = append(swapDevices, &SwapDevice{\n\t\t\tName:      fields[nameCol],\n\t\t\tUsedBytes: (totalBlocks - freeBlocks) * blockSize,\n\t\t\tFreeBytes: freeBlocks * blockSize,\n\t\t})\n\t}\n\n\treturn swapDevices, nil\n}\n"
  },
  {
    "path": "mem/mem_solaris_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build solaris\n\npackage mem\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst validFile = `swapfile                  dev  swaplo blocks   free\n/dev/zvol/dsk/rpool/swap 256,1      16 1058800 1058800\n/dev/dsk/c0t0d0s1   136,1      16 1638608 1600528`\n\nconst invalidFile = `swapfile                  dev  swaplo INVALID   free\n/dev/zvol/dsk/rpool/swap 256,1      16 1058800 1058800\n/dev/dsk/c0t0d0s1   136,1      16 1638608 1600528`\n\nfunc TestParseSwapsCommandOutput_Valid(t *testing.T) {\n\tstats, err := parseSwapsCommandOutput(validFile)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, SwapDevice{\n\t\tName:      \"/dev/zvol/dsk/rpool/swap\",\n\t\tUsedBytes: 0,\n\t\tFreeBytes: 1058800 * 512,\n\t}, *stats[0])\n\n\tassert.Equal(t, SwapDevice{\n\t\tName:      \"/dev/dsk/c0t0d0s1\",\n\t\tUsedBytes: 38080 * 512,\n\t\tFreeBytes: 1600528 * 512,\n\t}, *stats[1])\n}\n\nfunc TestParseSwapsCommandOutput_Invalid(t *testing.T) {\n\t_, err := parseSwapsCommandOutput(invalidFile)\n\tassert.Error(t, err)\n}\n\nfunc TestParseSwapsCommandOutput_Empty(t *testing.T) {\n\t_, err := parseSwapsCommandOutput(\"\")\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "mem/mem_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage mem\n\nimport (\n\t\"errors\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestVirtualMemory(t *testing.T) {\n\tif runtime.GOOS == \"solaris\" || runtime.GOOS == \"illumos\" {\n\t\tt.Skip(\"Only .Total .Available are supported on Solaris/illumos\")\n\t}\n\n\tv, err := VirtualMemory()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tempty := &VirtualMemoryStat{}\n\tassert.NotSamef(t, v, empty, \"error %v\", v)\n\tt.Log(v)\n\n\tassert.Positive(t, v.Total)\n\tassert.Positive(t, v.Available)\n\tassert.Positive(t, v.Used)\n\n\ttotal := v.Used + v.Free + v.Buffers + v.Cached\n\ttotalStr := \"used + free + buffers + cached\"\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\ttotal = v.Used + v.Available\n\t\ttotalStr = \"used + available\"\n\tcase \"darwin\", \"openbsd\":\n\t\ttotal = v.Used + v.Free + v.Cached + v.Inactive\n\t\ttotalStr = \"used + free + cached + inactive\"\n\tcase \"freebsd\":\n\t\ttotal = v.Used + v.Free + v.Cached + v.Inactive + v.Laundry\n\t\ttotalStr = \"used + free + cached + inactive + laundry\"\n\tcase \"linux\":\n\t\ttotal = v.Available + v.Used\n\t\ttotalStr = \"used + available\"\n\t}\n\tassert.Equalf(t, v.Total, total,\n\t\t\"Total should be computable (%v): %v\", totalStr, v)\n\n\tassert.True(t, runtime.GOOS == \"windows\" || v.Free > 0)\n\tassert.Truef(t, runtime.GOOS == \"windows\" || v.Available > v.Free,\n\t\t\"Free should be a subset of Available: %v\", v)\n\n\tinDelta := assert.InDelta\n\tif runtime.GOOS == \"windows\" {\n\t\tinDelta = assert.InEpsilon\n\t}\n\tinDelta(t, v.UsedPercent,\n\t\t100*float64(v.Used)/float64(v.Total), 0.1,\n\t\t\"UsedPercent should be how many percent of Total is Used: %v\", v)\n}\n\nfunc TestSwapMemory(t *testing.T) {\n\tv, err := SwapMemory()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tempty := &SwapMemoryStat{}\n\tassert.NotSamef(t, v, empty, \"error %v\", v)\n\n\tt.Log(v)\n}\n\nfunc TestVirtualMemoryStat_String(t *testing.T) {\n\tv := VirtualMemoryStat{\n\t\tTotal:       10,\n\t\tAvailable:   20,\n\t\tUsed:        30,\n\t\tUsedPercent: 30.1,\n\t\tFree:        40,\n\t}\n\tt.Log(v)\n\te := `{\"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}`\n\tassert.JSONEqf(t, e, v.String(), \"VirtualMemoryStat string is invalid: %v\", v)\n}\n\nfunc TestSwapMemoryStat_String(t *testing.T) {\n\tv := SwapMemoryStat{\n\t\tTotal:       10,\n\t\tUsed:        30,\n\t\tFree:        40,\n\t\tUsedPercent: 30.1,\n\t\tSin:         1,\n\t\tSout:        2,\n\t\tPgIn:        3,\n\t\tPgOut:       4,\n\t\tPgFault:     5,\n\t\tPgMajFault:  6,\n\t}\n\te := `{\"total\":10,\"used\":30,\"free\":40,\"usedPercent\":30.1,\"sin\":1,\"sout\":2,\"pgIn\":3,\"pgOut\":4,\"pgFault\":5,\"pgMajFault\":6}`\n\tassert.JSONEqf(t, e, v.String(), \"SwapMemoryStat string is invalid: %v\", v)\n}\n\nfunc TestSwapDevices(t *testing.T) {\n\tv, err := SwapDevices()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"error calling SwapDevices: %v\", err)\n\n\tt.Logf(\"SwapDevices() -> %+v\", v)\n\n\trequire.NotEmptyf(t, v, \"no swap devices found. [this is expected if the host has swap disabled]\")\n\n\tfor _, device := range v {\n\t\trequire.NotEmptyf(t, device.Name, \"deviceName not set in %+v\", device)\n\t\tif device.FreeBytes == 0 {\n\t\t\tt.Logf(\"[WARNING] free-bytes is zero in %+v. This might be expected\", device)\n\t\t}\n\t\tif device.UsedBytes == 0 {\n\t\t\tt.Logf(\"[WARNING] used-bytes is zero in %+v. This might be expected\", device)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "mem/mem_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage mem\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar (\n\tprocEnumPageFilesW       = common.ModPsapi.NewProc(\"EnumPageFilesW\")\n\tprocGetNativeSystemInfo  = common.Modkernel32.NewProc(\"GetNativeSystemInfo\")\n\tprocGetPerformanceInfo   = common.ModPsapi.NewProc(\"GetPerformanceInfo\")\n\tprocGlobalMemoryStatusEx = common.Modkernel32.NewProc(\"GlobalMemoryStatusEx\")\n)\n\ntype memoryStatusEx struct {\n\tcbSize                  uint32\n\tdwMemoryLoad            uint32\n\tullTotalPhys            uint64 // in bytes\n\tullAvailPhys            uint64\n\tullTotalPageFile        uint64\n\tullAvailPageFile        uint64\n\tullTotalVirtual         uint64\n\tullAvailVirtual         uint64\n\tullAvailExtendedVirtual uint64\n}\n\nfunc VirtualMemory() (*VirtualMemoryStat, error) {\n\treturn VirtualMemoryWithContext(context.Background())\n}\n\nfunc VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {\n\tvar memInfo memoryStatusEx\n\tmemInfo.cbSize = uint32(unsafe.Sizeof(memInfo))\n\t// GlobalMemoryStatusEx returns 0 for error, in which case we check err,\n\t// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call\n\tmem, _, err := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))\n\tif mem == 0 {\n\t\treturn nil, err\n\t}\n\n\tret := &VirtualMemoryStat{\n\t\tTotal:       memInfo.ullTotalPhys,\n\t\tAvailable:   memInfo.ullAvailPhys,\n\t\tFree:        memInfo.ullAvailPhys,\n\t\tUsedPercent: float64(memInfo.dwMemoryLoad),\n\t}\n\n\tret.Used = ret.Total - ret.Available\n\treturn ret, nil\n}\n\ntype performanceInformation struct {\n\tcb                uint32\n\tcommitTotal       uint64\n\tcommitLimit       uint64\n\tcommitPeak        uint64\n\tphysicalTotal     uint64\n\tphysicalAvailable uint64\n\tsystemCache       uint64\n\tkernelTotal       uint64\n\tkernelPaged       uint64\n\tkernelNonpaged    uint64\n\tpageSize          uint64\n\thandleCount       uint32\n\tprocessCount      uint32\n\tthreadCount       uint32\n}\n\nfunc SwapMemory() (*SwapMemoryStat, error) {\n\treturn SwapMemoryWithContext(context.Background())\n}\n\nfunc SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {\n\t// Use the performance counter to get the swap usage percentage\n\tcounter, err := common.NewWin32PerformanceCounter(\"swap_percentage\", `\\Paging File(_Total)\\% Usage`)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer common.PdhCloseQuery.Call(uintptr(counter.Query))\n\n\tusedPercent, err := counter.GetValue()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Get total memory from performance information\n\tvar perfInfo performanceInformation\n\tperfInfo.cb = uint32(unsafe.Sizeof(perfInfo))\n\t// GetPerformanceInfo returns 0 for error, in which case we check err,\n\t// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call\n\tmem, _, err := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))\n\tif mem == 0 {\n\t\treturn nil, err\n\t}\n\ttotalPhys := perfInfo.physicalTotal * perfInfo.pageSize\n\ttotalSys := perfInfo.commitLimit * perfInfo.pageSize\n\ttotal := totalSys - totalPhys\n\n\tvar used uint64\n\tif total > 0 {\n\t\tused = uint64(0.01 * usedPercent * float64(total))\n\t} else {\n\t\tusedPercent = 0.0\n\t\tused = 0\n\t}\n\n\tret := &SwapMemoryStat{\n\t\tTotal:       total,\n\t\tUsed:        used,\n\t\tFree:        total - used,\n\t\tUsedPercent: common.Round(usedPercent, 1),\n\t}\n\n\treturn ret, nil\n}\n\nvar (\n\tpageSize     uint64\n\tpageSizeOnce sync.Once\n)\n\ntype systemInfo struct {\n\twProcessorArchitecture      uint16\n\twReserved                   uint16\n\tdwPageSize                  uint32\n\tlpMinimumApplicationAddress uintptr\n\tlpMaximumApplicationAddress uintptr\n\tdwActiveProcessorMask       uintptr\n\tdwNumberOfProcessors        uint32\n\tdwProcessorType             uint32\n\tdwAllocationGranularity     uint32\n\twProcessorLevel             uint16\n\twProcessorRevision          uint16\n}\n\n// system type as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-enum_page_file_information\ntype enumPageFileInformation struct {\n\tcb         uint32\n\treserved   uint32\n\ttotalSize  uint64\n\ttotalInUse uint64\n\tpeakUsage  uint64\n}\n\nfunc SwapDevices() ([]*SwapDevice, error) {\n\treturn SwapDevicesWithContext(context.Background())\n}\n\nfunc SwapDevicesWithContext(_ context.Context) ([]*SwapDevice, error) {\n\tpageSizeOnce.Do(func() {\n\t\tvar sysInfo systemInfo\n\t\tprocGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sysInfo)))\n\t\tpageSize = uint64(sysInfo.dwPageSize)\n\t})\n\n\t// the following system call invokes the supplied callback function once for each page file before returning\n\t// see https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumpagefilesw\n\tvar swapDevices []*SwapDevice\n\t// EnumPageFilesW returns 0 for error, in which case we check err,\n\t// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call\n\tresult, _, err := procEnumPageFilesW.Call(windows.NewCallback(pEnumPageFileCallbackW), uintptr(unsafe.Pointer(&swapDevices)))\n\tif result == 0 {\n\t\treturn nil, err\n\t}\n\n\treturn swapDevices, nil\n}\n\n// system callback as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/nc-psapi-penum_page_file_callbackw\nfunc pEnumPageFileCallbackW(swapDevices *[]*SwapDevice, enumPageFileInfo *enumPageFileInformation, lpFilenamePtr *[syscall.MAX_LONG_PATH]uint16) *bool {\n\t*swapDevices = append(*swapDevices, &SwapDevice{\n\t\tName:      syscall.UTF16ToString((*lpFilenamePtr)[:]),\n\t\tUsedBytes: enumPageFileInfo.totalInUse * pageSize,\n\t\tFreeBytes: (enumPageFileInfo.totalSize - enumPageFileInfo.totalInUse) * pageSize,\n\t})\n\n\t// return true to continue enumerating page files\n\tret := true\n\treturn &ret\n}\n"
  },
  {
    "path": "mem/testdata/linux/virtualmemory/anonhugepages/proc/meminfo",
    "content": "MemTotal:       260799420 kB\nMemFree:        119443248 kB\nMemAvailable:   127880216 kB\nAnonHugePages:  50409472 kB"
  },
  {
    "path": "mem/testdata/linux/virtualmemory/intelcorei5/proc/meminfo",
    "content": "MemTotal:       16115528 kB\nMemFree:         8577628 kB\nMemAvailable:   11225936 kB\nBuffers:          207516 kB\nCached:          3791568 kB\nSwapCached:            0 kB\nActive:          4245500 kB\nInactive:        2869956 kB\nActive(anon):    3123508 kB\nInactive(anon):  1186612 kB\nActive(file):    1121992 kB\nInactive(file):  1683344 kB\nUnevictable:          32 kB\nMlocked:              32 kB\nSwapTotal:       8065020 kB\nSwapFree:        8065020 kB\nDirty:               172 kB\nWriteback:             0 kB\nAnonPages:       3116472 kB\nMapped:          1145144 kB\nShmem:           1193752 kB\nSlab:             247824 kB\nSReclaimable:     182100 kB\nSUnreclaim:        65724 kB\nKernelStack:       14224 kB\nPageTables:        63712 kB\nNFS_Unstable:          0 kB\nBounce:                0 kB\nWritebackTmp:          0 kB\nCommitLimit:    16122784 kB\nCommitted_AS:   12071112 kB\nVmallocTotal:   34359738367 kB\nVmallocUsed:           0 kB\nVmallocChunk:          0 kB\nPercpu:            19136 kB\nHardwareCorrupted:     0 kB\nAnonHugePages:         0 kB\nShmemHugePages:        0 kB\nShmemPmdMapped:        0 kB\nHugePages_Total:       0\nHugePages_Free:        0\nHugePages_Rsvd:        0\nHugePages_Surp:        0\nHugepagesize:       2048 kB\nDirectMap4k:      143564 kB\nDirectMap2M:     6871040 kB\nDirectMap1G:    10485760 kB\n"
  },
  {
    "path": "mem/testdata/linux/virtualmemory/issue1002/proc/meminfo",
    "content": "        total:    used:    free:  shared: buffers:  cached:\nMem:  260579328 136073216 124506112        0  4915200 94064640\nSwap:        0        0        0\nMemTotal:         254472 kB\nMemFree:          121588 kB\nMemShared:             0 kB\nBuffers:            4800 kB\nCached:            91860 kB\nSwapCached:            0 kB\nActive:           106236 kB\nInactive:           8380 kB\nMemAvailable:     210156 kB\nActive(anon):      17956 kB\nInactive(anon):        0 kB\nActive(file):      88280 kB\nInactive(file):     8380 kB\nUnevictable:           0 kB\nMlocked:               0 kB\nHighTotal:        131072 kB\nHighFree:          66196 kB\nLowTotal:         123400 kB\nLowFree:           55392 kB\nSwapTotal:             0 kB\nSwapFree:              0 kB\nDirty:                 0 kB\nWriteback:             0 kB\nAnonPages:         17992 kB\nMapped:            37884 kB\nShmem:                 0 kB\nSlab:               9076 kB\nSReclaimable:       2700 kB\nSUnreclaim:         6376 kB\nKernelStack:         624 kB\nPageTables:          396 kB\nNFS_Unstable:          0 kB\nBounce:                0 kB\nWritebackTmp:          0 kB\nCommitLimit:      127236 kB\nCommitted_AS:      24968 kB\nVmallocTotal:    1949696 kB\nVmallocUsed:           0 kB\nVmallocChunk:          0 kB\n"
  },
  {
    "path": "mem/testdata/plan9/virtualmemory/dev/swap",
    "content": "1071185920 memory\n4096 pagesize\n61372 kernel\n2792/200148 user\n0/160000 swap\n9046176/219352384 kernel malloc\n0/16777216 kernel draw\n"
  },
  {
    "path": "mem/types_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n/*\nInput to cgo -godefs.\n*/\n\npackage mem\n\n/*\n#include <sys/types.h>\n#include <sys/mount.h>\n#include <sys/sysctl.h>\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tCTLVfs        = 10\n\tVfsGeneric    = 0\n\tVfsBcacheStat = 3\n)\n\nconst (\n\tsizeOfBcachestats = C.sizeof_struct_bcachestats\n)\n\ntype Bcachestats C.struct_bcachestats\n"
  },
  {
    "path": "mktypes.sh",
    "content": "#!/bin/sh\n\nPKGS=\"cpu disk docker host load mem net process sensors winservices\"\n\nGOOS=$(go env GOOS)\nGOARCH=$(go env GOARCH)\n\nfor PKG in $PKGS\ndo\n        if [ -e \"${PKG}/types_${GOOS}.go\" ]; then\n                (echo \"// +build $GOOS\"\n                echo \"// +build $GOARCH\"\n                go tool cgo -godefs \"${PKG}/types_${GOOS}.go\") | gofmt > \"${PKG}/${PKG}_${GOOS}_${GOARCH}.go\"\n        fi\ndone\n"
  },
  {
    "path": "net/net.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage net\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"net\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar invoke common.Invoker = common.Invoke{}\n\ntype IOCountersStat struct {\n\tName        string `json:\"name\"`        // interface name\n\tBytesSent   uint64 `json:\"bytesSent\"`   // number of bytes sent\n\tBytesRecv   uint64 `json:\"bytesRecv\"`   // number of bytes received\n\tPacketsSent uint64 `json:\"packetsSent\"` // number of packets sent\n\tPacketsRecv uint64 `json:\"packetsRecv\"` // number of packets received\n\tErrin       uint64 `json:\"errin\"`       // total number of errors while receiving\n\tErrout      uint64 `json:\"errout\"`      // total number of errors while sending\n\tDropin      uint64 `json:\"dropin\"`      // total number of incoming packets which were dropped\n\tDropout     uint64 `json:\"dropout\"`     // total number of outgoing packets which were dropped (always 0 on OSX and BSD)\n\tFifoin      uint64 `json:\"fifoin\"`      // total number of FIFO buffers errors while receiving\n\tFifoout     uint64 `json:\"fifoout\"`     // total number of FIFO buffers errors while sending\n}\n\n// Addr is implemented compatibility to psutil\ntype Addr struct {\n\tIP   string `json:\"ip\"`\n\tPort uint32 `json:\"port\"`\n}\n\ntype ConnectionStat struct {\n\tFd     uint32  `json:\"fd\"`\n\tFamily uint32  `json:\"family\"`\n\tType   uint32  `json:\"type\"`\n\tLaddr  Addr    `json:\"localaddr\"`\n\tRaddr  Addr    `json:\"remoteaddr\"`\n\tStatus string  `json:\"status\"`\n\tUids   []int32 `json:\"uids\"`\n\tPid    int32   `json:\"pid\"`\n}\n\n// System wide stats about different network protocols\ntype ProtoCountersStat struct {\n\tProtocol string           `json:\"protocol\"`\n\tStats    map[string]int64 `json:\"stats\"`\n}\n\n// NetInterfaceAddr is designed for represent interface addresses\ntype InterfaceAddr struct {\n\tAddr string `json:\"addr\"`\n}\n\n// InterfaceAddrList is a list of InterfaceAddr\ntype InterfaceAddrList []InterfaceAddr\n\ntype InterfaceStat struct {\n\tIndex        int               `json:\"index\"`\n\tMTU          int               `json:\"mtu\"`          // maximum transmission unit\n\tName         string            `json:\"name\"`         // e.g., \"en0\", \"lo0\", \"eth0.100\"\n\tHardwareAddr string            `json:\"hardwareAddr\"` // IEEE MAC-48, EUI-48 and EUI-64 form\n\tFlags        []string          `json:\"flags\"`        // e.g., FlagUp, FlagLoopback, FlagMulticast\n\tAddrs        InterfaceAddrList `json:\"addrs\"`\n}\n\n// InterfaceStatList is a list of InterfaceStat\ntype InterfaceStatList []InterfaceStat\n\ntype FilterStat struct {\n\tConnTrackCount int64 `json:\"connTrackCount\"`\n\tConnTrackMax   int64 `json:\"connTrackMax\"`\n}\n\n// ConntrackStat has conntrack summary info\ntype ConntrackStat struct {\n\tEntries       uint32 `json:\"entries\"`       // Number of entries in the conntrack table\n\tSearched      uint32 `json:\"searched\"`      // Number of conntrack table lookups performed\n\tFound         uint32 `json:\"found\"`         // Number of searched entries which were successful\n\tNew           uint32 `json:\"new\"`           // Number of entries added which were not expected before\n\tInvalid       uint32 `json:\"invalid\"`       // Number of packets seen which can not be tracked\n\tIgnore        uint32 `json:\"ignore\"`        // Packets seen which are already connected to an entry\n\tDelete        uint32 `json:\"delete\"`        // Number of entries which were removed\n\tDeleteList    uint32 `json:\"deleteList\"`    // Number of entries which were put to dying list\n\tInsert        uint32 `json:\"insert\"`        // Number of entries inserted into the list\n\tInsertFailed  uint32 `json:\"insertFailed\"`  // # insertion attempted but failed (same entry exists)\n\tDrop          uint32 `json:\"drop\"`          // Number of packets dropped due to conntrack failure.\n\tEarlyDrop     uint32 `json:\"earlyDrop\"`     // Dropped entries to make room for new ones, if maxsize reached\n\tIcmpError     uint32 `json:\"icmpError\"`     // Subset of invalid. Packets that can't be tracked d/t error\n\tExpectNew     uint32 `json:\"expectNew\"`     // Entries added after an expectation was already present\n\tExpectCreate  uint32 `json:\"expectCreate\"`  // Expectations added\n\tExpectDelete  uint32 `json:\"expectDelete\"`  // Expectations deleted\n\tSearchRestart uint32 `json:\"searchRestart\"` // Conntrack table lookups restarted due to hashtable resizes\n}\n\nfunc NewConntrackStat(e, s, f, n, inv, ign, del, dlst, ins, insfail, drop, edrop, ie, en, ec, ed, sr uint32) *ConntrackStat {\n\treturn &ConntrackStat{\n\t\tEntries:       e,\n\t\tSearched:      s,\n\t\tFound:         f,\n\t\tNew:           n,\n\t\tInvalid:       inv,\n\t\tIgnore:        ign,\n\t\tDelete:        del,\n\t\tDeleteList:    dlst,\n\t\tInsert:        ins,\n\t\tInsertFailed:  insfail,\n\t\tDrop:          drop,\n\t\tEarlyDrop:     edrop,\n\t\tIcmpError:     ie,\n\t\tExpectNew:     en,\n\t\tExpectCreate:  ec,\n\t\tExpectDelete:  ed,\n\t\tSearchRestart: sr,\n\t}\n}\n\ntype ConntrackStatList struct {\n\titems []*ConntrackStat\n}\n\nfunc NewConntrackStatList() *ConntrackStatList {\n\treturn &ConntrackStatList{\n\t\titems: []*ConntrackStat{},\n\t}\n}\n\nfunc (l *ConntrackStatList) Append(c *ConntrackStat) {\n\tl.items = append(l.items, c)\n}\n\nfunc (l *ConntrackStatList) Items() []ConntrackStat {\n\titems := make([]ConntrackStat, len(l.items))\n\tfor i, el := range l.items {\n\t\titems[i] = *el\n\t}\n\treturn items\n}\n\n// Summary returns a single-element list with totals from all list items.\nfunc (l *ConntrackStatList) Summary() []ConntrackStat {\n\tsummary := NewConntrackStat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\n\tfor _, cs := range l.items {\n\t\tsummary.Entries += cs.Entries\n\t\tsummary.Searched += cs.Searched\n\t\tsummary.Found += cs.Found\n\t\tsummary.New += cs.New\n\t\tsummary.Invalid += cs.Invalid\n\t\tsummary.Ignore += cs.Ignore\n\t\tsummary.Delete += cs.Delete\n\t\tsummary.DeleteList += cs.DeleteList\n\t\tsummary.Insert += cs.Insert\n\t\tsummary.InsertFailed += cs.InsertFailed\n\t\tsummary.Drop += cs.Drop\n\t\tsummary.EarlyDrop += cs.EarlyDrop\n\t\tsummary.IcmpError += cs.IcmpError\n\t\tsummary.ExpectNew += cs.ExpectNew\n\t\tsummary.ExpectCreate += cs.ExpectCreate\n\t\tsummary.ExpectDelete += cs.ExpectDelete\n\t\tsummary.SearchRestart += cs.SearchRestart\n\t}\n\treturn []ConntrackStat{*summary}\n}\n\nfunc (n IOCountersStat) String() string {\n\ts, _ := json.Marshal(n)\n\treturn string(s)\n}\n\nfunc (n ConnectionStat) String() string {\n\ts, _ := json.Marshal(n)\n\treturn string(s)\n}\n\nfunc (n ProtoCountersStat) String() string {\n\ts, _ := json.Marshal(n)\n\treturn string(s)\n}\n\nfunc (a Addr) String() string {\n\ts, _ := json.Marshal(a)\n\treturn string(s)\n}\n\nfunc (n InterfaceStat) String() string {\n\ts, _ := json.Marshal(n)\n\treturn string(s)\n}\n\nfunc (l InterfaceStatList) String() string {\n\ts, _ := json.Marshal(l)\n\treturn string(s)\n}\n\nfunc (n InterfaceAddr) String() string {\n\ts, _ := json.Marshal(n)\n\treturn string(s)\n}\n\nfunc (n ConntrackStat) String() string {\n\ts, _ := json.Marshal(n)\n\treturn string(s)\n}\n\nfunc Interfaces() (InterfaceStatList, error) {\n\treturn InterfacesWithContext(context.Background())\n}\n\nfunc InterfacesWithContext(_ context.Context) (InterfaceStatList, error) {\n\tis, err := net.Interfaces()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := make(InterfaceStatList, 0, len(is))\n\tfor _, ifi := range is {\n\n\t\tvar flags []string\n\t\tif ifi.Flags&net.FlagUp != 0 {\n\t\t\tflags = append(flags, \"up\")\n\t\t}\n\t\tif ifi.Flags&net.FlagBroadcast != 0 {\n\t\t\tflags = append(flags, \"broadcast\")\n\t\t}\n\t\tif ifi.Flags&net.FlagLoopback != 0 {\n\t\t\tflags = append(flags, \"loopback\")\n\t\t}\n\t\tif ifi.Flags&net.FlagPointToPoint != 0 {\n\t\t\tflags = append(flags, \"pointtopoint\")\n\t\t}\n\t\tif ifi.Flags&net.FlagMulticast != 0 {\n\t\t\tflags = append(flags, \"multicast\")\n\t\t}\n\n\t\tr := InterfaceStat{\n\t\t\tIndex:        ifi.Index,\n\t\t\tName:         ifi.Name,\n\t\t\tMTU:          ifi.MTU,\n\t\t\tHardwareAddr: ifi.HardwareAddr.String(),\n\t\t\tFlags:        flags,\n\t\t}\n\t\taddrs, err := ifi.Addrs()\n\t\tif err == nil {\n\t\t\tr.Addrs = make(InterfaceAddrList, 0, len(addrs))\n\t\t\tfor _, addr := range addrs {\n\t\t\t\tr.Addrs = append(r.Addrs, InterfaceAddr{\n\t\t\t\t\tAddr: addr.String(),\n\t\t\t\t})\n\t\t\t}\n\n\t\t}\n\t\tret = append(ret, r)\n\t}\n\n\treturn ret, nil\n}\n\nfunc getIOCountersAll(n []IOCountersStat) []IOCountersStat {\n\tr := IOCountersStat{\n\t\tName: \"all\",\n\t}\n\tfor _, nic := range n {\n\t\tr.BytesRecv += nic.BytesRecv\n\t\tr.PacketsRecv += nic.PacketsRecv\n\t\tr.Errin += nic.Errin\n\t\tr.Dropin += nic.Dropin\n\t\tr.BytesSent += nic.BytesSent\n\t\tr.PacketsSent += nic.PacketsSent\n\t\tr.Errout += nic.Errout\n\t\tr.Dropout += nic.Dropout\n\t}\n\n\treturn []IOCountersStat{r}\n}\n\n// IOCounters returns network I/O statistics for every network\n// interface installed on the system.  If pernic argument is false,\n// return only sum of all information (which name is 'all'). If true,\n// every network interface installed on the system is returned\n// separately.\nfunc IOCounters(pernic bool) ([]IOCountersStat, error) {\n\treturn IOCountersWithContext(context.Background(), pernic)\n}\n\nfunc IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {\n\treturn IOCountersByFileWithContext(context.Background(), pernic, filename)\n}\n\n// ProtoCounters returns network statistics for the entire system\n// If protocols is empty then all protocols are returned, otherwise\n// just the protocols in the list are returned.\n// Available protocols:\n// [ip,icmp,icmpmsg,tcp,udp,udplite]\n// Not Implemented for FreeBSD, Windows, OpenBSD, Darwin\nfunc ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {\n\treturn ProtoCountersWithContext(context.Background(), protocols)\n}\n\n// FilterCounters returns iptables conntrack statistics\n// the currently in use conntrack count and the max.\n// If the file does not exist or is invalid it will return nil.\nfunc FilterCounters() ([]FilterStat, error) {\n\treturn FilterCountersWithContext(context.Background())\n}\n\n// ConntrackStats returns more detailed info about the conntrack table\nfunc ConntrackStats(percpu bool) ([]ConntrackStat, error) {\n\treturn ConntrackStatsWithContext(context.Background(), percpu)\n}\n\n// Return a list of network connections opened.\nfunc Connections(kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsWithContext(context.Background(), kind)\n}\n\n// Return a list of network connections opened returning at most `max`\n// connections for each running process.\nfunc ConnectionsMax(kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsMaxWithContext(context.Background(), kind, maxConn)\n}\n\n// Return a list of network connections opened, omitting `Uids`.\n// WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be\n// removed from the API in the future.\nfunc ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsWithoutUidsWithContext(context.Background(), kind)\n}\n\n// Return a list of network connections opened by a process.\nfunc ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidWithContext(context.Background(), kind, pid)\n}\n\n// Return a list of network connections opened, omitting `Uids`.\n// WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be\n// removed from the API in the future.\nfunc ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid)\n}\n\nfunc ConnectionsPidMaxWithoutUids(kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, maxConn)\n}\n\n// Return up to `max` network connections opened by a process.\nfunc ConnectionsPidMax(kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(context.Background(), kind, pid, maxConn)\n}\n\n// Pids retunres all pids.\n// Note: this is a copy of process_linux.Pids()\n// FIXME: Import process occurs import cycle.\n// move to common made other platform breaking. Need consider.\nfunc Pids() ([]int32, error) {\n\treturn PidsWithContext(context.Background())\n}\n"
  },
  {
    "path": "net/net_aix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage net\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// Deprecated: use process.PidsWithContext instead\nfunc PidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {\n\treturn IOCountersWithContext(ctx, pernic)\n}\n\nfunc FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc parseNetstatNetLine(line string) (ConnectionStat, error) {\n\tf := strings.Fields(line)\n\tif len(f) < 5 {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"wrong line,%s\", line)\n\t}\n\n\tvar netType, netFamily uint32\n\tswitch f[0] {\n\tcase \"tcp\", \"tcp4\":\n\t\tnetType = syscall.SOCK_STREAM\n\t\tnetFamily = syscall.AF_INET\n\tcase \"udp\", \"udp4\":\n\t\tnetType = syscall.SOCK_DGRAM\n\t\tnetFamily = syscall.AF_INET\n\tcase \"tcp6\":\n\t\tnetType = syscall.SOCK_STREAM\n\t\tnetFamily = syscall.AF_INET6\n\tcase \"udp6\":\n\t\tnetType = syscall.SOCK_DGRAM\n\t\tnetFamily = syscall.AF_INET6\n\tdefault:\n\t\treturn ConnectionStat{}, fmt.Errorf(\"unknown type, %s\", f[0])\n\t}\n\n\tladdr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)\n\tif err != nil {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"failed to parse netaddr, %s %s\", f[3], f[4])\n\t}\n\n\tn := ConnectionStat{\n\t\tFd:     uint32(0), // not supported\n\t\tFamily: uint32(netFamily),\n\t\tType:   uint32(netType),\n\t\tLaddr:  laddr,\n\t\tRaddr:  raddr,\n\t\tPid:    int32(0), // not supported\n\t}\n\tif len(f) == 6 {\n\t\tn.Status = f[5]\n\t}\n\n\treturn n, nil\n}\n\nvar portMatch = regexp.MustCompile(`(.*)\\.(\\d+)$`)\n\nfunc parseAddr(l string, family uint32) (Addr, error) {\n\tmatches := portMatch.FindStringSubmatch(l)\n\tif matches == nil {\n\t\treturn Addr{}, fmt.Errorf(\"wrong addr, %s\", l)\n\t}\n\thost := matches[1]\n\tport := matches[2]\n\tif host == \"*\" {\n\t\tswitch family {\n\t\tcase syscall.AF_INET:\n\t\t\thost = \"0.0.0.0\"\n\t\tcase syscall.AF_INET6:\n\t\t\thost = \"::\"\n\t\tdefault:\n\t\t\treturn Addr{}, fmt.Errorf(\"unknown family, %d\", family)\n\t\t}\n\t}\n\tlport, err := strconv.ParseInt(port, 10, 32)\n\tif err != nil {\n\t\treturn Addr{}, err\n\t}\n\treturn Addr{IP: host, Port: uint32(lport)}, nil\n}\n\n// This function only works for netstat returning addresses with a \".\"\n// before the port (0.0.0.0.22 instead of 0.0.0.0:22).\nfunc parseNetstatAddr(local, remote string, family uint32) (laddr, raddr Addr, err error) {\n\tladdr, err = parseAddr(local, family)\n\tif remote != \"*.*\" { // remote addr exists\n\t\traddr, err = parseAddr(remote, family)\n\t\tif err != nil {\n\t\t\treturn laddr, raddr, err\n\t\t}\n\t}\n\n\treturn laddr, raddr, err\n}\n\nfunc parseNetstatUnixLine(f []string) (ConnectionStat, error) {\n\tif len(f) < 8 {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"wrong number of fields: expected >=8 got %d\", len(f))\n\t}\n\n\tvar netType uint32\n\n\tswitch f[1] {\n\tcase \"dgram\":\n\t\tnetType = syscall.SOCK_DGRAM\n\tcase \"stream\":\n\t\tnetType = syscall.SOCK_STREAM\n\tdefault:\n\t\treturn ConnectionStat{}, fmt.Errorf(\"unknown type: %s\", f[1])\n\t}\n\n\t// Some Unix Socket don't have any address associated\n\taddr := \"\"\n\tif len(f) == 9 {\n\t\taddr = f[8]\n\t}\n\n\tc := ConnectionStat{\n\t\tFd:     uint32(0), // not supported\n\t\tFamily: uint32(syscall.AF_UNIX),\n\t\tType:   uint32(netType),\n\t\tLaddr: Addr{\n\t\t\tIP: addr,\n\t\t},\n\t\tStatus: \"NONE\",\n\t\tPid:    int32(0), // not supported\n\t}\n\n\treturn c, nil\n}\n\n// Return true if proto is the corresponding to the kind parameter\n// Only for Inet lines\nfunc hasCorrectInetProto(kind, proto string) bool {\n\tswitch kind {\n\tcase \"all\", \"inet\":\n\t\treturn true\n\tcase \"unix\":\n\t\treturn false\n\tcase \"inet4\":\n\t\treturn !strings.HasSuffix(proto, \"6\")\n\tcase \"inet6\":\n\t\treturn strings.HasSuffix(proto, \"6\")\n\tcase \"tcp\":\n\t\treturn proto == \"tcp\" || proto == \"tcp4\" || proto == \"tcp6\"\n\tcase \"tcp4\":\n\t\treturn proto == \"tcp\" || proto == \"tcp4\"\n\tcase \"tcp6\":\n\t\treturn proto == \"tcp6\"\n\tcase \"udp\":\n\t\treturn proto == \"udp\" || proto == \"udp4\" || proto == \"udp6\"\n\tcase \"udp4\":\n\t\treturn proto == \"udp\" || proto == \"udp4\"\n\tcase \"udp6\":\n\t\treturn proto == \"udp6\"\n\t}\n\treturn false\n}\n\nfunc parseNetstatA(output, kind string) ([]ConnectionStat, error) {\n\tvar ret []ConnectionStat\n\tlines := strings.Split(string(output), \"\\n\")\n\n\tfor _, line := range lines {\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) < 1 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch {\n\t\tcase strings.HasPrefix(fields[0], \"f1\"):\n\t\t\t// Unix lines\n\t\t\tif len(fields) < 2 {\n\t\t\t\t// every unix connections have two lines\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tc, err := parseNetstatUnixLine(fields)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse Unix Address (%s): %w\", line, err)\n\t\t\t}\n\n\t\t\tret = append(ret, c)\n\n\t\tcase strings.HasPrefix(fields[0], \"tcp\") || strings.HasPrefix(fields[0], \"udp\"):\n\t\t\t// Inet lines\n\t\t\tif !hasCorrectInetProto(kind, fields[0]) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// On AIX, netstat display some connections with \"*.*\" as local addresses\n\t\t\t// Skip them as they aren't real connections.\n\t\t\tif fields[3] == \"*.*\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tc, err := parseNetstatNetLine(line)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse Inet Address (%s): %w\", line, err)\n\t\t\t}\n\n\t\t\tret = append(ret, c)\n\t\tdefault:\n\t\t\t// Header lines\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n\nfunc ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\targs := []string{\"-na\"}\n\tswitch strings.ToLower(kind) {\n\tdefault:\n\t\tfallthrough\n\tcase \"\":\n\t\tkind = \"all\"\n\tcase \"all\":\n\t\t// nothing to add\n\tcase \"inet\", \"inet4\", \"inet6\":\n\t\targs = append(args, \"-finet\")\n\tcase \"tcp\", \"tcp4\", \"tcp6\":\n\t\targs = append(args, \"-finet\")\n\tcase \"udp\", \"udp4\", \"udp6\":\n\t\targs = append(args, \"-finet\")\n\tcase \"unix\":\n\t\targs = append(args, \"-funix\")\n\t}\n\n\tout, err := invoke.CommandWithContext(ctx, \"netstat\", args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret, err := parseNetstatA(string(out), kind)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ret, nil\n}\n\nfunc ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)\n}\n\nfunc ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)\n}\n\nfunc connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "net/net_aix_cgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && cgo\n\npackage net\n\nimport (\n\t\"context\"\n\n\t\"github.com/power-devops/perfstat\"\n)\n\nfunc IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {\n\tifs, err := perfstat.NetIfaceStat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tiocounters := make([]IOCountersStat, 0, len(ifs))\n\tfor _, netif := range ifs {\n\t\tn := IOCountersStat{\n\t\t\tName:        netif.Name,\n\t\t\tBytesSent:   uint64(netif.OBytes),\n\t\t\tBytesRecv:   uint64(netif.IBytes),\n\t\t\tPacketsSent: uint64(netif.OPackets),\n\t\t\tPacketsRecv: uint64(netif.IPackets),\n\t\t\tErrin:       uint64(netif.IErrors),\n\t\t\tErrout:      uint64(netif.OErrors),\n\t\t\tDropin:      uint64(netif.IfIqDrops),\n\t\t\tDropout:     uint64(netif.XmitDrops),\n\t\t}\n\t\tiocounters = append(iocounters, n)\n\t}\n\tif !pernic {\n\t\treturn getIOCountersAll(iocounters), nil\n\t}\n\treturn iocounters, nil\n}\n"
  },
  {
    "path": "net/net_aix_nocgo.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix && !cgo\n\npackage net\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc parseNetstatI(output string) ([]IOCountersStat, error) {\n\tlines := strings.Split(string(output), \"\\n\")\n\tret := make([]IOCountersStat, 0, len(lines)-1)\n\texists := make([]string, 0, len(ret))\n\n\t// Check first line is header\n\tif len(lines) > 0 && strings.Fields(lines[0])[0] != \"Name\" {\n\t\treturn nil, errors.New(\"not a 'netstat -i' output\")\n\t}\n\n\tfor _, line := range lines[1:] {\n\t\tvalues := strings.Fields(line)\n\t\tif len(values) < 1 || values[0] == \"Name\" {\n\t\t\tcontinue\n\t\t}\n\t\tif common.StringsHas(exists, values[0]) {\n\t\t\t// skip if already get\n\t\t\tcontinue\n\t\t}\n\t\texists = append(exists, values[0])\n\n\t\tif len(values) < 9 {\n\t\t\tcontinue\n\t\t}\n\n\t\tbase := 1\n\t\t// sometimes Address is omitted\n\t\tif len(values) < 10 {\n\t\t\tbase = 0\n\t\t}\n\n\t\tparsed := make([]uint64, 0, 5)\n\t\tvv := []string{\n\t\t\tvalues[base+3], // Ipkts == PacketsRecv\n\t\t\tvalues[base+4], // Ierrs == Errin\n\t\t\tvalues[base+5], // Opkts == PacketsSent\n\t\t\tvalues[base+6], // Oerrs == Errout\n\t\t\tvalues[base+8], // Drops == Dropout\n\t\t}\n\n\t\tfor _, target := range vv {\n\t\t\tif target == \"-\" {\n\t\t\t\tparsed = append(parsed, 0)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tt, err := strconv.ParseUint(target, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tparsed = append(parsed, t)\n\t\t}\n\n\t\tn := IOCountersStat{\n\t\t\tName:        values[0],\n\t\t\tPacketsRecv: parsed[0],\n\t\t\tErrin:       parsed[1],\n\t\t\tPacketsSent: parsed[2],\n\t\t\tErrout:      parsed[3],\n\t\t\tDropout:     parsed[4],\n\t\t}\n\t\tret = append(ret, n)\n\t}\n\treturn ret, nil\n}\n\nfunc IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"netstat\", \"-idn\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tiocounters, err := parseNetstatI(string(out))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !pernic {\n\t\treturn getIOCountersAll(iocounters), nil\n\t}\n\treturn iocounters, nil\n}\n"
  },
  {
    "path": "net/net_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage net\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar (\n\terrNetstatHeader  = errors.New(\"can't parse header of netstat output\")\n\tnetstatLinkRegexp = regexp.MustCompile(`^<Link#(\\d+)>$`)\n)\n\nconst endOfLine = \"\\n\"\n\nfunc parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err error) {\n\tvar (\n\t\tnumericValue uint64\n\t\tcolumns      = strings.Fields(line)\n\t)\n\n\tif columns[0] == \"Name\" {\n\t\treturn nil, nil, errNetstatHeader\n\t}\n\n\t// try to extract the numeric value from <Link#123>\n\tif subMatch := netstatLinkRegexp.FindStringSubmatch(columns[2]); len(subMatch) == 2 {\n\t\tnumericValue, err = strconv.ParseUint(subMatch[1], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tlinkIDUint := uint(numericValue)\n\t\tlinkID = &linkIDUint\n\t}\n\n\tbase := 1\n\tnumberColumns := len(columns)\n\t// sometimes Address is omitted\n\tif numberColumns < 12 {\n\t\tbase = 0\n\t}\n\tif numberColumns < 11 || numberColumns > 13 {\n\t\treturn nil, nil, fmt.Errorf(\"line %q do have an invalid number of columns %d\", line, numberColumns)\n\t}\n\n\tparsed := make([]uint64, 0, 7)\n\tvv := []string{\n\t\tcolumns[base+3],  // Ipkts == PacketsRecv\n\t\tcolumns[base+4],  // Ierrs == Errin\n\t\tcolumns[base+5],  // Ibytes == BytesRecv\n\t\tcolumns[base+6],  // Opkts == PacketsSent\n\t\tcolumns[base+7],  // Oerrs == Errout\n\t\tcolumns[base+8],  // Obytes == BytesSent\n\t\tcolumns[base+10], // Drop == Dropout\n\t}\n\n\tfor _, target := range vv {\n\t\tif target == \"-\" {\n\t\t\tparsed = append(parsed, 0)\n\t\t\tcontinue\n\t\t}\n\n\t\tif numericValue, err = strconv.ParseUint(target, 10, 64); err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tparsed = append(parsed, numericValue)\n\t}\n\n\tstat = &IOCountersStat{\n\t\tName:        strings.Trim(columns[0], \"*\"), // remove the * that sometimes is on right on interface\n\t\tPacketsRecv: parsed[0],\n\t\tErrin:       parsed[1],\n\t\tBytesRecv:   parsed[2],\n\t\tPacketsSent: parsed[3],\n\t\tErrout:      parsed[4],\n\t\tBytesSent:   parsed[5],\n\t\tDropout:     parsed[6],\n\t}\n\treturn stat, linkID, nil\n}\n\ntype netstatInterface struct {\n\tlinkID *uint\n\tstat   *IOCountersStat\n}\n\nfunc parseNetstatOutput(output string) ([]netstatInterface, error) {\n\tvar (\n\t\terr   error\n\t\tlines = strings.Split(strings.Trim(output, endOfLine), endOfLine)\n\t)\n\n\t// number of interfaces is number of lines less one for the header\n\tnumberInterfaces := len(lines) - 1\n\n\tinterfaces := make([]netstatInterface, numberInterfaces)\n\t// no output beside header\n\tif numberInterfaces == 0 {\n\t\treturn interfaces, nil\n\t}\n\n\tfor index := 0; index < numberInterfaces; index++ {\n\t\tnsIface := netstatInterface{}\n\t\tif nsIface.stat, nsIface.linkID, err = parseNetstatLine(lines[index+1]); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tinterfaces[index] = nsIface\n\t}\n\treturn interfaces, nil\n}\n\n// map that hold the name of a network interface and the number of usage\ntype mapInterfaceNameUsage map[string]uint\n\nfunc newMapInterfaceNameUsage(ifaces []netstatInterface) mapInterfaceNameUsage {\n\toutput := make(mapInterfaceNameUsage)\n\tfor index := range ifaces {\n\t\tif ifaces[index].linkID != nil {\n\t\t\tifaceName := ifaces[index].stat.Name\n\t\t\tusage, ok := output[ifaceName]\n\t\t\tif ok {\n\t\t\t\toutput[ifaceName] = usage + 1\n\t\t\t} else {\n\t\t\t\toutput[ifaceName] = 1\n\t\t\t}\n\t\t}\n\t}\n\treturn output\n}\n\nfunc (mapi mapInterfaceNameUsage) isTruncated() bool {\n\tfor _, usage := range mapi {\n\t\tif usage > 1 {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (mapi mapInterfaceNameUsage) notTruncated() []string {\n\toutput := make([]string, 0)\n\tfor ifaceName, usage := range mapi {\n\t\tif usage == 1 {\n\t\t\toutput = append(output, ifaceName)\n\t\t}\n\t}\n\treturn output\n}\n\n// Deprecated: use process.PidsWithContext instead\nfunc PidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\n// example of `netstat -ibdnW` output on yosemite\n// Name  Mtu   Network       Address            Ipkts Ierrs     Ibytes    Opkts Oerrs     Obytes  Coll Drop\n// lo0   16384 <Link#1>                        869107     0  169411755   869107     0  169411755     0   0\n// lo0   16384 ::1/128     ::1                 869107     -  169411755   869107     -  169411755     -   -\n// lo0   16384 127           127.0.0.1         869107     -  169411755   869107     -  169411755     -   -\nfunc IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {\n\tvar (\n\t\tret      []IOCountersStat\n\t\tretIndex int\n\t)\n\n\tnetstat, err := exec.LookPath(\"netstat\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// try to get all interface metrics, and hope there won't be any truncated\n\tout, err := invoke.CommandWithContext(ctx, netstat, \"-ibdnW\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnsInterfaces, err := parseNetstatOutput(string(out))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tifaceUsage := newMapInterfaceNameUsage(nsInterfaces)\n\tnotTruncated := ifaceUsage.notTruncated()\n\tret = make([]IOCountersStat, len(notTruncated))\n\n\tif !ifaceUsage.isTruncated() {\n\t\t// no truncated interface name, return stats of all interface with <Link#...>\n\t\tfor index := range nsInterfaces {\n\t\t\tif nsInterfaces[index].linkID != nil {\n\t\t\t\tret[retIndex] = *nsInterfaces[index].stat\n\t\t\t\tretIndex++\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// duplicated interface, list all interfaces\n\t\tif out, err = invoke.CommandWithContext(ctx, \"ifconfig\", \"-l\"); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tinterfaceNames := strings.Fields(strings.TrimRight(string(out), endOfLine))\n\n\t\t// for each of the interface name, run netstat if we don't have any stats yet\n\t\tfor _, interfaceName := range interfaceNames {\n\t\t\ttruncated := true\n\t\t\tfor index := range nsInterfaces {\n\t\t\t\tif nsInterfaces[index].linkID != nil && nsInterfaces[index].stat.Name == interfaceName {\n\t\t\t\t\t// handle the non truncated name to avoid execute netstat for them again\n\t\t\t\t\tret[retIndex] = *nsInterfaces[index].stat\n\t\t\t\t\tretIndex++\n\t\t\t\t\ttruncated = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif truncated {\n\t\t\t\t// run netstat with -I$ifacename\n\t\t\t\tif out, err = invoke.CommandWithContext(ctx, netstat, \"-ibdnWI\"+interfaceName); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tparsedIfaces, err := parseNetstatOutput(string(out))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif len(parsedIfaces) == 0 {\n\t\t\t\t\t// interface had been removed since `ifconfig -l` had been executed\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor index := range parsedIfaces {\n\t\t\t\t\tif parsedIfaces[index].linkID != nil {\n\t\t\t\t\t\tret = append(ret, *parsedIfaces[index].stat)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif !pernic {\n\t\treturn getIOCountersAll(ret), nil\n\t}\n\treturn ret, nil\n}\n\nfunc IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {\n\treturn IOCountersWithContext(ctx, pernic)\n}\n\nfunc FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "net/net_darwin_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage net\n\nimport (\n\t\"testing\"\n\n\tassert \"github.com/stretchr/testify/require\"\n)\n\nconst (\n\tnetstatTruncated = `Name  Mtu   Network       Address            Ipkts Ierrs     Ibytes    Opkts Oerrs     Obytes  Coll Drop\nlo0   16384 <Link#1>                         31241     0    3769823    31241     0    3769823     0   0\nlo0   16384 ::1/128     ::1                  31241     -    3769823    31241     -    3769823     -   -\nlo0   16384 127           127.0.0.1          31241     -    3769823    31241     -    3769823     -   -\nlo0   16384 fe80::1%lo0 fe80:1::1            31241     -    3769823    31241     -    3769823     -   -\ngif0* 1280  <Link#2>                             0     0          0        0     0          0     0   0\nstf0* 1280  <Link#3>                             0     0          0        0     0          0     0   0\nutun8 1500  <Link#88>                          286     0      27175        0     0          0     0   0\nutun8 1500  <Link#90>                          286     0      29554        0     0          0     0   0\nutun8 1500  <Link#92>                          286     0      29244        0     0          0     0   0\nutun8 1500  <Link#93>                          286     0      28267        0     0          0     0   0\nutun8 1500  <Link#95>                          286     0      28593        0     0          0     0   0`\n\tnetstatNotTruncated = `Name  Mtu   Network       Address            Ipkts Ierrs     Ibytes    Opkts Oerrs     Obytes  Coll Drop\nlo0   16384 <Link#1>                      27190978     0 12824763793 27190978     0 12824763793     0   0\nlo0   16384 ::1/128     ::1               27190978     - 12824763793 27190978     - 12824763793     -   -\nlo0   16384 127           127.0.0.1       27190978     - 12824763793 27190978     - 12824763793     -   -\nlo0   16384 fe80::1%lo0 fe80:1::1         27190978     - 12824763793 27190978     - 12824763793     -   -\ngif0* 1280  <Link#2>                             0     0          0        0     0          0     0   0\nstf0* 1280  <Link#3>                             0     0          0        0     0          0     0   0\nen0   1500  <Link#4>    a8:66:7f:dd:ee:ff  5708989     0 7295722068  3494252     0  379533492     0 230\nen0   1500  fe80::aa66: fe80:4::aa66:7fff  5708989     - 7295722068  3494252     -  379533492     -   -`\n)\n\nfunc TestParseNetstatLineHeader(t *testing.T) {\n\tstat, linkIkd, err := parseNetstatLine(`Name  Mtu   Network       Address            Ipkts Ierrs     Ibytes    Opkts Oerrs     Obytes  Coll Drop`)\n\tassert.Nil(t, linkIkd)\n\tassert.Nil(t, stat)\n\tassert.Error(t, err)\n\tassert.Equal(t, errNetstatHeader, err)\n}\n\nfunc assertLoopbackStat(t *testing.T, err error, stat *IOCountersStat) {\n\tt.Helper()\n\tassert.NoError(t, err)\n\tassert.Equal(t, uint64(869107), stat.PacketsRecv)\n\tassert.Equal(t, uint64(0), stat.Errin)\n\tassert.Equal(t, uint64(169411755), stat.BytesRecv)\n\tassert.Equal(t, uint64(869108), stat.PacketsSent)\n\tassert.Equal(t, uint64(1), stat.Errout)\n\tassert.Equal(t, uint64(169411756), stat.BytesSent)\n}\n\nfunc TestParseNetstatLineNoAddressWithDrop(t *testing.T) {\n\tstat, linkID, err := parseNetstatLine(\n\t\t`gif0* 1280  <Link#2>                             5     0          0        0     0          0     0   3`,\n\t)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, linkID)\n\tassert.Equal(t, uint64(3), stat.Dropout)\n}\n\nfunc TestParseNetstatLineLink(t *testing.T) {\n\tstat, linkID, err := parseNetstatLine(\n\t\t`lo0   16384 <Link#1>                        869107     0  169411755   869108     1  169411756     0   0`,\n\t)\n\tassertLoopbackStat(t, err, stat)\n\tassert.NotNil(t, linkID)\n\tassert.Equal(t, uint(1), *linkID)\n}\n\nfunc TestParseNetstatLineIPv6(t *testing.T) {\n\tstat, linkID, err := parseNetstatLine(\n\t\t`lo0   16384 ::1/128     ::1                 869107     -  169411755   869108     1  169411756     -   -`,\n\t)\n\tassertLoopbackStat(t, err, stat)\n\tassert.Nil(t, linkID)\n}\n\nfunc TestParseNetstatLineIPv4(t *testing.T) {\n\tstat, linkID, err := parseNetstatLine(\n\t\t`lo0   16384 127           127.0.0.1         869107     -  169411755   869108     1  169411756     -   -`,\n\t)\n\tassertLoopbackStat(t, err, stat)\n\tassert.Nil(t, linkID)\n}\n\nfunc TestParseNetstatOutput(t *testing.T) {\n\tnsInterfaces, err := parseNetstatOutput(netstatNotTruncated)\n\tassert.NoError(t, err)\n\tassert.Len(t, nsInterfaces, 8)\n\tfor index := range nsInterfaces {\n\t\tassert.NotNilf(t, nsInterfaces[index].stat, \"Index %d\", index)\n\t}\n\n\tassert.NotNil(t, nsInterfaces[0].linkID)\n\tassert.Equal(t, uint(1), *nsInterfaces[0].linkID)\n\n\tassert.Nil(t, nsInterfaces[1].linkID)\n\tassert.Nil(t, nsInterfaces[2].linkID)\n\tassert.Nil(t, nsInterfaces[3].linkID)\n\n\tassert.NotNil(t, nsInterfaces[4].linkID)\n\tassert.Equal(t, uint(2), *nsInterfaces[4].linkID)\n\n\tassert.NotNil(t, nsInterfaces[5].linkID)\n\tassert.Equal(t, uint(3), *nsInterfaces[5].linkID)\n\n\tassert.NotNil(t, nsInterfaces[6].linkID)\n\tassert.Equal(t, uint(4), *nsInterfaces[6].linkID)\n\n\tassert.Nil(t, nsInterfaces[7].linkID)\n\n\tmapUsage := newMapInterfaceNameUsage(nsInterfaces)\n\tassert.False(t, mapUsage.isTruncated())\n\tassert.Len(t, mapUsage.notTruncated(), 4)\n}\n\nfunc TestParseNetstatTruncated(t *testing.T) {\n\tnsInterfaces, err := parseNetstatOutput(netstatTruncated)\n\tassert.NoError(t, err)\n\tassert.Len(t, nsInterfaces, 11)\n\tfor index := range nsInterfaces {\n\t\tassert.NotNilf(t, nsInterfaces[index].stat, \"Index %d\", index)\n\t}\n\n\tconst truncatedIface = \"utun8\"\n\n\tassert.NotNil(t, nsInterfaces[6].linkID)\n\tassert.Equal(t, uint(88), *nsInterfaces[6].linkID)\n\tassert.Equal(t, truncatedIface, nsInterfaces[6].stat.Name)\n\n\tassert.NotNil(t, nsInterfaces[7].linkID)\n\tassert.Equal(t, uint(90), *nsInterfaces[7].linkID)\n\tassert.Equal(t, truncatedIface, nsInterfaces[7].stat.Name)\n\n\tassert.NotNil(t, nsInterfaces[8].linkID)\n\tassert.Equal(t, uint(92), *nsInterfaces[8].linkID)\n\tassert.Equal(t, truncatedIface, nsInterfaces[8].stat.Name)\n\n\tassert.NotNil(t, nsInterfaces[9].linkID)\n\tassert.Equal(t, uint(93), *nsInterfaces[9].linkID)\n\tassert.Equal(t, truncatedIface, nsInterfaces[9].stat.Name)\n\n\tassert.NotNil(t, nsInterfaces[10].linkID)\n\tassert.Equal(t, uint(95), *nsInterfaces[10].linkID)\n\tassert.Equal(t, truncatedIface, nsInterfaces[10].stat.Name)\n\n\tmapUsage := newMapInterfaceNameUsage(nsInterfaces)\n\tassert.True(t, mapUsage.isTruncated())\n\tassert.Lenf(t, mapUsage.notTruncated(), 3, \"en0, gif0 and stf0\")\n}\n"
  },
  {
    "path": "net/net_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !aix && !darwin && !linux && !freebsd && !openbsd && !windows && !solaris\n\npackage net\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc IOCountersWithContext(_ context.Context, _ bool) ([]IOCountersStat, error) {\n\treturn []IOCountersStat{}, common.ErrNotImplementedError\n}\n\nfunc IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {\n\treturn IOCountersWithContext(ctx, pernic)\n}\n\nfunc FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\n// Deprecated: use process.PidsWithContext instead\nfunc PidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConnectionsWithContext(_ context.Context, _ string) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n\nfunc ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)\n}\n\nfunc ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)\n}\n\nfunc connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "net/net_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd\n\npackage net\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// Deprecated: use process.PidsWithContext instead\nfunc PidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {\n\tout, err := invoke.CommandWithContext(ctx, \"netstat\", \"-ibdnW\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlines := strings.Split(string(out), \"\\n\")\n\tret := make([]IOCountersStat, 0, len(lines)-1)\n\texists := make([]string, 0, len(ret))\n\n\tfor _, line := range lines {\n\t\tvalues := strings.Fields(line)\n\t\tif len(values) < 1 || values[0] == \"Name\" {\n\t\t\tcontinue\n\t\t}\n\t\tif common.StringsHas(exists, values[0]) {\n\t\t\t// skip if already get\n\t\t\tcontinue\n\t\t}\n\t\texists = append(exists, values[0])\n\n\t\tif len(values) < 12 {\n\t\t\tcontinue\n\t\t}\n\t\tbase := 1\n\t\t// sometimes Address is omitted\n\t\tif len(values) < 13 {\n\t\t\tbase = 0\n\t\t}\n\n\t\tparsed := make([]uint64, 0, 8)\n\t\tvv := []string{\n\t\t\tvalues[base+3],  // PacketsRecv\n\t\t\tvalues[base+4],  // Errin\n\t\t\tvalues[base+5],  // Dropin\n\t\t\tvalues[base+6],  // BytesRecvn\n\t\t\tvalues[base+7],  // PacketSent\n\t\t\tvalues[base+8],  // Errout\n\t\t\tvalues[base+9],  // BytesSent\n\t\t\tvalues[base+11], // Dropout\n\t\t}\n\t\tfor _, target := range vv {\n\t\t\tif target == \"-\" {\n\t\t\t\tparsed = append(parsed, 0)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tt, err := strconv.ParseUint(target, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tparsed = append(parsed, t)\n\t\t}\n\n\t\tn := IOCountersStat{\n\t\t\tName:        values[0],\n\t\t\tPacketsRecv: parsed[0],\n\t\t\tErrin:       parsed[1],\n\t\t\tDropin:      parsed[2],\n\t\t\tBytesRecv:   parsed[3],\n\t\t\tPacketsSent: parsed[4],\n\t\t\tErrout:      parsed[5],\n\t\t\tBytesSent:   parsed[6],\n\t\t\tDropout:     parsed[7],\n\t\t}\n\t\tret = append(ret, n)\n\t}\n\n\tif !pernic {\n\t\treturn getIOCountersAll(ret), nil\n\t}\n\n\treturn ret, nil\n}\n\nfunc IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {\n\treturn IOCountersWithContext(ctx, pernic)\n}\n\nfunc FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "net/net_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage net\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst ( // Conntrack Column numbers\n\tctENTRIES = iota\n\tctSEARCHED\n\tctFOUND\n\tctNEW\n\tctINVALID\n\tctIGNORE\n\tctDELETE\n\tctDELETE_LIST //nolint:revive //FIXME\n\tctINSERT\n\tctINSERT_FAILED //nolint:revive //FIXME\n\tctDROP\n\tctEARLY_DROP     //nolint:revive //FIXME\n\tctICMP_ERROR     //nolint:revive //FIXME\n\tCT_EXPEctNEW     //nolint:revive //FIXME\n\tctEXPECT_CREATE  //nolint:revive //FIXME\n\tCT_EXPEctDELETE  //nolint:revive //FIXME\n\tctSEARCH_RESTART //nolint:revive //FIXME\n)\n\nfunc IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {\n\tfilename := common.HostProcWithContext(ctx, \"net/dev\")\n\treturn IOCountersByFileWithContext(ctx, pernic, filename)\n}\n\nfunc IOCountersByFileWithContext(_ context.Context, pernic bool, filename string) ([]IOCountersStat, error) {\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tstatlen := len(lines) - 1\n\n\tret := make([]IOCountersStat, 0, statlen)\n\n\tfor _, line := range lines[2:] {\n\t\t// Split interface name and stats data at the last \":\"\n\t\tseparatorPos := strings.LastIndex(line, \":\")\n\t\tif separatorPos == -1 {\n\t\t\tcontinue\n\t\t}\n\t\tinterfacePart := line[0:separatorPos]\n\t\tstatsPart := line[separatorPos+1:]\n\n\t\tinterfaceName := strings.TrimSpace(interfacePart)\n\t\tif interfaceName == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tfields := strings.Fields(strings.TrimSpace(statsPart))\n\t\tbytesRecv, err := strconv.ParseUint(fields[0], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tpacketsRecv, err := strconv.ParseUint(fields[1], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\terrIn, err := strconv.ParseUint(fields[2], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tdropIn, err := strconv.ParseUint(fields[3], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tfifoIn, err := strconv.ParseUint(fields[4], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tbytesSent, err := strconv.ParseUint(fields[8], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tpacketsSent, err := strconv.ParseUint(fields[9], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\terrOut, err := strconv.ParseUint(fields[10], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tdropOut, err := strconv.ParseUint(fields[11], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tfifoOut, err := strconv.ParseUint(fields[12], 10, 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\n\t\tnic := IOCountersStat{\n\t\t\tName:        interfaceName,\n\t\t\tBytesRecv:   bytesRecv,\n\t\t\tPacketsRecv: packetsRecv,\n\t\t\tErrin:       errIn,\n\t\t\tDropin:      dropIn,\n\t\t\tFifoin:      fifoIn,\n\t\t\tBytesSent:   bytesSent,\n\t\t\tPacketsSent: packetsSent,\n\t\t\tErrout:      errOut,\n\t\t\tDropout:     dropOut,\n\t\t\tFifoout:     fifoOut,\n\t\t}\n\t\tret = append(ret, nic)\n\t}\n\n\tif !pernic {\n\t\treturn getIOCountersAll(ret), nil\n\t}\n\n\treturn ret, nil\n}\n\nvar netProtocols = []string{\n\t\"ip\",\n\t\"icmp\",\n\t\"icmpmsg\",\n\t\"tcp\",\n\t\"udp\",\n\t\"udplite\",\n}\n\nfunc ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {\n\tif len(protocols) == 0 {\n\t\tprotocols = netProtocols\n\t}\n\n\tstats := make([]ProtoCountersStat, 0, len(protocols))\n\tprotos := make(map[string]bool, len(protocols))\n\tfor _, p := range protocols {\n\t\tprotos[p] = true\n\t}\n\n\tfilename := common.HostProcWithContext(ctx, \"net/snmp\")\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlinecount := len(lines)\n\tfor i := 0; i < linecount; i++ {\n\t\tline := lines[i]\n\t\tr := strings.IndexRune(line, ':')\n\t\tif r == -1 {\n\t\t\treturn nil, errors.New(filename + \" is not formatted correctly, expected ':'.\")\n\t\t}\n\t\tproto := strings.ToLower(line[:r])\n\t\tif !protos[proto] {\n\t\t\t// skip protocol and data line\n\t\t\ti++\n\t\t\tcontinue\n\t\t}\n\n\t\t// Read header line\n\t\tstatNames := strings.Split(line[r+2:], \" \")\n\n\t\t// Read data line\n\t\ti++\n\t\tstatValues := strings.Split(lines[i][r+2:], \" \")\n\t\tif len(statNames) != len(statValues) {\n\t\t\treturn nil, errors.New(filename + \" is not formatted correctly, expected same number of columns.\")\n\t\t}\n\t\tstat := ProtoCountersStat{\n\t\t\tProtocol: proto,\n\t\t\tStats:    make(map[string]int64, len(statNames)),\n\t\t}\n\t\tfor j := range statNames {\n\t\t\tvalue, err := strconv.ParseInt(statValues[j], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tstat.Stats[statNames[j]] = value\n\t\t}\n\t\tstats = append(stats, stat)\n\t}\n\treturn stats, nil\n}\n\nfunc FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {\n\tcountfile := common.HostProcWithContext(ctx, \"sys/net/netfilter/nf_conntrack_count\")\n\tmaxfile := common.HostProcWithContext(ctx, \"sys/net/netfilter/nf_conntrack_max\")\n\n\tcount, err := common.ReadInts(countfile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstats := make([]FilterStat, 0, 1)\n\n\tmaxConn, err := common.ReadInts(maxfile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpayload := FilterStat{\n\t\tConnTrackCount: count[0],\n\t\tConnTrackMax:   maxConn[0],\n\t}\n\n\tstats = append(stats, payload)\n\treturn stats, nil\n}\n\n// ConntrackStatsWithContext returns more detailed info about the conntrack table\nfunc ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {\n\treturn conntrackStatsFromFile(common.HostProcWithContext(ctx, \"net/stat/nf_conntrack\"), percpu)\n}\n\n// conntrackStatsFromFile returns more detailed info about the conntrack table\n// from `filename`\n// If 'percpu' is false, the result will contain exactly one item with totals/summary\nfunc conntrackStatsFromFile(filename string, percpu bool) ([]ConntrackStat, error) {\n\tlines, err := common.ReadLines(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tstatlist := NewConntrackStatList()\n\n\tfor _, line := range lines {\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) == 17 && fields[0] != \"entries\" {\n\t\t\tstatlist.Append(NewConntrackStat(\n\t\t\t\tcommon.HexToUint32(fields[ctENTRIES]),\n\t\t\t\tcommon.HexToUint32(fields[ctSEARCHED]),\n\t\t\t\tcommon.HexToUint32(fields[ctFOUND]),\n\t\t\t\tcommon.HexToUint32(fields[ctNEW]),\n\t\t\t\tcommon.HexToUint32(fields[ctINVALID]),\n\t\t\t\tcommon.HexToUint32(fields[ctIGNORE]),\n\t\t\t\tcommon.HexToUint32(fields[ctDELETE]),\n\t\t\t\tcommon.HexToUint32(fields[ctDELETE_LIST]),\n\t\t\t\tcommon.HexToUint32(fields[ctINSERT]),\n\t\t\t\tcommon.HexToUint32(fields[ctINSERT_FAILED]),\n\t\t\t\tcommon.HexToUint32(fields[ctDROP]),\n\t\t\t\tcommon.HexToUint32(fields[ctEARLY_DROP]),\n\t\t\t\tcommon.HexToUint32(fields[ctICMP_ERROR]),\n\t\t\t\tcommon.HexToUint32(fields[CT_EXPEctNEW]),\n\t\t\t\tcommon.HexToUint32(fields[ctEXPECT_CREATE]),\n\t\t\t\tcommon.HexToUint32(fields[CT_EXPEctDELETE]),\n\t\t\t\tcommon.HexToUint32(fields[ctSEARCH_RESTART]),\n\t\t\t))\n\t\t}\n\t}\n\n\tif percpu {\n\t\treturn statlist.Items(), nil\n\t}\n\treturn statlist.Summary(), nil\n}\n\n// http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h\nvar tcpStatuses = map[string]string{\n\t\"01\": \"ESTABLISHED\",\n\t\"02\": \"SYN_SENT\",\n\t\"03\": \"SYN_RECV\",\n\t\"04\": \"FIN_WAIT1\",\n\t\"05\": \"FIN_WAIT2\",\n\t\"06\": \"TIME_WAIT\",\n\t\"07\": \"CLOSE\",\n\t\"08\": \"CLOSE_WAIT\",\n\t\"09\": \"LAST_ACK\",\n\t\"0A\": \"LISTEN\",\n\t\"0B\": \"CLOSING\",\n}\n\ntype netConnectionKindType struct {\n\tfamily   uint32\n\tsockType uint32\n\tfilename string\n}\n\nvar kindTCP4 = netConnectionKindType{\n\tfamily:   syscall.AF_INET,\n\tsockType: syscall.SOCK_STREAM,\n\tfilename: \"tcp\",\n}\n\nvar kindTCP6 = netConnectionKindType{\n\tfamily:   syscall.AF_INET6,\n\tsockType: syscall.SOCK_STREAM,\n\tfilename: \"tcp6\",\n}\n\nvar kindUDP4 = netConnectionKindType{\n\tfamily:   syscall.AF_INET,\n\tsockType: syscall.SOCK_DGRAM,\n\tfilename: \"udp\",\n}\n\nvar kindUDP6 = netConnectionKindType{\n\tfamily:   syscall.AF_INET6,\n\tsockType: syscall.SOCK_DGRAM,\n\tfilename: \"udp6\",\n}\n\nvar kindUNIX = netConnectionKindType{\n\tfamily:   syscall.AF_UNIX,\n\tfilename: \"unix\",\n}\n\nvar netConnectionKindMap = map[string][]netConnectionKindType{\n\t\"all\":   {kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},\n\t\"tcp\":   {kindTCP4, kindTCP6},\n\t\"tcp4\":  {kindTCP4},\n\t\"tcp6\":  {kindTCP6},\n\t\"udp\":   {kindUDP4, kindUDP6},\n\t\"udp4\":  {kindUDP4},\n\t\"udp6\":  {kindUDP6},\n\t\"unix\":  {kindUNIX},\n\t\"inet\":  {kindTCP4, kindTCP6, kindUDP4, kindUDP6},\n\t\"inet4\": {kindTCP4, kindUDP4},\n\t\"inet6\": {kindTCP6, kindUDP6},\n}\n\ntype inodeMap struct {\n\tpid int32\n\tfd  uint32\n}\n\ntype connTmp struct {\n\tfd       uint32\n\tfamily   uint32\n\tsockType uint32\n\tladdr    Addr\n\traddr    Addr\n\tstatus   string\n\tpid      int32\n\tboundPid int32\n\tpath     string\n}\n\nfunc ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsPidWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)\n}\n\nfunc ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)\n}\n\nfunc connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int, skipUids bool) ([]ConnectionStat, error) {\n\ttmap, ok := netConnectionKindMap[kind]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid kind, %s\", kind)\n\t}\n\troot := common.HostProcWithContext(ctx)\n\tvar err error\n\tvar inodes map[string][]inodeMap\n\tif pid == 0 {\n\t\tinodes, err = getProcInodesAllWithContext(ctx, root, maxConn)\n\t} else {\n\t\tinodes, err = getProcInodes(root, pid, maxConn)\n\t\tif len(inodes) == 0 {\n\t\t\t// no connection for the pid\n\t\t\treturn []ConnectionStat{}, nil\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get pid(s), %d: %w\", pid, err)\n\t}\n\treturn statsFromInodesWithContext(ctx, root, pid, tmap, inodes, skipUids)\n}\n\nfunc statsFromInodesWithContext(ctx context.Context, root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap, skipUids bool) ([]ConnectionStat, error) {\n\tdupCheckMap := make(map[string]struct{})\n\tvar ret []ConnectionStat\n\n\tvar err error\n\tfor _, t := range tmap {\n\t\tvar path string\n\t\tvar connKey string\n\t\tvar ls []connTmp\n\t\tif pid == 0 {\n\t\t\tpath = fmt.Sprintf(\"%s/net/%s\", root, t.filename)\n\t\t} else {\n\t\t\tpath = fmt.Sprintf(\"%s/%d/net/%s\", root, pid, t.filename)\n\t\t}\n\t\tswitch t.family {\n\t\tcase syscall.AF_INET, syscall.AF_INET6:\n\t\t\tls, err = processInet(path, t, inodes, pid)\n\t\tcase syscall.AF_UNIX:\n\t\t\tls, err = processUnix(path, t, inodes, pid)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor _, c := range ls {\n\t\t\t// Build TCP key to id the connection uniquely\n\t\t\t// socket type, src ip, src port, dst ip, dst port and state should be enough\n\t\t\t// to prevent duplications.\n\t\t\tconnKey = fmt.Sprintf(\"%d-%s:%d-%s:%d-%s\", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)\n\t\t\tif _, ok := dupCheckMap[connKey]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconn := ConnectionStat{\n\t\t\t\tFd:     c.fd,\n\t\t\t\tFamily: c.family,\n\t\t\t\tType:   c.sockType,\n\t\t\t\tLaddr:  c.laddr,\n\t\t\t\tRaddr:  c.raddr,\n\t\t\t\tStatus: c.status,\n\t\t\t\tPid:    c.pid,\n\t\t\t}\n\t\t\tif c.pid == 0 {\n\t\t\t\tconn.Pid = c.boundPid\n\t\t\t} else {\n\t\t\t\tconn.Pid = c.pid\n\t\t\t}\n\n\t\t\tif !skipUids {\n\t\t\t\t// fetch process owner Real, effective, saved set, and filesystem UIDs\n\t\t\t\tproc := process{Pid: conn.Pid}\n\t\t\t\tconn.Uids, _ = proc.getUids(ctx)\n\t\t\t}\n\n\t\t\tret = append(ret, conn)\n\t\t\tdupCheckMap[connKey] = struct{}{}\n\t\t}\n\n\t}\n\n\treturn ret, nil\n}\n\n// getProcInodes returns fd of the pid.\nfunc getProcInodes(root string, pid int32, maxConn int) (map[string][]inodeMap, error) {\n\tret := make(map[string][]inodeMap)\n\n\tdir := fmt.Sprintf(\"%s/%d/fd\", root, pid)\n\tf, err := os.Open(dir)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tdefer f.Close()\n\tdirEntries, err := f.ReadDir(maxConn)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\tfor _, dirEntry := range dirEntries {\n\t\tinodePath := fmt.Sprintf(\"%s/%d/fd/%s\", root, pid, dirEntry.Name())\n\n\t\tinode, err := os.Readlink(inodePath)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif !strings.HasPrefix(inode, \"socket:[\") {\n\t\t\tcontinue\n\t\t}\n\t\t// the process is using a socket\n\t\tl := len(inode)\n\t\tinode = inode[8 : l-1]\n\t\t_, ok := ret[inode]\n\t\tif !ok {\n\t\t\tret[inode] = make([]inodeMap, 0)\n\t\t}\n\t\tfd, err := strconv.ParseInt(dirEntry.Name(), 10, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\ti := inodeMap{\n\t\t\tpid: pid,\n\t\t\tfd:  uint32(fd),\n\t\t}\n\t\tret[inode] = append(ret[inode], i)\n\t}\n\treturn ret, nil\n}\n\nfunc PidsWithContext(ctx context.Context) ([]int32, error) {\n\tvar ret []int32\n\n\td, err := os.Open(common.HostProcWithContext(ctx))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer d.Close()\n\n\tfnames, err := d.Readdirnames(-1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, fname := range fnames {\n\t\tpid, err := strconv.ParseInt(fname, 10, 32)\n\t\tif err != nil {\n\t\t\t// if not numeric name, just skip\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, int32(pid))\n\t}\n\n\treturn ret, nil\n}\n\n// Note: the following is based off process_linux structs and methods\n// we need these to fetch the owner of a process ID\n// FIXME: Import process occurs import cycle.\n// see remarks on pids()\ntype process struct {\n\tPid  int32 `json:\"pid\"`\n\tuids []int32\n}\n\n// Uids returns user ids of the process as a slice of the int\nfunc (p *process) getUids(ctx context.Context) ([]int32, error) {\n\terr := p.fillFromStatus(ctx)\n\tif err != nil {\n\t\treturn []int32{}, err\n\t}\n\treturn p.uids, nil\n}\n\n// Get status from /proc/(pid)/status\nfunc (p *process) fillFromStatus(ctx context.Context) error {\n\tpid := p.Pid\n\tstatPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"status\")\n\tcontents, err := os.ReadFile(statPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlines := strings.Split(string(contents), \"\\n\")\n\tfor _, line := range lines {\n\t\ttabParts := strings.SplitN(line, \"\\t\", 2)\n\t\tif len(tabParts) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tvalue := tabParts[1]\n\t\tif strings.TrimRight(tabParts[0], \":\") == \"Uid\" {\n\t\t\tp.uids = make([]int32, 0, 4)\n\t\t\tfor _, i := range strings.Split(value, \"\\t\") {\n\t\t\t\tv, err := strconv.ParseInt(i, 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tp.uids = append(p.uids, int32(v))\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc getProcInodesAllWithContext(ctx context.Context, root string, maxConn int) (map[string][]inodeMap, error) {\n\tpids, err := PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := make(map[string][]inodeMap)\n\n\tfor _, pid := range pids {\n\t\tt, err := getProcInodes(root, pid, maxConn)\n\t\tif err != nil {\n\t\t\t// skip if permission error or no longer exists\n\t\t\tif os.IsPermission(err) || os.IsNotExist(err) || errors.Is(err, io.EOF) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn ret, err\n\t\t}\n\t\tif len(t) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\t// TODO: update ret.\n\t\tret = updateMap(ret, t)\n\t}\n\treturn ret, nil\n}\n\n// decodeAddress decode address represents addr in proc/net/*\n// ex:\n// \"0500000A:0016\" -> \"10.0.0.5\", 22\n// \"0085002452100113070057A13F025401:0035\" -> \"2400:8500:1301:1052:a157:7:154:23f\", 53\nfunc decodeAddress(family uint32, src string) (Addr, error) {\n\tt := strings.Split(src, \":\")\n\tif len(t) != 2 {\n\t\treturn Addr{}, fmt.Errorf(\"does not contain port, %s\", src)\n\t}\n\taddr := t[0]\n\tport, err := strconv.ParseUint(t[1], 16, 16)\n\tif err != nil {\n\t\treturn Addr{}, fmt.Errorf(\"invalid port, %s\", src)\n\t}\n\tdecoded, err := hex.DecodeString(addr)\n\tif err != nil {\n\t\treturn Addr{}, fmt.Errorf(\"decode error, %w\", err)\n\t}\n\tvar ip net.IP\n\n\tif family == syscall.AF_INET {\n\t\tif common.IsLittleEndian() {\n\t\t\tip = net.IP(Reverse(decoded))\n\t\t} else {\n\t\t\tip = net.IP(decoded)\n\t\t}\n\t} else { // IPv6\n\t\tip, err = parseIPv6HexString(decoded)\n\t\tif err != nil {\n\t\t\treturn Addr{}, err\n\t\t}\n\t}\n\treturn Addr{\n\t\tIP:   ip.String(),\n\t\tPort: uint32(port),\n\t}, nil\n}\n\nfunc Reverse(s []byte) []byte {\n\tfor i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {\n\t\ts[i], s[j] = s[j], s[i]\n\t}\n\treturn s\n}\n\n// parseIPv6HexString parse array of bytes to IPv6 string\nfunc parseIPv6HexString(src []byte) (net.IP, error) {\n\tif len(src) != 16 {\n\t\treturn nil, errors.New(\"invalid IPv6 string\")\n\t}\n\n\tbuf := make([]byte, 0, 16)\n\tfor i := 0; i < len(src); i += 4 {\n\t\tr := Reverse(src[i : i+4])\n\t\tbuf = append(buf, r...)\n\t}\n\treturn net.IP(buf), nil\n}\n\nfunc processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {\n\tif strings.HasSuffix(file, \"6\") && !common.PathExists(file) {\n\t\t// IPv6 not supported, return empty.\n\t\treturn []connTmp{}, nil\n\t}\n\n\t// Read the contents of the /proc file with a single read sys call.\n\t// This minimizes duplicates in the returned connections\n\t// For more info:\n\t// https://github.com/shirou/gopsutil/pull/361\n\tcontents, err := os.ReadFile(file)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlines := bytes.Split(contents, []byte(\"\\n\"))\n\n\tvar ret []connTmp\n\t// skip first line\n\tfor _, line := range lines[1:] {\n\t\tl := strings.Fields(string(line))\n\t\tif len(l) < 10 {\n\t\t\tcontinue\n\t\t}\n\t\tladdr := l[1]\n\t\traddr := l[2]\n\t\tstatus := l[3]\n\t\tinode := l[9]\n\t\tpid := int32(0)\n\t\tfd := uint32(0)\n\t\ti, exists := inodes[inode]\n\t\tif exists {\n\t\t\tpid = i[0].pid\n\t\t\tfd = i[0].fd\n\t\t}\n\t\tif filterPid > 0 && filterPid != pid {\n\t\t\tcontinue\n\t\t}\n\t\tif kind.sockType == syscall.SOCK_STREAM {\n\t\t\tstatus = tcpStatuses[status]\n\t\t} else {\n\t\t\tstatus = \"NONE\"\n\t\t}\n\t\tla, err := decodeAddress(kind.family, laddr)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tra, err := decodeAddress(kind.family, raddr)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, connTmp{\n\t\t\tfd:       fd,\n\t\t\tfamily:   kind.family,\n\t\t\tsockType: kind.sockType,\n\t\t\tladdr:    la,\n\t\t\traddr:    ra,\n\t\t\tstatus:   status,\n\t\t\tpid:      pid,\n\t\t})\n\t}\n\n\treturn ret, nil\n}\n\nfunc processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {\n\t// Read the contents of the /proc file with a single read sys call.\n\t// This minimizes duplicates in the returned connections\n\t// For more info:\n\t// https://github.com/shirou/gopsutil/pull/361\n\tcontents, err := os.ReadFile(file)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlines := bytes.Split(contents, []byte(\"\\n\"))\n\n\tvar ret []connTmp\n\t// skip first line\n\tfor _, line := range lines[1:] {\n\t\ttokens := strings.Fields(string(line))\n\t\tif len(tokens) < 6 {\n\t\t\tcontinue\n\t\t}\n\t\tst, err := strconv.ParseInt(tokens[4], 10, 32)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tinode := tokens[6]\n\n\t\tvar pairs []inodeMap\n\t\tpairs, exists := inodes[inode]\n\t\tif !exists {\n\t\t\tpairs = []inodeMap{\n\t\t\t\t{},\n\t\t\t}\n\t\t}\n\t\tfor _, pair := range pairs {\n\t\t\tif filterPid > 0 && filterPid != pair.pid {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar path string\n\t\t\tif len(tokens) == 8 {\n\t\t\t\tpath = tokens[len(tokens)-1]\n\t\t\t}\n\t\t\tret = append(ret, connTmp{\n\t\t\t\tfd:       pair.fd,\n\t\t\t\tfamily:   kind.family,\n\t\t\t\tsockType: uint32(st),\n\t\t\t\tladdr: Addr{\n\t\t\t\t\tIP: path,\n\t\t\t\t},\n\t\t\t\tpid:    pair.pid,\n\t\t\t\tstatus: \"NONE\",\n\t\t\t\tpath:   path,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n\nfunc updateMap(src, add map[string][]inodeMap) map[string][]inodeMap {\n\tfor key, value := range add {\n\t\ta, exists := src[key]\n\t\tif !exists {\n\t\t\tsrc[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tsrc[key] = append(a, value...)\n\t}\n\treturn src\n}\n"
  },
  {
    "path": "net/net_linux_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage net\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"syscall\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestIOCountersByFileParsing(t *testing.T) {\n\t// Prpare a temporary file, which will be read during the test\n\ttmpfile, err := os.CreateTemp(\"\", \"proc_dev_net\")\n\tdefer os.Remove(tmpfile.Name()) // clean up\n\n\trequire.NoErrorf(t, err, \"Temporary file creation failed: %s\", err)\n\n\tcases := [4][2]string{\n\t\t{\"eth0:   \", \"eth1:   \"},\n\t\t{\"eth0:0:   \", \"eth1:0:   \"},\n\t\t{\"eth0:\", \"eth1:\"},\n\t\t{\"eth0:0:\", \"eth1:0:\"},\n\t}\n\tfor _, testCase := range cases {\n\t\terr = tmpfile.Truncate(0)\n\t\trequire.NoErrorf(t, err, \"Temporary file truncating problem: %s\", err)\n\n\t\t// Parse interface name for assertion\n\t\tinterface0 := strings.TrimSpace(testCase[0])\n\t\tinterface0 = interface0[:len(interface0)-1]\n\n\t\tinterface1 := strings.TrimSpace(testCase[1])\n\t\tinterface1 = interface1[:len(interface1)-1]\n\n\t\t// Replace the interfaces from the test case\n\t\tproc := []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]))\n\n\t\t// Write /proc/net/dev sample output\n\t\t_, err = tmpfile.Write(proc)\n\t\trequire.NoErrorf(t, err, \"Temporary file writing failed: %s\", err)\n\n\t\tcounters, err := IOCountersByFile(true, tmpfile.Name())\n\n\t\trequire.NoError(t, err)\n\t\tassert.NotEmpty(t, counters)\n\t\tassert.Len(t, counters, 2)\n\t\tassert.Equal(t, interface0, counters[0].Name)\n\t\tassert.Equal(t, uint64(1), counters[0].BytesRecv)\n\t\tassert.Equal(t, uint64(2), counters[0].PacketsRecv)\n\t\tassert.Equal(t, uint64(3), counters[0].Errin)\n\t\tassert.Equal(t, uint64(4), counters[0].Dropin)\n\t\tassert.Equal(t, uint64(5), counters[0].Fifoin)\n\t\tassert.Equal(t, uint64(9), counters[0].BytesSent)\n\t\tassert.Equal(t, uint64(10), counters[0].PacketsSent)\n\t\tassert.Equal(t, uint64(11), counters[0].Errout)\n\t\tassert.Equal(t, uint64(12), counters[0].Dropout)\n\t\tassert.Equal(t, uint64(13), counters[0].Fifoout)\n\t\tassert.Equal(t, interface1, counters[1].Name)\n\t\tassert.Equal(t, uint64(100), counters[1].BytesRecv)\n\t\tassert.Equal(t, uint64(200), counters[1].PacketsRecv)\n\t\tassert.Equal(t, uint64(300), counters[1].Errin)\n\t\tassert.Equal(t, uint64(400), counters[1].Dropin)\n\t\tassert.Equal(t, uint64(500), counters[1].Fifoin)\n\t\tassert.Equal(t, uint64(900), counters[1].BytesSent)\n\t\tassert.Equal(t, uint64(1000), counters[1].PacketsSent)\n\t\tassert.Equal(t, uint64(1100), counters[1].Errout)\n\t\tassert.Equal(t, uint64(1200), counters[1].Dropout)\n\t\tassert.Equal(t, uint64(1300), counters[1].Fifoout)\n\t}\n\n\tassert.NoErrorf(t, tmpfile.Close(), \"Temporary file closing failed\")\n}\n\nfunc TestGetProcInodesAll(t *testing.T) {\n\twaitForServer := make(chan bool)\n\tgo func(t *testing.T) { // TCP listening goroutine to have some opened inodes even in CI\n\t\tt.Helper()\n\t\taddr, err := net.ResolveTCPAddr(\"tcp\", \"localhost:0\") // dynamically get a random open port from OS\n\t\tif err != nil {\n\t\t\tt.Skipf(\"unable to resolve localhost: %v\", err)\n\t\t}\n\t\tl, err := net.ListenTCP(addr.Network(), addr)\n\t\tif err != nil {\n\t\t\tt.Skipf(\"unable to listen on %v: %v\", addr, err)\n\t\t}\n\t\tdefer l.Close()\n\t\twaitForServer <- true\n\t\tfor {\n\t\t\tconn, err := l.Accept()\n\t\t\tif err != nil {\n\t\t\t\tt.Skipf(\"unable to accept connection: %v\", err)\n\t\t\t}\n\t\t\tdefer conn.Close()\n\t\t}\n\t}(t)\n\t<-waitForServer\n\n\tctx := context.Background()\n\troot := common.HostProcWithContext(ctx, \"\")\n\tv, err := getProcInodesAllWithContext(ctx, root, 0)\n\trequire.NoError(t, err)\n\tassert.NotEmpty(t, v)\n}\n\nfunc TestConnectionsMax(t *testing.T) {\n\tif os.Getenv(\"CI\") != \"\" {\n\t\tt.Skip(\"Skip CI\")\n\t}\n\n\tmaxConn := 10\n\tv, err := ConnectionsMax(\"tcp\", maxConn)\n\trequire.NoError(t, err)\n\tassert.NotEmpty(t, v)\n\n\tcxByPid := map[int32]int{}\n\tfor _, cx := range v {\n\t\tif cx.Pid > 0 {\n\t\t\tcxByPid[cx.Pid]++\n\t\t}\n\t}\n\tfor _, c := range cxByPid {\n\t\tassert.LessOrEqual(t, c, maxConn)\n\t}\n}\n\ntype AddrTest struct {\n\tIP    string\n\tPort  int\n\tError bool\n}\n\nfunc TestDecodeAddress(t *testing.T) {\n\taddr := map[string]AddrTest{\n\t\t\"11111:0035\": {\n\t\t\tError: true,\n\t\t},\n\t\t\"0100007F:BLAH\": {\n\t\t\tError: true,\n\t\t},\n\t\t\"0085002452100113070057A13F025401:0035\": {\n\t\t\tIP:   \"2400:8500:1301:1052:a157:7:154:23f\",\n\t\t\tPort: 53,\n\t\t},\n\t\t\"00855210011307F025401:0035\": {\n\t\t\tError: true,\n\t\t},\n\t}\n\tif common.IsLittleEndian() {\n\t\taddr[\"0500000A:0016\"] = AddrTest{\n\t\t\tIP:   \"10.0.0.5\",\n\t\t\tPort: 22,\n\t\t}\n\t\taddr[\"0100007F:D1C2\"] = AddrTest{\n\t\t\tIP:   \"127.0.0.1\",\n\t\t\tPort: 53698,\n\t\t}\n\t} else {\n\t\taddr[\"0A000005:0016\"] = AddrTest{\n\t\t\tIP:   \"10.0.0.5\",\n\t\t\tPort: 22,\n\t\t}\n\t\taddr[\"7F000001:D1C2\"] = AddrTest{\n\t\t\tIP:   \"127.0.0.1\",\n\t\t\tPort: 53698,\n\t\t}\n\t}\n\n\tfor src, dst := range addr {\n\t\tfamily := syscall.AF_INET\n\t\tif len(src) > 13 {\n\t\t\tfamily = syscall.AF_INET6\n\t\t}\n\t\taddr, err := decodeAddress(uint32(family), src)\n\t\tif dst.Error {\n\t\t\tassert.Errorf(t, err, src)\n\t\t} else {\n\t\t\trequire.NoErrorf(t, err, src)\n\t\t\tassert.Equalf(t, dst.IP, addr.IP, src)\n\t\t\tassert.Equalf(t, dst.Port, int(addr.Port), src)\n\t\t}\n\t}\n}\n\nfunc TestReverse(t *testing.T) {\n\tsrc := []byte{0x01, 0x02, 0x03}\n\tassert.Equal(t, []byte{0x03, 0x02, 0x01}, Reverse(src))\n}\n\nfunc TestConntrackStatFileParsing(t *testing.T) {\n\ttmpfile, err := os.CreateTemp(\"\", \"proc_net_stat_conntrack\")\n\tdefer os.Remove(tmpfile.Name())\n\trequire.NoErrorf(t, err, \"Temporary file creation failed: %s\", err)\n\n\tdata := []byte(`\nentries  searched found new invalid ignore delete deleteList insert insertFailed drop earlyDrop icmpError  expectNew expectCreate expectDelete searchRestart\n0000007b  00000000 00000000 00000000 000b115a 00000084 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 0000004a\n0000007b  00000000 00000000 00000000 0007eee5 00000068 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000035\n0000007b  00000000 00000000 00000000 0090346b 00000057 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000025\n0000007b  00000000 00000000 00000000 0005920f 00000069 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000064\n0000007b  00000000 00000000 00000000 000331ff 00000059 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 0000003b\n0000007b  00000000 00000000 00000000 000314ea 00000066 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000054\n0000007b  00000000 00000000 00000000 0002b270 00000055 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 0000003d\n0000007b  00000000 00000000 00000000 0002f67d 00000057 00000000 00000000 00000000 00000000 00000000 00000000 00000000  00000000 00000000 00000000 00000042\n`)\n\n\t// Expected results\n\tslist := NewConntrackStatList()\n\n\tslist.Append(&ConntrackStat{\n\t\tEntries:       123,\n\t\tSearched:      0,\n\t\tFound:         0,\n\t\tNew:           0,\n\t\tInvalid:       725338,\n\t\tIgnore:        132,\n\t\tDelete:        0,\n\t\tDeleteList:    0,\n\t\tInsert:        0,\n\t\tInsertFailed:  0,\n\t\tDrop:          0,\n\t\tEarlyDrop:     0,\n\t\tIcmpError:     0,\n\t\tExpectNew:     0,\n\t\tExpectCreate:  0,\n\t\tExpectDelete:  0,\n\t\tSearchRestart: 74,\n\t})\n\tslist.Append(&ConntrackStat{123, 0, 0, 0, 519909, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53})\n\n\tslist.Append(&ConntrackStat{123, 0, 0, 0, 9450603, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37})\n\tslist.Append(&ConntrackStat{123, 0, 0, 0, 365071, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100})\n\n\tslist.Append(&ConntrackStat{123, 0, 0, 0, 209407, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59})\n\tslist.Append(&ConntrackStat{123, 0, 0, 0, 201962, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84})\n\n\tslist.Append(&ConntrackStat{123, 0, 0, 0, 176752, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61})\n\tslist.Append(&ConntrackStat{123, 0, 0, 0, 194173, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66})\n\n\t// Write data to tempfile\n\t_, err = tmpfile.Write(data)\n\trequire.NoErrorf(t, err, \"Temporary file writing failed: %s\", err)\n\n\t// Function under test\n\tstats, err := conntrackStatsFromFile(tmpfile.Name(), true)\n\trequire.NoError(t, err)\n\tassert.Lenf(t, stats, 8, \"Expected 8 results\")\n\n\tsummary := &ConntrackStat{}\n\tfor i, exp := range slist.Items() {\n\t\tst := stats[i]\n\n\t\tassert.Equal(t, exp.Entries, st.Entries)\n\t\tsummary.Entries += st.Entries\n\n\t\tassert.Equal(t, exp.Searched, st.Searched)\n\t\tsummary.Searched += st.Searched\n\n\t\tassert.Equal(t, exp.Found, st.Found)\n\t\tsummary.Found += st.Found\n\n\t\tassert.Equal(t, exp.New, st.New)\n\t\tsummary.New += st.New\n\n\t\tassert.Equal(t, exp.Invalid, st.Invalid)\n\t\tsummary.Invalid += st.Invalid\n\n\t\tassert.Equal(t, exp.Ignore, st.Ignore)\n\t\tsummary.Ignore += st.Ignore\n\n\t\tassert.Equal(t, exp.Delete, st.Delete)\n\t\tsummary.Delete += st.Delete\n\n\t\tassert.Equal(t, exp.DeleteList, st.DeleteList)\n\t\tsummary.DeleteList += st.DeleteList\n\n\t\tassert.Equal(t, exp.Insert, st.Insert)\n\t\tsummary.Insert += st.Insert\n\n\t\tassert.Equal(t, exp.InsertFailed, st.InsertFailed)\n\t\tsummary.InsertFailed += st.InsertFailed\n\n\t\tassert.Equal(t, exp.Drop, st.Drop)\n\t\tsummary.Drop += st.Drop\n\n\t\tassert.Equal(t, exp.EarlyDrop, st.EarlyDrop)\n\t\tsummary.EarlyDrop += st.EarlyDrop\n\n\t\tassert.Equal(t, exp.IcmpError, st.IcmpError)\n\t\tsummary.IcmpError += st.IcmpError\n\n\t\tassert.Equal(t, exp.ExpectNew, st.ExpectNew)\n\t\tsummary.ExpectNew += st.ExpectNew\n\n\t\tassert.Equal(t, exp.ExpectCreate, st.ExpectCreate)\n\t\tsummary.ExpectCreate += st.ExpectCreate\n\n\t\tassert.Equal(t, exp.ExpectDelete, st.ExpectDelete)\n\t\tsummary.ExpectDelete += st.ExpectDelete\n\n\t\tassert.Equal(t, exp.SearchRestart, st.SearchRestart)\n\t\tsummary.SearchRestart += st.SearchRestart\n\t}\n\n\t// Test summary grouping\n\ttotals, err := conntrackStatsFromFile(tmpfile.Name(), false)\n\trequire.NoError(t, err)\n\tfor i, st := range totals {\n\t\tassert.Equal(t, summary.Entries, st.Entries)\n\t\tassert.Equal(t, summary.Searched, st.Searched)\n\t\tassert.Equal(t, summary.Found, st.Found)\n\t\tassert.Equal(t, summary.New, st.New)\n\t\tassert.Equal(t, summary.Invalid, st.Invalid)\n\t\tassert.Equal(t, summary.Ignore, st.Ignore)\n\t\tassert.Equal(t, summary.Delete, st.Delete)\n\t\tassert.Equal(t, summary.DeleteList, st.DeleteList)\n\t\tassert.Equal(t, summary.Insert, st.Insert)\n\t\tassert.Equal(t, summary.InsertFailed, st.InsertFailed)\n\t\tassert.Equal(t, summary.Drop, st.Drop)\n\t\tassert.Equal(t, summary.EarlyDrop, st.EarlyDrop)\n\t\tassert.Equal(t, summary.IcmpError, st.IcmpError)\n\t\tassert.Equal(t, summary.ExpectNew, st.ExpectNew)\n\t\tassert.Equal(t, summary.ExpectCreate, st.ExpectCreate)\n\t\tassert.Equal(t, summary.ExpectDelete, st.ExpectDelete)\n\t\tassert.Equal(t, summary.SearchRestart, st.SearchRestart)\n\n\t\tassert.Equal(t, 0, i) // Should only have one element\n\t}\n}\n"
  },
  {
    "path": "net/net_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage net\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar portMatch = regexp.MustCompile(`(.*)\\.(\\d+)$`)\n\nfunc ParseNetstat(output string, mode string,\n\tiocs map[string]IOCountersStat,\n) error {\n\tlines := strings.Split(output, \"\\n\")\n\n\texists := make([]string, 0, len(lines)-1)\n\n\tcolumns := 9\n\tif mode == \"inb\" {\n\t\tcolumns = 6\n\t}\n\tfor _, line := range lines {\n\t\tvalues := strings.Fields(line)\n\t\tif len(values) < 1 || values[0] == \"Name\" {\n\t\t\tcontinue\n\t\t}\n\t\tif common.StringsHas(exists, values[0]) {\n\t\t\t// skip if already get\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(values) < columns {\n\t\t\tcontinue\n\t\t}\n\t\tbase := 1\n\t\t// sometimes Address is omitted\n\t\tif len(values) < columns {\n\t\t\tbase = 0\n\t\t}\n\n\t\tparsed := make([]uint64, 0, 8)\n\t\tvar vv []string\n\t\tswitch mode {\n\t\tcase \"inb\":\n\t\t\tvv = []string{\n\t\t\t\tvalues[base+3], // BytesRecv\n\t\t\t\tvalues[base+4], // BytesSent\n\t\t\t}\n\t\tcase \"ind\":\n\t\t\tvv = []string{\n\t\t\t\tvalues[base+3], // Ipkts\n\t\t\t\tvalues[base+4], // Idrop\n\t\t\t\tvalues[base+5], // Opkts\n\t\t\t\tvalues[base+6], // Odrops\n\t\t\t}\n\t\tcase \"ine\":\n\t\t\tvv = []string{\n\t\t\t\tvalues[base+4], // Ierrs\n\t\t\t\tvalues[base+6], // Oerrs\n\t\t\t}\n\t\t}\n\t\tfor _, target := range vv {\n\t\t\tif target == \"-\" {\n\t\t\t\tparsed = append(parsed, 0)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tt, err := strconv.ParseUint(target, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tparsed = append(parsed, t)\n\t\t}\n\t\texists = append(exists, values[0])\n\n\t\tn, present := iocs[values[0]]\n\t\tif !present {\n\t\t\tn = IOCountersStat{Name: values[0]}\n\t\t}\n\n\t\tswitch mode {\n\t\tcase \"inb\":\n\t\t\tn.BytesRecv = parsed[0]\n\t\t\tn.BytesSent = parsed[1]\n\t\tcase \"ind\":\n\t\t\tn.PacketsRecv = parsed[0]\n\t\t\tn.Dropin = parsed[1]\n\t\t\tn.PacketsSent = parsed[2]\n\t\t\tn.Dropout = parsed[3]\n\t\tcase \"ine\":\n\t\t\tn.Errin = parsed[0]\n\t\t\tn.Errout = parsed[1]\n\t\t}\n\n\t\tiocs[n.Name] = n\n\t}\n\treturn nil\n}\n\n// Deprecated: use process.PidsWithContext instead\nfunc PidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {\n\tnetstat, err := exec.LookPath(\"netstat\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tout, err := invoke.CommandWithContext(ctx, netstat, \"-inb\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tout2, err := invoke.CommandWithContext(ctx, netstat, \"-ind\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tout3, err := invoke.CommandWithContext(ctx, netstat, \"-ine\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tiocs := make(map[string]IOCountersStat)\n\n\tlines := strings.Split(string(out), \"\\n\")\n\tret := make([]IOCountersStat, 0, len(lines)-1)\n\n\terr = ParseNetstat(string(out), \"inb\", iocs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = ParseNetstat(string(out2), \"ind\", iocs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = ParseNetstat(string(out3), \"ine\", iocs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, ioc := range iocs {\n\t\tret = append(ret, ioc)\n\t}\n\n\tif !pernic {\n\t\treturn getIOCountersAll(ret), nil\n\t}\n\n\treturn ret, nil\n}\n\nfunc IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {\n\treturn IOCountersWithContext(ctx, pernic)\n}\n\nfunc FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc parseNetstatLine(line string) (ConnectionStat, error) {\n\tf := strings.Fields(line)\n\tif len(f) < 5 {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"wrong line,%s\", line)\n\t}\n\n\tvar netType, netFamily uint32\n\tswitch f[0] {\n\tcase \"tcp\":\n\t\tnetType = syscall.SOCK_STREAM\n\t\tnetFamily = syscall.AF_INET\n\tcase \"udp\":\n\t\tnetType = syscall.SOCK_DGRAM\n\t\tnetFamily = syscall.AF_INET\n\tcase \"tcp6\":\n\t\tnetType = syscall.SOCK_STREAM\n\t\tnetFamily = syscall.AF_INET6\n\tcase \"udp6\":\n\t\tnetType = syscall.SOCK_DGRAM\n\t\tnetFamily = syscall.AF_INET6\n\tdefault:\n\t\treturn ConnectionStat{}, fmt.Errorf(\"unknown type, %s\", f[0])\n\t}\n\n\tladdr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)\n\tif err != nil {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"failed to parse netaddr, %s %s\", f[3], f[4])\n\t}\n\n\tn := ConnectionStat{\n\t\tFd:     uint32(0), // not supported\n\t\tFamily: uint32(netFamily),\n\t\tType:   uint32(netType),\n\t\tLaddr:  laddr,\n\t\tRaddr:  raddr,\n\t\tPid:    int32(0), // not supported\n\t}\n\tif len(f) == 6 {\n\t\tn.Status = f[5]\n\t}\n\n\treturn n, nil\n}\n\nfunc parseAddr(l string, family uint32) (Addr, error) {\n\tmatches := portMatch.FindStringSubmatch(l)\n\tif matches == nil {\n\t\treturn Addr{}, fmt.Errorf(\"wrong addr, %s\", l)\n\t}\n\thost := matches[1]\n\tport := matches[2]\n\tif host == \"*\" {\n\t\tswitch family {\n\t\tcase syscall.AF_INET:\n\t\t\thost = \"0.0.0.0\"\n\t\tcase syscall.AF_INET6:\n\t\t\thost = \"::\"\n\t\tdefault:\n\t\t\treturn Addr{}, fmt.Errorf(\"unknown family, %d\", family)\n\t\t}\n\t}\n\tlport, err := strconv.ParseInt(port, 10, 32)\n\tif err != nil {\n\t\treturn Addr{}, err\n\t}\n\treturn Addr{IP: host, Port: uint32(lport)}, nil\n}\n\nfunc parseNetstatAddr(local, remote string, family uint32) (laddr, raddr Addr, err error) {\n\tladdr, err = parseAddr(local, family)\n\tif remote != \"*.*\" { // remote addr exists\n\t\traddr, err = parseAddr(remote, family)\n\t\tif err != nil {\n\t\t\treturn laddr, raddr, err\n\t\t}\n\t}\n\n\treturn laddr, raddr, err\n}\n\nfunc ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\tvar ret []ConnectionStat\n\n\targs := []string{\"-na\"}\n\tswitch strings.ToLower(kind) {\n\tdefault:\n\t\tfallthrough\n\tcase \"\", \"all\", \"inet\":\n\t\t// nothing to add\n\tcase \"inet4\":\n\t\targs = append(args, \"-finet\")\n\tcase \"inet6\":\n\t\targs = append(args, \"-finet6\")\n\tcase \"tcp\":\n\t\targs = append(args, \"-ptcp\")\n\tcase \"tcp4\":\n\t\targs = append(args, \"-ptcp\", \"-finet\")\n\tcase \"tcp6\":\n\t\targs = append(args, \"-ptcp\", \"-finet6\")\n\tcase \"udp\":\n\t\targs = append(args, \"-pudp\")\n\tcase \"udp4\":\n\t\targs = append(args, \"-pudp\", \"-finet\")\n\tcase \"udp6\":\n\t\targs = append(args, \"-pudp\", \"-finet6\")\n\tcase \"unix\":\n\t\treturn ret, common.ErrNotImplementedError\n\t}\n\n\tnetstat, err := exec.LookPath(\"netstat\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tout, err := invoke.CommandWithContext(ctx, netstat, args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\tfor _, line := range lines {\n\t\tif !strings.HasPrefix(line, \"tcp\") && !strings.HasPrefix(line, \"udp\") {\n\t\t\tcontinue\n\t\t}\n\t\tn, err := parseNetstatLine(line)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, n)\n\t}\n\n\treturn ret, nil\n}\n\nfunc ConnectionsPidWithContext(_ context.Context, _ string, _ int32) ([]ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConnectionsMaxWithContext(_ context.Context, _ string, _ int) ([]ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConnectionsPidMaxWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn)\n}\n\nfunc connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "net/net_solaris.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build solaris\n\npackage net\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar kstatSplit = regexp.MustCompile(`[:\\s]+`)\n\nfunc IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {\n\t// collect all the net class's links with below statistics\n\tfilterstr := \"/^(?!vnic)/::phys:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/\"\n\tif runtime.GOOS == \"illumos\" {\n\t\tfilterstr = \"/[^vnic]/::mac:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/\"\n\t}\n\tkstatSysOut, err := invoke.CommandWithContext(ctx, \"kstat\", \"-c\", \"net\", \"-p\", filterstr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot execute kstat: %w\", err)\n\t}\n\n\tlines := strings.Split(strings.TrimSpace(string(kstatSysOut)), \"\\n\")\n\tif len(lines) == 0 {\n\t\treturn nil, errors.New(\"no interface found\")\n\t}\n\trbytes64arr := make(map[string]uint64)\n\tipackets64arr := make(map[string]uint64)\n\tidrops64arr := make(map[string]uint64)\n\tierrorsarr := make(map[string]uint64)\n\tobytes64arr := make(map[string]uint64)\n\topackets64arr := make(map[string]uint64)\n\todrops64arr := make(map[string]uint64)\n\toerrorsarr := make(map[string]uint64)\n\n\tfor _, line := range lines {\n\t\tfields := kstatSplit.Split(line, -1)\n\t\tinterfaceName := fields[0]\n\t\tinstance := fields[1]\n\t\tswitch fields[3] {\n\t\tcase \"rbytes64\":\n\t\t\trbytes64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse rbytes64: %w\", err)\n\t\t\t}\n\t\tcase \"ipackets64\":\n\t\t\tipackets64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse ipackets64: %w\", err)\n\t\t\t}\n\t\tcase \"idrops64\":\n\t\t\tidrops64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse idrops64: %w\", err)\n\t\t\t}\n\t\tcase \"ierrors\":\n\t\t\tierrorsarr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse ierrors: %w\", err)\n\t\t\t}\n\t\tcase \"obytes64\":\n\t\t\tobytes64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse obytes64: %w\", err)\n\t\t\t}\n\t\tcase \"opackets64\":\n\t\t\topackets64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse opackets64: %w\", err)\n\t\t\t}\n\t\tcase \"odrops64\":\n\t\t\todrops64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse odrops64: %w\", err)\n\t\t\t}\n\t\tcase \"oerrors\":\n\t\t\toerrorsarr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"cannot parse oerrors: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\tret := make([]IOCountersStat, 0)\n\tfor k := range rbytes64arr {\n\t\tnic := IOCountersStat{\n\t\t\tName:        k,\n\t\t\tBytesRecv:   rbytes64arr[k],\n\t\t\tPacketsRecv: ipackets64arr[k],\n\t\t\tErrin:       ierrorsarr[k],\n\t\t\tDropin:      idrops64arr[k],\n\t\t\tBytesSent:   obytes64arr[k],\n\t\t\tPacketsSent: opackets64arr[k],\n\t\t\tErrout:      oerrorsarr[k],\n\t\t\tDropout:     odrops64arr[k],\n\t\t}\n\t\tret = append(ret, nic)\n\t}\n\n\tif !pernic {\n\t\treturn getIOCountersAll(ret), nil\n\t}\n\n\treturn ret, nil\n}\n\nfunc IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {\n\treturn IOCountersWithContext(ctx, pernic)\n}\n\nfunc FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\n// Deprecated: use process.PidsWithContext instead\nfunc PidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConnectionsWithContext(_ context.Context, _ string) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n\nfunc ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)\n}\n\nfunc ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)\n}\n\nfunc connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "net/net_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage net\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestAddrString(t *testing.T) {\n\tv := Addr{IP: \"192.168.0.1\", Port: 8000}\n\n\ts := v.String()\n\tassert.JSONEqf(t, `{\"ip\":\"192.168.0.1\",\"port\":8000}`, s, \"Addr string is invalid: %v\", v)\n}\n\nfunc TestIOCountersStatString(t *testing.T) {\n\tv := IOCountersStat{\n\t\tName:      \"test\",\n\t\tBytesSent: 100,\n\t}\n\te := `{\"name\":\"test\",\"bytesSent\":100,\"bytesRecv\":0,\"packetsSent\":0,\"packetsRecv\":0,\"errin\":0,\"errout\":0,\"dropin\":0,\"dropout\":0,\"fifoin\":0,\"fifoout\":0}`\n\tassert.JSONEqf(t, e, v.String(), \"NetIOCountersStat string is invalid: %v\", v)\n}\n\nfunc TestProtoCountersStatString(t *testing.T) {\n\tv := ProtoCountersStat{\n\t\tProtocol: \"tcp\",\n\t\tStats: map[string]int64{\n\t\t\t\"MaxConn\":      -1,\n\t\t\t\"ActiveOpens\":  4000,\n\t\t\t\"PassiveOpens\": 3000,\n\t\t},\n\t}\n\te := `{\"protocol\":\"tcp\",\"stats\":{\"ActiveOpens\":4000,\"MaxConn\":-1,\"PassiveOpens\":3000}}`\n\tassert.JSONEqf(t, e, v.String(), \"NetProtoCountersStat string is invalid: %v\", v)\n}\n\nfunc TestConnectionStatString(t *testing.T) {\n\tv := ConnectionStat{\n\t\tFd:     10,\n\t\tFamily: 10,\n\t\tType:   10,\n\t\tUids:   []int32{10, 10},\n\t}\n\te := `{\"fd\":10,\"family\":10,\"type\":10,\"localaddr\":{\"ip\":\"\",\"port\":0},\"remoteaddr\":{\"ip\":\"\",\"port\":0},\"status\":\"\",\"uids\":[10,10],\"pid\":0}`\n\tassert.JSONEqf(t, e, v.String(), \"NetConnectionStat string is invalid: %v\", v)\n}\n\nfunc TestIOCountersAll(t *testing.T) {\n\tv, err := IOCounters(false)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"Could not get NetIOCounters: %v\", err)\n\tper, err := IOCounters(true)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"Could not get NetIOCounters: %v\", err)\n\tassert.Lenf(t, v, 1, \"Could not get NetIOCounters: %v\", v)\n\tassert.Equalf(t, \"all\", v[0].Name, \"Invalid NetIOCounters: %v\", v)\n\tvar pr uint64\n\tfor _, p := range per {\n\t\tpr += p.PacketsRecv\n\t}\n\t// small diff is ok, compare instead of math.Abs(subtraction) with uint64\n\tvar diff uint64\n\tif v[0].PacketsRecv > pr {\n\t\tdiff = v[0].PacketsRecv - pr\n\t} else {\n\t\tdiff = pr - v[0].PacketsRecv\n\t}\n\tif diff > 5 {\n\t\tif ci := os.Getenv(\"CI\"); ci != \"\" {\n\t\t\t// This test often fails in CI. so just print even if failed.\n\t\t\tfmt.Printf(\"invalid sum value: %v, %v\", v[0].PacketsRecv, pr)\n\t\t} else {\n\t\t\tt.Errorf(\"invalid sum value: %v, %v\", v[0].PacketsRecv, pr)\n\t\t}\n\t}\n}\n\nfunc TestIOCountersPerNic(t *testing.T) {\n\tv, err := IOCounters(true)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"Could not get NetIOCounters: %v\", err)\n\tassert.NotEmptyf(t, v, \"Could not get NetIOCounters: %v\", v)\n\tfor _, vv := range v {\n\t\tassert.NotEmptyf(t, vv.Name, \"Invalid NetIOCounters: %v\", vv)\n\t}\n}\n\nfunc TestGetNetIOCountersAll(t *testing.T) {\n\tn := []IOCountersStat{\n\t\t{\n\t\t\tName:        \"a\",\n\t\t\tBytesRecv:   10,\n\t\t\tPacketsRecv: 10,\n\t\t},\n\t\t{\n\t\t\tName:        \"b\",\n\t\t\tBytesRecv:   10,\n\t\t\tPacketsRecv: 10,\n\t\t\tErrin:       10,\n\t\t},\n\t}\n\tret := getIOCountersAll(n)\n\tassert.Lenf(t, ret, 1, \"invalid return count\")\n\tassert.Equalf(t, \"all\", ret[0].Name, \"invalid return name\")\n\tassert.Equalf(t, uint64(20), ret[0].BytesRecv, \"invalid count bytesrecv\")\n\tassert.Equalf(t, uint64(10), ret[0].Errin, \"invalid count errin\")\n}\n\nfunc TestInterfaces(t *testing.T) {\n\tv, err := Interfaces()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"Could not get NetInterfaceStat: %v\", err)\n\tassert.NotEmptyf(t, v, \"Could not get NetInterfaceStat: %v\", err)\n\tfor _, vv := range v {\n\t\tassert.NotEmptyf(t, vv.Name, \"Invalid NetInterface: %v\", vv)\n\t}\n}\n\nfunc TestProtoCountersStatsAll(t *testing.T) {\n\tv, err := ProtoCounters(nil)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"Could not get NetProtoCounters: %v\", err)\n\trequire.NotEmptyf(t, v, \"Could not get NetProtoCounters: %v\", err)\n\tfor _, vv := range v {\n\t\tassert.NotEmptyf(t, vv.Protocol, \"Invalid NetProtoCountersStat: %v\", vv)\n\t\tassert.NotEmptyf(t, vv.Stats, \"Invalid NetProtoCountersStat: %v\", vv)\n\t}\n}\n\nfunc TestProtoCountersStats(t *testing.T) {\n\tv, err := ProtoCounters([]string{\"tcp\", \"ip\"})\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"Could not get NetProtoCounters: %v\", err)\n\trequire.NotEmptyf(t, v, \"Could not get NetProtoCounters: %v\", err)\n\trequire.Lenf(t, v, 2, \"Go incorrect number of NetProtoCounters: %v\", err)\n\tfor _, vv := range v {\n\t\tif vv.Protocol != \"tcp\" && vv.Protocol != \"ip\" {\n\t\t\tt.Errorf(\"Invalid NetProtoCountersStat: %v\", vv)\n\t\t}\n\t\tassert.NotEmptyf(t, vv.Stats, \"Invalid NetProtoCountersStat: %v\", vv)\n\t}\n}\n\nfunc TestConnections(t *testing.T) {\n\tif ci := os.Getenv(\"CI\"); ci != \"\" { // skip if test on CI\n\t\treturn\n\t}\n\n\tv, err := Connections(\"inet\")\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"could not get NetConnections: %v\", err)\n\tassert.NotEmptyf(t, v, \"could not get NetConnections: %v\", v)\n\tfor _, vv := range v {\n\t\tassert.NotZerof(t, vv.Family, \"invalid NetConnections: %v\", vv)\n\t}\n}\n\nfunc TestFilterCounters(t *testing.T) {\n\tif ci := os.Getenv(\"CI\"); ci != \"\" { // skip if test on CI\n\t\treturn\n\t}\n\n\tif runtime.GOOS == \"linux\" {\n\t\t// some test environment has not the path.\n\t\tif !common.PathExists(\"/proc/sys/net/netfilter/nf_connTrackCount\") {\n\t\t\tt.SkipNow()\n\t\t}\n\t}\n\n\tv, err := FilterCounters()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"could not get NetConnections: %v\", err)\n\tassert.NotEmptyf(t, v, \"could not get NetConnections: %v\", v)\n\tfor _, vv := range v {\n\t\tassert.NotZerof(t, vv.ConnTrackMax, \"nf_connTrackMax needs to be greater than zero: %v\", vv)\n\t}\n}\n\nfunc TestInterfaceStatString(t *testing.T) {\n\tv := InterfaceStat{\n\t\tIndex:        0,\n\t\tMTU:          1500,\n\t\tName:         \"eth0\",\n\t\tHardwareAddr: \"01:23:45:67:89:ab\",\n\t\tFlags:        []string{\"up\", \"down\"},\n\t\tAddrs:        InterfaceAddrList{{Addr: \"1.2.3.4\"}, {Addr: \"5.6.7.8\"}},\n\t}\n\n\ts := v.String()\n\tassert.JSONEqf(t, `{\"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\"}]}`, s, \"InterfaceStat string is invalid: %v\", s)\n\n\tlist := InterfaceStatList{v, v}\n\ts = list.String()\n\tassert.JSONEqf(t, `[{\"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\"}]}]`, s, \"InterfaceStatList string is invalid: %v\", s)\n}\n"
  },
  {
    "path": "net/net_unix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd || darwin\n\npackage net\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsPidWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithContext(_ context.Context, _ string, _ int) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n\nfunc ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\tvar ret []ConnectionStat\n\n\targs := []string{\"-i\"}\n\tswitch strings.ToLower(kind) {\n\tdefault:\n\t\tfallthrough\n\tcase \"\", \"all\", \"inet\":\n\t\targs = append(args, \"tcp\", \"-i\", \"udp\")\n\tcase \"inet4\":\n\t\targs = append(args, \"4\")\n\tcase \"inet6\":\n\t\targs = append(args, \"6\")\n\tcase \"tcp\":\n\t\targs = append(args, \"tcp\")\n\tcase \"tcp4\":\n\t\targs = append(args, \"4tcp\")\n\tcase \"tcp6\":\n\t\targs = append(args, \"6tcp\")\n\tcase \"udp\":\n\t\targs = append(args, \"udp\")\n\tcase \"udp4\":\n\t\targs = append(args, \"4udp\")\n\tcase \"udp6\":\n\t\targs = append(args, \"6udp\")\n\tcase \"unix\":\n\t\targs = []string{\"-U\"}\n\t}\n\n\tr, err := common.CallLsofWithContext(ctx, invoke, pid, args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, rr := range r {\n\t\tif strings.HasPrefix(rr, \"COMMAND\") {\n\t\t\tcontinue\n\t\t}\n\t\tn, err := parseNetLine(rr)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tret = append(ret, n)\n\t}\n\n\treturn ret, nil\n}\n\nvar constMap = map[string]int{\n\t\"unix\": syscall.AF_UNIX,\n\t\"TCP\":  syscall.SOCK_STREAM,\n\t\"UDP\":  syscall.SOCK_DGRAM,\n\t\"IPv4\": syscall.AF_INET,\n\t\"IPv6\": syscall.AF_INET6,\n}\n\nfunc parseNetLine(line string) (ConnectionStat, error) {\n\tf := strings.Fields(line)\n\tif len(f) < 8 {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"wrong line,%s\", line)\n\t}\n\n\tif len(f) == 8 {\n\t\tf = append(f, f[7])\n\t\tf[7] = \"unix\"\n\t}\n\n\tpid, err := strconv.ParseInt(f[1], 10, 32)\n\tif err != nil {\n\t\treturn ConnectionStat{}, err\n\t}\n\tfd, err := strconv.ParseInt(strings.Trim(f[3], \"u\"), 10, 32)\n\tif err != nil {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"unknown fd, %s\", f[3])\n\t}\n\tnetFamily, ok := constMap[f[4]]\n\tif !ok {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"unknown family, %s\", f[4])\n\t}\n\tnetType, ok := constMap[f[7]]\n\tif !ok {\n\t\treturn ConnectionStat{}, fmt.Errorf(\"unknown type, %s\", f[7])\n\t}\n\n\tvar laddr, raddr Addr\n\tif f[7] == \"unix\" {\n\t\tladdr.IP = f[8]\n\t} else {\n\t\tladdr, raddr, err = parseNetAddr(f[8])\n\t\tif err != nil {\n\t\t\treturn ConnectionStat{}, fmt.Errorf(\"failed to parse netaddr, %s\", f[8])\n\t\t}\n\t}\n\n\tn := ConnectionStat{\n\t\tFd:     uint32(fd),\n\t\tFamily: uint32(netFamily),\n\t\tType:   uint32(netType),\n\t\tLaddr:  laddr,\n\t\tRaddr:  raddr,\n\t\tPid:    int32(pid),\n\t}\n\tif len(f) == 10 {\n\t\tn.Status = strings.Trim(f[9], \"()\")\n\t}\n\n\treturn n, nil\n}\n\nfunc parseAddr(l string) (Addr, error) {\n\thost, port, err := net.SplitHostPort(l)\n\tif err != nil {\n\t\treturn Addr{}, fmt.Errorf(\"wrong addr, %s\", l)\n\t}\n\tlport, err := strconv.ParseInt(port, 10, 32)\n\tif err != nil {\n\t\treturn Addr{}, err\n\t}\n\treturn Addr{IP: host, Port: uint32(lport)}, nil\n}\n\nfunc parseNetAddr(line string) (laddr, raddr Addr, err error) {\n\taddrs := strings.Split(line, \"->\")\n\tif len(addrs) == 0 {\n\t\treturn laddr, raddr, fmt.Errorf(\"wrong netaddr, %s\", line)\n\t}\n\tladdr, err = parseAddr(addrs[0])\n\tif len(addrs) == 2 { // remote addr exists\n\t\traddr, err = parseAddr(addrs[1])\n\t\tif err != nil {\n\t\t\treturn laddr, raddr, err\n\t\t}\n\t}\n\n\treturn laddr, raddr, err\n}\n\nfunc ConnectionsPidMaxWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n\nfunc ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn)\n}\n\nfunc connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "net/net_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage net\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar (\n\tmodiphlpapi             = windows.NewLazySystemDLL(\"iphlpapi.dll\")\n\tprocGetExtendedTCPTable = modiphlpapi.NewProc(\"GetExtendedTcpTable\")\n\tprocGetExtendedUDPTable = modiphlpapi.NewProc(\"GetExtendedUdpTable\")\n\tprocGetIfEntry2         = modiphlpapi.NewProc(\"GetIfEntry2\")\n)\n\nconst (\n\tTCPTableBasicListener = iota\n\tTCPTableBasicConnections\n\tTCPTableBasicAll\n\tTCPTableOwnerPIDListener\n\tTCPTableOwnerPIDConnections\n\tTCPTableOwnerPIDAll\n\tTCPTableOwnerModuleListener\n\tTCPTableOwnerModuleConnections\n\tTCPTableOwnerModuleAll\n)\n\ntype netConnectionKindType struct {\n\tfamily   uint32\n\tsockType uint32\n\tfilename string\n}\n\nvar kindTCP4 = netConnectionKindType{\n\tfamily:   syscall.AF_INET,\n\tsockType: syscall.SOCK_STREAM,\n\tfilename: \"tcp\",\n}\n\nvar kindTCP6 = netConnectionKindType{\n\tfamily:   syscall.AF_INET6,\n\tsockType: syscall.SOCK_STREAM,\n\tfilename: \"tcp6\",\n}\n\nvar kindUDP4 = netConnectionKindType{\n\tfamily:   syscall.AF_INET,\n\tsockType: syscall.SOCK_DGRAM,\n\tfilename: \"udp\",\n}\n\nvar kindUDP6 = netConnectionKindType{\n\tfamily:   syscall.AF_INET6,\n\tsockType: syscall.SOCK_DGRAM,\n\tfilename: \"udp6\",\n}\n\nvar netConnectionKindMap = map[string][]netConnectionKindType{\n\t\"all\":   {kindTCP4, kindTCP6, kindUDP4, kindUDP6},\n\t\"tcp\":   {kindTCP4, kindTCP6},\n\t\"tcp4\":  {kindTCP4},\n\t\"tcp6\":  {kindTCP6},\n\t\"udp\":   {kindUDP4, kindUDP6},\n\t\"udp4\":  {kindUDP4},\n\t\"udp6\":  {kindUDP6},\n\t\"inet\":  {kindTCP4, kindTCP6, kindUDP4, kindUDP6},\n\t\"inet4\": {kindTCP4, kindUDP4},\n\t\"inet6\": {kindTCP6, kindUDP6},\n}\n\n// https://github.com/microsoft/ethr/blob/aecdaf923970e5a9b4c461b4e2e3963d781ad2cc/plt_windows.go#L114-L170\ntype guid struct {\n\tData1 uint32\n\tData2 uint16\n\tData3 uint16\n\tData4 [8]byte\n}\n\nconst (\n\tmaxStringSize        = 256\n\tmaxPhysAddressLength = 32\n\tpad0for64_4for32     = 0\n)\n\ntype mibIfRow2 struct {\n\tInterfaceLuid               uint64\n\tInterfaceIndex              uint32\n\tInterfaceGuid               guid //nolint:revive //FIXME\n\tAlias                       [maxStringSize + 1]uint16\n\tDescription                 [maxStringSize + 1]uint16\n\tPhysicalAddressLength       uint32\n\tPhysicalAddress             [maxPhysAddressLength]uint8\n\tPermanentPhysicalAddress    [maxPhysAddressLength]uint8\n\tMtu                         uint32\n\tType                        uint32\n\tTunnelType                  uint32\n\tMediaType                   uint32\n\tPhysicalMediumType          uint32\n\tAccessType                  uint32\n\tDirectionType               uint32\n\tInterfaceAndOperStatusFlags uint32\n\tOperStatus                  uint32\n\tAdminStatus                 uint32\n\tMediaConnectState           uint32\n\tNetworkGuid                 guid //nolint:revive //FIXME\n\tConnectionType              uint32\n\tpadding1                    [pad0for64_4for32]byte\n\tTransmitLinkSpeed           uint64\n\tReceiveLinkSpeed            uint64\n\tInOctets                    uint64\n\tInUcastPkts                 uint64\n\tInNUcastPkts                uint64\n\tInDiscards                  uint64\n\tInErrors                    uint64\n\tInUnknownProtos             uint64\n\tInUcastOctets               uint64\n\tInMulticastOctets           uint64\n\tInBroadcastOctets           uint64\n\tOutOctets                   uint64\n\tOutUcastPkts                uint64\n\tOutNUcastPkts               uint64\n\tOutDiscards                 uint64\n\tOutErrors                   uint64\n\tOutUcastOctets              uint64\n\tOutMulticastOctets          uint64\n\tOutBroadcastOctets          uint64\n\tOutQLen                     uint64\n}\n\nfunc IOCountersWithContext(_ context.Context, pernic bool) ([]IOCountersStat, error) {\n\tifs, err := net.Interfaces()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar counters []IOCountersStat\n\n\terr = procGetIfEntry2.Find()\n\tif err == nil { // Vista+, uint64 values (issue#693)\n\t\tfor _, ifi := range ifs {\n\t\t\tc := IOCountersStat{\n\t\t\t\tName: ifi.Name,\n\t\t\t}\n\n\t\t\trow := mibIfRow2{InterfaceIndex: uint32(ifi.Index)}\n\t\t\tret, _, err := procGetIfEntry2.Call(uintptr(unsafe.Pointer(&row)))\n\t\t\tif ret != 0 {\n\t\t\t\treturn nil, os.NewSyscallError(\"GetIfEntry2\", err)\n\t\t\t}\n\t\t\tc.BytesSent = uint64(row.OutOctets)\n\t\t\tc.BytesRecv = uint64(row.InOctets)\n\t\t\tc.PacketsSent = uint64(row.OutUcastPkts)\n\t\t\tc.PacketsRecv = uint64(row.InUcastPkts)\n\t\t\tc.Errin = uint64(row.InErrors)\n\t\t\tc.Errout = uint64(row.OutErrors)\n\t\t\tc.Dropin = uint64(row.InDiscards)\n\t\t\tc.Dropout = uint64(row.OutDiscards)\n\n\t\t\tcounters = append(counters, c)\n\t\t}\n\t} else { // WinXP fallback, uint32 values\n\t\tfor _, ifi := range ifs {\n\t\t\tc := IOCountersStat{\n\t\t\t\tName: ifi.Name,\n\t\t\t}\n\n\t\t\trow := windows.MibIfRow{Index: uint32(ifi.Index)}\n\t\t\terr = windows.GetIfEntry(&row)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, os.NewSyscallError(\"GetIfEntry\", err)\n\t\t\t}\n\t\t\tc.BytesSent = uint64(row.OutOctets)\n\t\t\tc.BytesRecv = uint64(row.InOctets)\n\t\t\tc.PacketsSent = uint64(row.OutUcastPkts)\n\t\t\tc.PacketsRecv = uint64(row.InUcastPkts)\n\t\t\tc.Errin = uint64(row.InErrors)\n\t\t\tc.Errout = uint64(row.OutErrors)\n\t\t\tc.Dropin = uint64(row.InDiscards)\n\t\t\tc.Dropout = uint64(row.OutDiscards)\n\n\t\t\tcounters = append(counters, c)\n\t\t}\n\t}\n\n\tif !pernic {\n\t\treturn getIOCountersAll(counters), nil\n\t}\n\treturn counters, nil\n}\n\nfunc IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {\n\treturn IOCountersWithContext(ctx, pernic)\n}\n\nfunc ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsPidWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsPidWithContext(_ context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\ttmap, ok := netConnectionKindMap[kind]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid kind, %s\", kind)\n\t}\n\treturn getProcInet(tmap, pid)\n}\n\nfunc getProcInet(kinds []netConnectionKindType, pid int32) ([]ConnectionStat, error) {\n\tstats := make([]ConnectionStat, 0)\n\n\tfor _, kind := range kinds {\n\t\ts, err := getNetStatWithKind(kind)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif pid == 0 {\n\t\t\tstats = append(stats, s...)\n\t\t} else {\n\t\t\tfor _, ns := range s {\n\t\t\t\tif ns.Pid != pid {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tstats = append(stats, ns)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn stats, nil\n}\n\nfunc getNetStatWithKind(kindType netConnectionKindType) ([]ConnectionStat, error) {\n\tif kindType.filename == \"\" {\n\t\treturn nil, errors.New(\"kind filename must be required\")\n\t}\n\n\tswitch kindType.filename {\n\tcase kindTCP4.filename:\n\t\treturn getTCPConnections(kindTCP4.family)\n\tcase kindTCP6.filename:\n\t\treturn getTCPConnections(kindTCP6.family)\n\tcase kindUDP4.filename:\n\t\treturn getUDPConnections(kindUDP4.family)\n\tcase kindUDP6.filename:\n\t\treturn getUDPConnections(kindUDP6.family)\n\t}\n\n\treturn nil, fmt.Errorf(\"invalid kind filename, %s\", kindType.filename)\n}\n\n// Deprecated: use process.PidsWithContext instead\nfunc PidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {\n\treturn ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)\n}\n\nfunc ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)\n}\n\nfunc ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {\n\treturn ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)\n}\n\nfunc ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)\n}\n\nfunc ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {\n\treturn connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)\n}\n\nfunc connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {\n\treturn []ConnectionStat{}, common.ErrNotImplementedError\n}\n\nfunc FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc getTableUintptr(family uint32, buf []byte) uintptr {\n\tvar (\n\t\tpmibTCPTable  pmibTCPTableOwnerPidAll\n\t\tpmibTCP6Table pmibTCP6TableOwnerPidAll\n\n\t\tp uintptr\n\t)\n\tswitch family {\n\tcase kindTCP4.family:\n\t\tif len(buf) > 0 {\n\t\t\tpmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0]))\n\t\t\tp = uintptr(unsafe.Pointer(pmibTCPTable))\n\t\t} else {\n\t\t\tp = uintptr(unsafe.Pointer(pmibTCPTable))\n\t\t}\n\tcase kindTCP6.family:\n\t\tif len(buf) > 0 {\n\t\t\tpmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0]))\n\t\t\tp = uintptr(unsafe.Pointer(pmibTCP6Table))\n\t\t} else {\n\t\t\tp = uintptr(unsafe.Pointer(pmibTCP6Table))\n\t\t}\n\t}\n\treturn p\n}\n\nfunc getTableInfo(filename string, table any) (index, step, length int) {\n\tswitch filename {\n\tcase kindTCP4.filename:\n\t\tindex = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).DwNumEntries))\n\t\tstep = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).Table))\n\t\tlength = int(table.(pmibTCPTableOwnerPidAll).DwNumEntries)\n\tcase kindTCP6.filename:\n\t\tindex = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).DwNumEntries))\n\t\tstep = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).Table))\n\t\tlength = int(table.(pmibTCP6TableOwnerPidAll).DwNumEntries)\n\tcase kindUDP4.filename:\n\t\tindex = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).DwNumEntries))\n\t\tstep = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).Table))\n\t\tlength = int(table.(pmibUDPTableOwnerPid).DwNumEntries)\n\tcase kindUDP6.filename:\n\t\tindex = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).DwNumEntries))\n\t\tstep = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).Table))\n\t\tlength = int(table.(pmibUDP6TableOwnerPid).DwNumEntries)\n\t}\n\n\treturn index, step, length\n}\n\nfunc getTCPConnections(family uint32) ([]ConnectionStat, error) {\n\tvar (\n\t\tp    uintptr\n\t\tbuf  []byte\n\t\tsize uint32\n\n\t\tpmibTCPTable  pmibTCPTableOwnerPidAll\n\t\tpmibTCP6Table pmibTCP6TableOwnerPidAll\n\t)\n\n\tif family == 0 {\n\t\treturn nil, errors.New(\"faimly must be required\")\n\t}\n\n\tfor {\n\t\tswitch family {\n\t\tcase kindTCP4.family:\n\t\t\tif len(buf) > 0 {\n\t\t\t\tpmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0]))\n\t\t\t\tp = uintptr(unsafe.Pointer(pmibTCPTable))\n\t\t\t} else {\n\t\t\t\tp = uintptr(unsafe.Pointer(pmibTCPTable))\n\t\t\t}\n\t\tcase kindTCP6.family:\n\t\t\tif len(buf) > 0 {\n\t\t\t\tpmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0]))\n\t\t\t\tp = uintptr(unsafe.Pointer(pmibTCP6Table))\n\t\t\t} else {\n\t\t\t\tp = uintptr(unsafe.Pointer(pmibTCP6Table))\n\t\t\t}\n\t\t}\n\n\t\terr := getExtendedTCPTable(p,\n\t\t\t&size,\n\t\t\ttrue,\n\t\t\tfamily,\n\t\t\ttcpTableOwnerPidAll,\n\t\t\t0)\n\t\tif err == nil {\n\t\t\tbreak\n\t\t}\n\t\tif !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {\n\t\t\treturn nil, err\n\t\t}\n\t\tbuf = make([]byte, size)\n\t}\n\n\tvar (\n\t\tindex, step int\n\t\tlength      int\n\t)\n\n\tstats := make([]ConnectionStat, 0)\n\tswitch family {\n\tcase kindTCP4.family:\n\t\tindex, step, length = getTableInfo(kindTCP4.filename, pmibTCPTable)\n\tcase kindTCP6.family:\n\t\tindex, step, length = getTableInfo(kindTCP6.filename, pmibTCP6Table)\n\t}\n\n\tif length == 0 {\n\t\treturn nil, nil\n\t}\n\n\tfor i := 0; i < length; i++ {\n\t\tswitch family {\n\t\tcase kindTCP4.family:\n\t\t\tmibs := (*mibTCPRowOwnerPid)(unsafe.Pointer(&buf[index]))\n\t\t\tns := mibs.convertToConnectionStat()\n\t\t\tstats = append(stats, ns)\n\t\tcase kindTCP6.family:\n\t\t\tmibs := (*mibTCP6RowOwnerPid)(unsafe.Pointer(&buf[index]))\n\t\t\tns := mibs.convertToConnectionStat()\n\t\t\tstats = append(stats, ns)\n\t\t}\n\n\t\tindex += step\n\t}\n\treturn stats, nil\n}\n\nfunc getUDPConnections(family uint32) ([]ConnectionStat, error) {\n\tvar (\n\t\tp    uintptr\n\t\tbuf  []byte\n\t\tsize uint32\n\n\t\tpmibUDPTable  pmibUDPTableOwnerPid\n\t\tpmibUDP6Table pmibUDP6TableOwnerPid\n\t)\n\n\tif family == 0 {\n\t\treturn nil, errors.New(\"faimly must be required\")\n\t}\n\n\tfor {\n\t\tswitch family {\n\t\tcase kindUDP4.family:\n\t\t\tif len(buf) > 0 {\n\t\t\t\tpmibUDPTable = (*mibUDPTableOwnerPid)(unsafe.Pointer(&buf[0]))\n\t\t\t\tp = uintptr(unsafe.Pointer(pmibUDPTable))\n\t\t\t} else {\n\t\t\t\tp = uintptr(unsafe.Pointer(pmibUDPTable))\n\t\t\t}\n\t\tcase kindUDP6.family:\n\t\t\tif len(buf) > 0 {\n\t\t\t\tpmibUDP6Table = (*mibUDP6TableOwnerPid)(unsafe.Pointer(&buf[0]))\n\t\t\t\tp = uintptr(unsafe.Pointer(pmibUDP6Table))\n\t\t\t} else {\n\t\t\t\tp = uintptr(unsafe.Pointer(pmibUDP6Table))\n\t\t\t}\n\t\t}\n\n\t\terr := getExtendedUDPTable(\n\t\t\tp,\n\t\t\t&size,\n\t\t\ttrue,\n\t\t\tfamily,\n\t\t\tudpTableOwnerPid,\n\t\t\t0,\n\t\t)\n\t\tif err == nil {\n\t\t\tbreak\n\t\t}\n\t\tif !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {\n\t\t\treturn nil, err\n\t\t}\n\t\tbuf = make([]byte, size)\n\t}\n\n\tvar index, step, length int\n\n\tstats := make([]ConnectionStat, 0)\n\tswitch family {\n\tcase kindUDP4.family:\n\t\tindex, step, length = getTableInfo(kindUDP4.filename, pmibUDPTable)\n\tcase kindUDP6.family:\n\t\tindex, step, length = getTableInfo(kindUDP6.filename, pmibUDP6Table)\n\t}\n\n\tif length == 0 {\n\t\treturn nil, nil\n\t}\n\n\tfor i := 0; i < length; i++ {\n\t\tswitch family {\n\t\tcase kindUDP4.family:\n\t\t\tmibs := (*mibUDPRowOwnerPid)(unsafe.Pointer(&buf[index]))\n\t\t\tns := mibs.convertToConnectionStat()\n\t\t\tstats = append(stats, ns)\n\t\tcase kindUDP6.family:\n\t\t\tmibs := (*mibUDP6RowOwnerPid)(unsafe.Pointer(&buf[index]))\n\t\t\tns := mibs.convertToConnectionStat()\n\t\t\tstats = append(stats, ns)\n\t\t}\n\n\t\tindex += step\n\t}\n\treturn stats, nil\n}\n\n// tcpStatuses https://msdn.microsoft.com/en-us/library/windows/desktop/bb485761(v=vs.85).aspx\nvar tcpStatuses = map[mibTCPState]string{\n\t1:  \"CLOSED\",\n\t2:  \"LISTEN\",\n\t3:  \"SYN_SENT\",\n\t4:  \"SYN_RECEIVED\",\n\t5:  \"ESTABLISHED\",\n\t6:  \"FIN_WAIT_1\",\n\t7:  \"FIN_WAIT_2\",\n\t8:  \"CLOSE_WAIT\",\n\t9:  \"CLOSING\",\n\t10: \"LAST_ACK\",\n\t11: \"TIME_WAIT\",\n\t12: \"DELETE\",\n}\n\nfunc getExtendedTCPTable(pTCPTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass tcpTableClass, reserved uint32) (errcode error) {\n\tr1, _, _ := syscall.Syscall6(procGetExtendedTCPTable.Addr(), 6, pTCPTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved))\n\tif r1 != 0 {\n\t\terrcode = syscall.Errno(r1)\n\t}\n\treturn errcode\n}\n\nfunc getExtendedUDPTable(pUDPTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass udpTableClass, reserved uint32) (errcode error) {\n\tr1, _, _ := syscall.Syscall6(procGetExtendedUDPTable.Addr(), 6, pUDPTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved))\n\tif r1 != 0 {\n\t\terrcode = syscall.Errno(r1)\n\t}\n\treturn errcode\n}\n\nfunc getUintptrFromBool(b bool) uintptr {\n\tif b {\n\t\treturn 1\n\t}\n\treturn 0\n}\n\nconst anySize = 1\n\n// type MIB_TCP_STATE int32\ntype mibTCPState int32\n\ntype tcpTableClass int32\n\nconst (\n\ttcpTableBasicListener tcpTableClass = iota\n\ttcpTableBasicConnections\n\ttcpTableBasicAll\n\ttcpTableOwnerPidListener\n\ttcpTableOwnerPidConnections\n\ttcpTableOwnerPidAll\n\ttcpTableOwnerModuleListener\n\ttcpTableOwnerModuleConnections\n\ttcpTableOwnerModuleAll\n)\n\ntype udpTableClass int32\n\nconst (\n\tudpTableBasic udpTableClass = iota\n\tudpTableOwnerPid\n\tudpTableOwnerModule\n)\n\n// TCP\n\ntype mibTCPRowOwnerPid struct {\n\tDwState      uint32\n\tDwLocalAddr  uint32\n\tDwLocalPort  uint32\n\tDwRemoteAddr uint32\n\tDwRemotePort uint32\n\tDwOwningPid  uint32\n}\n\nfunc (m *mibTCPRowOwnerPid) convertToConnectionStat() ConnectionStat {\n\tns := ConnectionStat{\n\t\tFamily: kindTCP4.family,\n\t\tType:   kindTCP4.sockType,\n\t\tLaddr: Addr{\n\t\t\tIP:   parseIPv4HexString(m.DwLocalAddr),\n\t\t\tPort: uint32(decodePort(m.DwLocalPort)),\n\t\t},\n\t\tRaddr: Addr{\n\t\t\tIP:   parseIPv4HexString(m.DwRemoteAddr),\n\t\t\tPort: uint32(decodePort(m.DwRemotePort)),\n\t\t},\n\t\tPid:    int32(m.DwOwningPid),\n\t\tStatus: tcpStatuses[mibTCPState(m.DwState)],\n\t}\n\n\treturn ns\n}\n\ntype mibTCPTableOwnerPid struct {\n\tDwNumEntries uint32\n\tTable        [anySize]mibTCPRowOwnerPid\n}\n\ntype mibTCP6RowOwnerPid struct {\n\tUcLocalAddr     [16]byte\n\tDwLocalScopeId  uint32\n\tDwLocalPort     uint32\n\tUcRemoteAddr    [16]byte\n\tDwRemoteScopeId uint32\n\tDwRemotePort    uint32\n\tDwState         uint32\n\tDwOwningPid     uint32\n}\n\nfunc (m *mibTCP6RowOwnerPid) convertToConnectionStat() ConnectionStat {\n\tns := ConnectionStat{\n\t\tFamily: kindTCP6.family,\n\t\tType:   kindTCP6.sockType,\n\t\tLaddr: Addr{\n\t\t\tIP:   parseIPv6HexString(m.UcLocalAddr),\n\t\t\tPort: uint32(decodePort(m.DwLocalPort)),\n\t\t},\n\t\tRaddr: Addr{\n\t\t\tIP:   parseIPv6HexString(m.UcRemoteAddr),\n\t\t\tPort: uint32(decodePort(m.DwRemotePort)),\n\t\t},\n\t\tPid:    int32(m.DwOwningPid),\n\t\tStatus: tcpStatuses[mibTCPState(m.DwState)],\n\t}\n\n\treturn ns\n}\n\ntype mibTCP6TableOwnerPid struct {\n\tDwNumEntries uint32\n\tTable        [anySize]mibTCP6RowOwnerPid\n}\n\ntype (\n\tpmibTCPTableOwnerPidAll  *mibTCPTableOwnerPid\n\tpmibTCP6TableOwnerPidAll *mibTCP6TableOwnerPid\n)\n\n// UDP\n\ntype mibUDPRowOwnerPid struct {\n\tDwLocalAddr uint32\n\tDwLocalPort uint32\n\tDwOwningPid uint32\n}\n\nfunc (m *mibUDPRowOwnerPid) convertToConnectionStat() ConnectionStat {\n\tns := ConnectionStat{\n\t\tFamily: kindUDP4.family,\n\t\tType:   kindUDP4.sockType,\n\t\tLaddr: Addr{\n\t\t\tIP:   parseIPv4HexString(m.DwLocalAddr),\n\t\t\tPort: uint32(decodePort(m.DwLocalPort)),\n\t\t},\n\t\tPid: int32(m.DwOwningPid),\n\t}\n\n\treturn ns\n}\n\ntype mibUDPTableOwnerPid struct {\n\tDwNumEntries uint32\n\tTable        [anySize]mibUDPRowOwnerPid\n}\n\ntype mibUDP6RowOwnerPid struct {\n\tUcLocalAddr    [16]byte\n\tDwLocalScopeId uint32\n\tDwLocalPort    uint32\n\tDwOwningPid    uint32\n}\n\nfunc (m *mibUDP6RowOwnerPid) convertToConnectionStat() ConnectionStat {\n\tns := ConnectionStat{\n\t\tFamily: kindUDP6.family,\n\t\tType:   kindUDP6.sockType,\n\t\tLaddr: Addr{\n\t\t\tIP:   parseIPv6HexString(m.UcLocalAddr),\n\t\t\tPort: uint32(decodePort(m.DwLocalPort)),\n\t\t},\n\t\tPid: int32(m.DwOwningPid),\n\t}\n\n\treturn ns\n}\n\ntype mibUDP6TableOwnerPid struct {\n\tDwNumEntries uint32\n\tTable        [anySize]mibUDP6RowOwnerPid\n}\n\ntype (\n\tpmibUDPTableOwnerPid  *mibUDPTableOwnerPid\n\tpmibUDP6TableOwnerPid *mibUDP6TableOwnerPid\n)\n\nfunc decodePort(port uint32) uint16 {\n\treturn syscall.Ntohs(uint16(port))\n}\n\nfunc parseIPv4HexString(addr uint32) string {\n\treturn fmt.Sprintf(\"%d.%d.%d.%d\", addr&255, addr>>8&255, addr>>16&255, addr>>24&255)\n}\n\nfunc parseIPv6HexString(addr [16]byte) string {\n\tvar ret [16]byte\n\tfor i := 0; i < 16; i++ {\n\t\tret[i] = uint8(addr[i])\n\t}\n\n\t// convert []byte to net.IP\n\tip := net.IP(ret[:])\n\treturn ip.String()\n}\n"
  },
  {
    "path": "net/types_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n// Hand writing: _Ctype_struct___3, 4\n\n/*\nInput to cgo -godefs.\n\n*/\n\npackage net\n\n/*\n#include <sys/types.h>\n#include <sys/socketvar.h>\n#include <sys/proc_info.h>\n#include <netinet/in_pcb.h>\n\nenum {\n\tsizeofPtr = sizeof(void*),\n};\n\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tsizeofPtr        = C.sizeofPtr\n\tsizeofShort      = C.sizeof_short\n\tsizeofInt        = C.sizeof_int\n\tsizeofLong       = C.sizeof_long\n\tsizeofLongLong   = C.sizeof_longlong\n\tsizeofLongDouble = C.sizeof_longlong\n)\n\n// Basic types\n\ntype (\n\t_C_short       C.short\n\t_C_int         C.int\n\t_C_long        C.long\n\t_C_long_long   C.longlong\n\t_C_long_double C.longlong\n)\n\ntype (\n\tXinpgen          C.struct_xinpgen\n\tInpcb            C.struct_inpcb\n\tin_addr          C.struct_in_addr\n\tInpcb_list_entry C.struct__inpcb_list_entry\n\tXsocket          C.struct_xsocket\n\tXsockbuf         C.struct_xsockbuf\n\tXinpcb           C.struct_xinpcb\n)\n\n// type u_quad_t C.struct_u_quad_t\n"
  },
  {
    "path": "process/process.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage process\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"sort\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/mem\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\nvar (\n\tinvoke                 common.Invoker = common.Invoke{}\n\tstrictIntPtrn                         = regexp.MustCompile(`^\\d+$`)\n\tErrorNoChildren                       = errors.New(\"process does not have children\") // Deprecated: ErrorNoChildren is never returned by process.Children(), check its returned []*Process slice length instead\n\tErrorProcessNotRunning                = errors.New(\"process does not exist\")\n\tErrorNotPermitted                     = errors.New(\"operation not permitted\")\n)\n\ntype Process struct {\n\tPid            int32 `json:\"pid\"`\n\tname           string\n\tstatus         string\n\tparent         int32\n\tparentMutex    sync.RWMutex // for windows ppid cache\n\tnumCtxSwitches *NumCtxSwitchesStat\n\tuids           []uint32\n\tgids           []uint32\n\tgroups         []uint32\n\tnumThreads     int32\n\tmemInfo        *MemoryInfoStat\n\tsigInfo        *SignalInfoStat\n\tcreateTime     int64\n\n\tlastCPUTimes *cpu.TimesStat\n\tlastCPUTime  time.Time\n\n\ttgid int32\n}\n\n// Process status\nconst (\n\t// Running marks a task a running or runnable (on the run queue)\n\tRunning = \"running\"\n\t// Blocked marks a task waiting on a short, uninterruptible operation (usually I/O)\n\tBlocked = \"blocked\"\n\t// Idle marks a task sleeping for more than about 20 seconds\n\tIdle = \"idle\"\n\t// Lock marks a task waiting to acquire a lock\n\tLock = \"lock\"\n\t// Sleep marks task waiting for short, interruptible operation\n\tSleep = \"sleep\"\n\t// Stop marks a stopped process\n\tStop = \"stop\"\n\t// Wait marks an idle interrupt thread (or paging in pre 2.6.xx Linux)\n\tWait = \"wait\"\n\t// Zombie marks a defunct process, terminated but not reaped by its parent\n\tZombie = \"zombie\"\n\n\t// Solaris states. See https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115\n\tDaemon   = \"daemon\"\n\tDetached = \"detached\"\n\tSystem   = \"system\"\n\tOrphan   = \"orphan\"\n\n\tUnknownState = \"\"\n)\n\ntype OpenFilesStat struct {\n\tPath string `json:\"path\"`\n\tFd   uint64 `json:\"fd\"`\n}\n\ntype MemoryInfoStat struct {\n\tRSS    uint64 `json:\"rss\"`    // bytes\n\tVMS    uint64 `json:\"vms\"`    // bytes\n\tHWM    uint64 `json:\"hwm\"`    // bytes\n\tData   uint64 `json:\"data\"`   // bytes\n\tStack  uint64 `json:\"stack\"`  // bytes\n\tLocked uint64 `json:\"locked\"` // bytes\n\tSwap   uint64 `json:\"swap\"`   // bytes\n}\n\ntype SignalInfoStat struct {\n\tPendingProcess uint64 `json:\"pending_process\"`\n\tPendingThread  uint64 `json:\"pending_thread\"`\n\tBlocked        uint64 `json:\"blocked\"`\n\tIgnored        uint64 `json:\"ignored\"`\n\tCaught         uint64 `json:\"caught\"`\n}\n\ntype RlimitStat struct {\n\tResource int32  `json:\"resource\"`\n\tSoft     uint64 `json:\"soft\"`\n\tHard     uint64 `json:\"hard\"`\n\tUsed     uint64 `json:\"used\"`\n}\n\ntype IOCountersStat struct {\n\t// ReadCount is a number of read I/O operations such as syscalls.\n\tReadCount uint64 `json:\"readCount\"`\n\t// WriteCount is a number of read I/O operations such as syscalls.\n\tWriteCount uint64 `json:\"writeCount\"`\n\t// ReadBytes is a number of all I/O read in bytes. This includes disk I/O on Linux and Windows.\n\tReadBytes uint64 `json:\"readBytes\"`\n\t// WriteBytes is a number of all I/O write in bytes. This includes disk I/O on Linux and Windows.\n\tWriteBytes uint64 `json:\"writeBytes\"`\n\t// DiskReadBytes is a number of disk I/O write in bytes. Currently only Linux has this value.\n\tDiskReadBytes uint64 `json:\"diskReadBytes\"`\n\t// DiskWriteBytes is a number of disk I/O read in bytes.  Currently only Linux has this value.\n\tDiskWriteBytes uint64 `json:\"diskWriteBytes\"`\n}\n\ntype NumCtxSwitchesStat struct {\n\tVoluntary   int64 `json:\"voluntary\"`\n\tInvoluntary int64 `json:\"involuntary\"`\n}\n\ntype PageFaultsStat struct {\n\tMinorFaults      uint64 `json:\"minorFaults\"`\n\tMajorFaults      uint64 `json:\"majorFaults\"`\n\tChildMinorFaults uint64 `json:\"childMinorFaults\"`\n\tChildMajorFaults uint64 `json:\"childMajorFaults\"`\n}\n\n// Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h\n// from libc6-dev package in Ubuntu 16.10\nconst (\n\tRLIMIT_CPU        int32 = 0\n\tRLIMIT_FSIZE      int32 = 1\n\tRLIMIT_DATA       int32 = 2\n\tRLIMIT_STACK      int32 = 3\n\tRLIMIT_CORE       int32 = 4\n\tRLIMIT_RSS        int32 = 5\n\tRLIMIT_NPROC      int32 = 6\n\tRLIMIT_NOFILE     int32 = 7\n\tRLIMIT_MEMLOCK    int32 = 8\n\tRLIMIT_AS         int32 = 9\n\tRLIMIT_LOCKS      int32 = 10\n\tRLIMIT_SIGPENDING int32 = 11\n\tRLIMIT_MSGQUEUE   int32 = 12\n\tRLIMIT_NICE       int32 = 13\n\tRLIMIT_RTPRIO     int32 = 14\n\tRLIMIT_RTTIME     int32 = 15\n)\n\nfunc (p Process) String() string {\n\ts, _ := json.Marshal(p)\n\treturn string(s)\n}\n\nfunc (o OpenFilesStat) String() string {\n\ts, _ := json.Marshal(o)\n\treturn string(s)\n}\n\nfunc (m MemoryInfoStat) String() string {\n\ts, _ := json.Marshal(m)\n\treturn string(s)\n}\n\nfunc (r RlimitStat) String() string {\n\ts, _ := json.Marshal(r)\n\treturn string(s)\n}\n\nfunc (i IOCountersStat) String() string {\n\ts, _ := json.Marshal(i)\n\treturn string(s)\n}\n\nfunc (p NumCtxSwitchesStat) String() string {\n\ts, _ := json.Marshal(p)\n\treturn string(s)\n}\n\nvar enableBootTimeCache bool\n\n// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.\nfunc EnableBootTimeCache(enable bool) {\n\tenableBootTimeCache = enable\n}\n\n// Pids returns a slice of process ID list which are running now.\nfunc Pids() ([]int32, error) {\n\treturn PidsWithContext(context.Background())\n}\n\nfunc PidsWithContext(ctx context.Context) ([]int32, error) {\n\tpids, err := pidsWithContext(ctx)\n\tsort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] })\n\treturn pids, err\n}\n\n// Processes returns a slice of pointers to Process structs for all\n// currently running processes.\nfunc Processes() ([]*Process, error) {\n\treturn ProcessesWithContext(context.Background())\n}\n\n// NewProcess creates a new Process instance, it only stores the pid and\n// checks that the process exists. Other method on Process can be used\n// to get more information about the process. An error will be returned\n// if the process does not exist.\nfunc NewProcess(pid int32) (*Process, error) {\n\treturn NewProcessWithContext(context.Background(), pid)\n}\n\nfunc NewProcessWithContext(ctx context.Context, pid int32) (*Process, error) {\n\tp := &Process{\n\t\tPid: pid,\n\t}\n\n\texists, err := PidExistsWithContext(ctx, pid)\n\tif err != nil {\n\t\treturn p, err\n\t}\n\tif !exists {\n\t\treturn p, ErrorProcessNotRunning\n\t}\n\tp.CreateTimeWithContext(ctx)\n\treturn p, nil\n}\n\nfunc PidExists(pid int32) (bool, error) {\n\treturn PidExistsWithContext(context.Background(), pid)\n}\n\n// Background returns true if the process is in background, false otherwise.\nfunc (p *Process) Background() (bool, error) {\n\treturn p.BackgroundWithContext(context.Background())\n}\n\nfunc (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) {\n\tfg, err := p.ForegroundWithContext(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn !fg, err\n}\n\n// If interval is 0, return difference from last call(non-blocking).\n// If interval > 0, wait interval sec and return difference between start and end.\nfunc (p *Process) Percent(interval time.Duration) (float64, error) {\n\treturn p.PercentWithContext(context.Background(), interval)\n}\n\nfunc (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) {\n\tcpuTimes, err := p.TimesWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tnow := time.Now()\n\n\tif interval > 0 {\n\t\tp.lastCPUTimes = cpuTimes\n\t\tp.lastCPUTime = now\n\t\tif err := common.Sleep(ctx, interval); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tcpuTimes, err = p.TimesWithContext(ctx)\n\t\tnow = time.Now()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t} else if p.lastCPUTimes == nil {\n\t\t// invoked first time\n\t\tp.lastCPUTimes = cpuTimes\n\t\tp.lastCPUTime = now\n\t\treturn 0, nil\n\t}\n\n\tnumcpu := runtime.NumCPU()\n\tdelta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)\n\tret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)\n\tp.lastCPUTimes = cpuTimes\n\tp.lastCPUTime = now\n\treturn ret, nil\n}\n\n// IsRunning returns whether the process is still running or not.\nfunc (p *Process) IsRunning() (bool, error) {\n\treturn p.IsRunningWithContext(context.Background())\n}\n\nfunc (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {\n\tcreateTime, err := p.CreateTimeWithContext(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tp2, err := NewProcessWithContext(ctx, p.Pid)\n\tif errors.Is(err, ErrorProcessNotRunning) {\n\t\treturn false, nil\n\t}\n\tcreateTime2, err := p2.CreateTimeWithContext(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn createTime == createTime2, nil\n}\n\n// CreateTime returns created time of the process in milliseconds since the epoch, in UTC.\nfunc (p *Process) CreateTime() (int64, error) {\n\treturn p.CreateTimeWithContext(context.Background())\n}\n\nfunc (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {\n\tif p.createTime != 0 {\n\t\treturn p.createTime, nil\n\t}\n\tcreateTime, err := p.createTimeWithContext(ctx)\n\tp.createTime = createTime\n\treturn p.createTime, err\n}\n\nfunc calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {\n\tif delta == 0 {\n\t\treturn 0\n\t}\n\t// https://github.com/giampaolo/psutil/blob/c034e6692cf736b5e87d14418a8153bb03f6cf42/psutil/__init__.py#L1064\n\tdeltaProc := (t2.User - t1.User) + (t2.System - t1.System)\n\tif deltaProc <= 0 {\n\t\treturn 0\n\t}\n\toverallPercent := ((deltaProc / delta) * 100) * float64(numcpu)\n\treturn overallPercent\n}\n\n// MemoryPercent returns how many percent of the total RAM this process uses\nfunc (p *Process) MemoryPercent() (float32, error) {\n\treturn p.MemoryPercentWithContext(context.Background())\n}\n\nfunc (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) {\n\tmachineMemory, err := mem.VirtualMemoryWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\ttotal := machineMemory.Total\n\n\tprocessMemory, err := p.MemoryInfoWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tused := processMemory.RSS\n\n\treturn (100 * float32(used) / float32(total)), nil\n}\n\n// CPUPercent returns how many percent of the CPU time this process uses\nfunc (p *Process) CPUPercent() (float64, error) {\n\treturn p.CPUPercentWithContext(context.Background())\n}\n\nfunc (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) {\n\tcreateTime, err := p.createTimeWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tcput, err := p.TimesWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tcreated := time.Unix(0, createTime*int64(time.Millisecond))\n\ttotalTime := time.Since(created).Seconds()\n\tif totalTime <= 0 {\n\t\treturn 0, nil\n\t}\n\n\treturn 100 * cput.Total() / totalTime, nil\n}\n\n// Groups returns all group IDs(include supplementary groups) of the process as a slice of the int\nfunc (p *Process) Groups() ([]uint32, error) {\n\treturn p.GroupsWithContext(context.Background())\n}\n\n// Ppid returns Parent Process ID of the process.\nfunc (p *Process) Ppid() (int32, error) {\n\treturn p.PpidWithContext(context.Background())\n}\n\n// Name returns name of the process.\nfunc (p *Process) Name() (string, error) {\n\treturn p.NameWithContext(context.Background())\n}\n\n// Exe returns executable path of the process.\nfunc (p *Process) Exe() (string, error) {\n\treturn p.ExeWithContext(context.Background())\n}\n\n// Cmdline returns the command line arguments of the process as a string with\n// each argument separated by 0x20 ascii character.\nfunc (p *Process) Cmdline() (string, error) {\n\treturn p.CmdlineWithContext(context.Background())\n}\n\n// CmdlineSlice returns the command line arguments of the process as a slice with each\n// element being an argument.\n//\n// On Windows, this assumes the command line is encoded according to the convention accepted by\n// [golang.org/x/sys/windows.CmdlineToArgv] (the most common convention). If this is not suitable,\n// you should instead use [Process.Cmdline] and parse the command line according to your specific\n// requirements.\nfunc (p *Process) CmdlineSlice() ([]string, error) {\n\treturn p.CmdlineSliceWithContext(context.Background())\n}\n\n// Cwd returns current working directory of the process.\nfunc (p *Process) Cwd() (string, error) {\n\treturn p.CwdWithContext(context.Background())\n}\n\n// Parent returns parent Process of the process.\nfunc (p *Process) Parent() (*Process, error) {\n\treturn p.ParentWithContext(context.Background())\n}\n\n// ParentWithContext returns parent Process of the process.\nfunc (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {\n\tppid, err := p.PpidWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn NewProcessWithContext(ctx, ppid)\n}\n\n// Status returns the process status.\n// Return value could be one of these.\n// R: Running S: Sleep T: Stop I: Idle\n// Z: Zombie W: Wait L: Lock\n// The character is same within all supported platforms.\nfunc (p *Process) Status() ([]string, error) {\n\treturn p.StatusWithContext(context.Background())\n}\n\n// Foreground returns true if the process is in foreground, false otherwise.\nfunc (p *Process) Foreground() (bool, error) {\n\treturn p.ForegroundWithContext(context.Background())\n}\n\n// Uids returns user ids of the process as a slice of the int\nfunc (p *Process) Uids() ([]uint32, error) {\n\treturn p.UidsWithContext(context.Background())\n}\n\n// Gids returns group ids of the process as a slice of the int\nfunc (p *Process) Gids() ([]uint32, error) {\n\treturn p.GidsWithContext(context.Background())\n}\n\n// Terminal returns a terminal which is associated with the process.\nfunc (p *Process) Terminal() (string, error) {\n\treturn p.TerminalWithContext(context.Background())\n}\n\n// Nice returns a nice value (priority).\nfunc (p *Process) Nice() (int32, error) {\n\treturn p.NiceWithContext(context.Background())\n}\n\n// IOnice returns process I/O nice value (priority).\nfunc (p *Process) IOnice() (int32, error) {\n\treturn p.IOniceWithContext(context.Background())\n}\n\n// Rlimit returns Resource Limits.\nfunc (p *Process) Rlimit() ([]RlimitStat, error) {\n\treturn p.RlimitWithContext(context.Background())\n}\n\n// RlimitUsage returns Resource Limits.\n// If gatherUsed is true, the currently used value will be gathered and added\n// to the resulting RlimitStat.\nfunc (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {\n\treturn p.RlimitUsageWithContext(context.Background(), gatherUsed)\n}\n\n// IOCounters returns IO Counters.\nfunc (p *Process) IOCounters() (*IOCountersStat, error) {\n\treturn p.IOCountersWithContext(context.Background())\n}\n\n// NumCtxSwitches returns the number of the context switches of the process.\nfunc (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {\n\treturn p.NumCtxSwitchesWithContext(context.Background())\n}\n\n// NumFDs returns the number of File Descriptors used by the process.\nfunc (p *Process) NumFDs() (int32, error) {\n\treturn p.NumFDsWithContext(context.Background())\n}\n\n// NumThreads returns the number of threads used by the process.\nfunc (p *Process) NumThreads() (int32, error) {\n\treturn p.NumThreadsWithContext(context.Background())\n}\n\nfunc (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {\n\treturn p.ThreadsWithContext(context.Background())\n}\n\n// Times returns CPU times of the process.\nfunc (p *Process) Times() (*cpu.TimesStat, error) {\n\treturn p.TimesWithContext(context.Background())\n}\n\n// CPUAffinity returns CPU affinity of the process.\nfunc (p *Process) CPUAffinity() ([]int32, error) {\n\treturn p.CPUAffinityWithContext(context.Background())\n}\n\n// MemoryInfo returns generic process memory information,\n// such as RSS and VMS.\nfunc (p *Process) MemoryInfo() (*MemoryInfoStat, error) {\n\treturn p.MemoryInfoWithContext(context.Background())\n}\n\n// MemoryInfoEx returns platform-specific process memory information.\nfunc (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {\n\treturn p.MemoryInfoExWithContext(context.Background())\n}\n\n// PageFaults returns the process's page fault counters.\nfunc (p *Process) PageFaults() (*PageFaultsStat, error) {\n\treturn p.PageFaultsWithContext(context.Background())\n}\n\n// Children returns the children of the process represented as a slice\n// of pointers to Process type.\nfunc (p *Process) Children() ([]*Process, error) {\n\treturn p.ChildrenWithContext(context.Background())\n}\n\n// OpenFiles returns a slice of OpenFilesStat opend by the process.\n// OpenFilesStat includes a file path and file descriptor.\nfunc (p *Process) OpenFiles() ([]OpenFilesStat, error) {\n\treturn p.OpenFilesWithContext(context.Background())\n}\n\n// Connections returns a slice of net.ConnectionStat used by the process.\n// This returns all kind of the connection. This means TCP, UDP or UNIX.\nfunc (p *Process) Connections() ([]net.ConnectionStat, error) {\n\treturn p.ConnectionsWithContext(context.Background())\n}\n\n// ConnectionsMax returns a slice of net.ConnectionStat used by the process at most `max`.\nfunc (p *Process) ConnectionsMax(maxConn int) ([]net.ConnectionStat, error) {\n\treturn p.ConnectionsMaxWithContext(context.Background(), maxConn)\n}\n\n// MemoryMaps get memory maps from /proc/(pid)/smaps\nfunc (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {\n\treturn p.MemoryMapsWithContext(context.Background(), grouped)\n}\n\n// Tgid returns thread group id of the process.\nfunc (p *Process) Tgid() (int32, error) {\n\treturn p.TgidWithContext(context.Background())\n}\n\n// SendSignal sends a unix.Signal to the process.\nfunc (p *Process) SendSignal(sig Signal) error {\n\treturn p.SendSignalWithContext(context.Background(), sig)\n}\n\n// Suspend sends SIGSTOP to the process.\nfunc (p *Process) Suspend() error {\n\treturn p.SuspendWithContext(context.Background())\n}\n\n// Resume sends SIGCONT to the process.\nfunc (p *Process) Resume() error {\n\treturn p.ResumeWithContext(context.Background())\n}\n\n// Terminate sends SIGTERM to the process.\nfunc (p *Process) Terminate() error {\n\treturn p.TerminateWithContext(context.Background())\n}\n\n// Kill sends SIGKILL to the process.\nfunc (p *Process) Kill() error {\n\treturn p.KillWithContext(context.Background())\n}\n\n// Username returns a username of the process.\nfunc (p *Process) Username() (string, error) {\n\treturn p.UsernameWithContext(context.Background())\n}\n\n// Environ returns the environment variables of the process.\nfunc (p *Process) Environ() ([]string, error) {\n\treturn p.EnvironWithContext(context.Background())\n}\n\n// convertStatusChar as reported by the ps command across different platforms.\nfunc convertStatusChar(letter string) string {\n\t// Sources\n\t// Darwin: http://www.mywebuniversity.com/Man_Pages/Darwin/man_ps.html\n\t// FreeBSD: https://www.freebsd.org/cgi/man.cgi?ps\n\t// Linux https://man7.org/linux/man-pages/man1/ps.1.html\n\t// OpenBSD: https://man.openbsd.org/ps.1#state\n\t// Solaris: https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115\n\tswitch letter {\n\tcase \"A\":\n\t\treturn Daemon\n\tcase \"D\", \"U\":\n\t\treturn Blocked\n\tcase \"E\":\n\t\treturn Detached\n\tcase \"I\":\n\t\treturn Idle\n\tcase \"L\":\n\t\treturn Lock\n\tcase \"O\":\n\t\treturn Orphan\n\tcase \"R\":\n\t\treturn Running\n\tcase \"S\":\n\t\treturn Sleep\n\tcase \"T\", \"t\":\n\t\t// \"t\" is used by Linux to signal stopped by the debugger during tracing\n\t\treturn Stop\n\tcase \"W\":\n\t\treturn Wait\n\tcase \"Y\":\n\t\treturn System\n\tcase \"Z\":\n\t\treturn Zombie\n\tdefault:\n\t\treturn UnknownState\n\t}\n}\n"
  },
  {
    "path": "process/process_bsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin || freebsd || openbsd\n\npackage process\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\ntype MemoryInfoExStat struct{}\n\ntype MemoryMapsStat struct{}\n\nfunc (*Process) TgidWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) IOniceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) EnvironWithContext(_ context.Context) ([]string, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc parseKinfoProc(buf []byte) (KinfoProc, error) {\n\tvar k KinfoProc\n\tbr := bytes.NewReader(buf)\n\terr := binary.Read(br, binary.LittleEndian, &k)\n\treturn k, err\n}\n"
  },
  {
    "path": "process/process_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage process\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\n// copied from sys/sysctl.h\nconst (\n\tCTLKern          = 1  // \"high kernel\": proc, limits\n\tKernProc         = 14 // struct: process entries\n\tKernProcPID      = 1  // by process id\n\tKernProcProc     = 8  // only return procs\n\tKernProcAll      = 0  // everything\n\tKernProcPathname = 12 // path to executable\n)\n\ntype _Ctype_struct___0 struct { //nolint:revive //FIXME\n\tPad uint64\n}\n\nfunc pidsWithContext(_ context.Context) ([]int32, error) {\n\tvar ret []int32\n\n\tkprocs, err := unix.SysctlKinfoProcSlice(\"kern.proc.all\")\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tfor i := range kprocs {\n\t\tproc := &kprocs[i]\n\t\tret = append(ret, int32(proc.Proc.P_pid))\n\t}\n\n\treturn ret, nil\n}\n\nfunc (p *Process) PpidWithContext(_ context.Context) (int32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn k.Eproc.Ppid, nil\n}\n\nfunc (p *Process) NameWithContext(ctx context.Context) (string, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tname := common.ByteToString(k.Proc.P_comm[:])\n\n\tif len(name) >= 15 {\n\t\tcmdName, err := p.cmdNameWithContext(ctx)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif cmdName != \"\" {\n\t\t\textendedName := filepath.Base(cmdName)\n\t\t\tif strings.HasPrefix(extendedName, p.name) {\n\t\t\t\tname = extendedName\n\t\t\t}\n\t\t}\n\t}\n\n\treturn name, nil\n}\n\nfunc (p *Process) createTimeWithContext(_ context.Context) (int64, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn k.Proc.P_starttime.Sec*1000 + int64(k.Proc.P_starttime.Usec)/1000, nil\n}\n\nfunc (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {\n\tr, err := callPsWithContext(ctx, \"state\", p.Pid, false, false)\n\tif err != nil {\n\t\treturn []string{\"\"}, err\n\t}\n\tstatus := convertStatusChar(r[0][0][0:1])\n\treturn []string{status}, err\n}\n\nfunc (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {\n\t// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details\n\tpid := p.Pid\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", \"-o\", \"stat=\", \"-p\", strconv.Itoa(int(pid)))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn strings.IndexByte(string(out), '+') != -1, nil\n}\n\nfunc (p *Process) UidsWithContext(_ context.Context) ([]uint32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html\n\tuserEffectiveUID := uint32(k.Eproc.Ucred.Uid)\n\n\treturn []uint32{userEffectiveUID}, nil\n}\n\nfunc (p *Process) GidsWithContext(_ context.Context) ([]uint32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgids := make([]uint32, 0, 3)\n\tgids = append(gids, uint32(k.Eproc.Pcred.P_rgid), uint32(k.Eproc.Ucred.Groups[0]), uint32(k.Eproc.Pcred.P_svgid))\n\n\treturn gids, nil\n}\n\nfunc (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n\t// k, err := p.getKProc()\n\t// if err != nil {\n\t// \treturn nil, err\n\t// }\n\n\t// groups := make([]int32, k.Eproc.Ucred.Ngroups)\n\t// for i := int16(0); i < k.Eproc.Ucred.Ngroups; i++ {\n\t// \tgroups[i] = int32(k.Eproc.Ucred.Groups[i])\n\t// }\n\n\t// return groups, nil\n}\n\nfunc (*Process) TerminalWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n\t/*\n\t\tk, err := p.getKProc()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tttyNr := uint64(k.Eproc.Tdev)\n\t\ttermmap, err := getTerminalMap()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\treturn termmap[ttyNr], nil\n\t*/\n}\n\nfunc (p *Process) NiceWithContext(_ context.Context) (int32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int32(k.Proc.P_nice), nil\n}\n\nfunc (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {\n\tprocs, err := ProcessesWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil\n\t}\n\tret := make([]*Process, 0, len(procs))\n\tfor _, proc := range procs {\n\t\tppid, err := proc.PpidWithContext(ctx)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif ppid == p.Pid {\n\t\t\tret = append(ret, proc)\n\t\t}\n\t}\n\tsort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })\n\treturn ret, nil\n}\n\nfunc (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {\n\treturn net.ConnectionsPidWithContext(ctx, \"all\", p.Pid)\n}\n\nfunc (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {\n\treturn net.ConnectionsPidMaxWithContext(ctx, \"all\", p.Pid, maxConn)\n}\n\nfunc ProcessesWithContext(ctx context.Context) ([]*Process, error) {\n\tout := []*Process{}\n\n\tpids, err := PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn out, err\n\t}\n\n\tfor _, pid := range pids {\n\t\tp, err := NewProcessWithContext(ctx, pid)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tout = append(out, p)\n\t}\n\n\treturn out, nil\n}\n\n// Returns a proc as defined here:\n// http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html\nfunc (p *Process) getKProc() (*unix.KinfoProc, error) {\n\treturn unix.SysctlKinfoProc(\"kern.proc.pid\", int(p.Pid))\n}\n\n// call ps command.\n// Return value deletes Header line(you must not input wrong arg).\n// And split by Space. Caller have responsibility to manage.\n// If passed arg pid is 0, get information from all process.\nfunc callPsWithContext(ctx context.Context, arg string, pid int32, threadOption, nameOption bool) ([][]string, error) {\n\tvar cmd []string\n\tswitch {\n\tcase pid == 0: // will get from all processes.\n\t\tcmd = []string{\"-ax\", \"-o\", arg}\n\tcase threadOption:\n\t\tcmd = []string{\"-x\", \"-o\", arg, \"-M\", \"-p\", strconv.Itoa(int(pid))}\n\tdefault:\n\t\tcmd = []string{\"-x\", \"-o\", arg, \"-p\", strconv.Itoa(int(pid))}\n\t}\n\tif nameOption {\n\t\tcmd = append(cmd, \"-c\")\n\t}\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", cmd...)\n\tif err != nil {\n\t\treturn [][]string{}, err\n\t}\n\tlines := strings.Split(string(out), \"\\n\")\n\n\tvar ret [][]string\n\tfor _, l := range lines[1:] {\n\t\tvar lr []string\n\t\tif nameOption {\n\t\t\tlr = append(lr, l)\n\t\t} else {\n\t\t\tfor _, r := range strings.Split(l, \" \") {\n\t\t\t\tif r == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tlr = append(lr, strings.TrimSpace(r))\n\t\t\t}\n\t\t}\n\t\tif len(lr) != 0 {\n\t\t\tret = append(ret, lr)\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n\ntype dlFuncs struct {\n\tlib *common.SystemLib\n}\n\nfunc loadProcFuncs() (*dlFuncs, error) {\n\tlib, err := common.NewSystemLib()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &dlFuncs{lib}, err\n}\n\nfunc (f *dlFuncs) getTimeScaleToNanoSeconds() float64 {\n\tvar timeBaseInfo common.MachTimeBaseInfo\n\n\tf.lib.MachTimeBaseInfo(uintptr(unsafe.Pointer(&timeBaseInfo)))\n\n\treturn float64(timeBaseInfo.Numer) / float64(timeBaseInfo.Denom)\n}\n\nfunc (f *dlFuncs) Close() {\n\tf.lib.Close()\n}\n\nfunc (p *Process) ExeWithContext(_ context.Context) (string, error) {\n\tfuncs, err := loadProcFuncs()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer funcs.Close()\n\n\tbuf := common.NewCStr(common.PROC_PIDPATHINFO_MAXSIZE)\n\tret := funcs.lib.ProcPidPath(p.Pid, buf.Addr(), common.PROC_PIDPATHINFO_MAXSIZE)\n\n\tif ret <= 0 {\n\t\treturn \"\", fmt.Errorf(\"unknown error: proc_pidpath returned %d\", ret)\n\t}\n\n\treturn buf.GoString(), nil\n}\n\n// CwdWithContext retrieves the Current Working Directory for the given process.\n// It uses the proc_pidinfo from libproc and will only work for processes the\n// EUID can access.  Otherwise \"operation not permitted\" will be returned as the\n// error.\n// Note: This might also work for other *BSD OSs.\nfunc (p *Process) CwdWithContext(_ context.Context) (string, error) {\n\tfuncs, err := loadProcFuncs()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer funcs.Close()\n\n\t// Lock OS thread to ensure the errno does not change\n\truntime.LockOSThread()\n\tdefer runtime.UnlockOSThread()\n\n\tvar vpi vnodePathInfo\n\tconst vpiSize = int32(unsafe.Sizeof(vpi))\n\tret := funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize)\n\terrno, _ := funcs.lib.Dlsym(\"errno\")\n\terr = *(**unix.Errno)(unsafe.Pointer(&errno))\n\tif errors.Is(err, unix.EPERM) {\n\t\treturn \"\", ErrorNotPermitted\n\t}\n\n\tif ret <= 0 {\n\t\treturn \"\", fmt.Errorf(\"unknown error: proc_pidinfo returned %d\", ret)\n\t}\n\n\tif ret != vpiSize {\n\t\treturn \"\", fmt.Errorf(\"too few bytes; expected %d, got %d\", vpiSize, ret)\n\t}\n\treturn common.GoString((*byte)(unsafe.Pointer(&vpi.Cdir.Path[0]))), nil\n}\n\nfunc procArgs(pid int32) ([]byte, int, error) {\n\tprocargs, err := unix.SysctlRaw(\"kern.procargs2\", int(pid))\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\t// The first 4 bytes indicate the number of arguments.\n\tnargs := procargs[:4]\n\treturn procargs, int(binary.LittleEndian.Uint32(nargs)), nil\n}\n\nfunc (p *Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {\n\treturn p.cmdlineSlice()\n}\n\nfunc (p *Process) cmdlineSlice() ([]string, error) {\n\tpargs, nargs, err := procArgs(p.Pid)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// The first bytes hold the nargs int, skip it.\n\targs := bytes.Split((pargs)[unsafe.Sizeof(int(0)):], []byte{0})\n\tvar argStr string\n\t// The first element is the actual binary/command path.\n\t// command := args[0]\n\tvar argSlice []string\n\t// var envSlice []string\n\t// All other, non-zero elements are arguments. The first \"nargs\" elements\n\t// are the arguments. Everything else in the slice is then the environment\n\t// of the process.\n\tfor _, arg := range args[1:] {\n\t\targStr = string(arg)\n\t\tif argStr != \"\" {\n\t\t\tif nargs > 0 {\n\t\t\t\targSlice = append(argSlice, argStr)\n\t\t\t\tnargs--\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tbreak\n\t\t\t// envSlice = append(envSlice, argStr)\n\t\t}\n\t}\n\treturn argSlice, err\n}\n\n// cmdNameWithContext returns the command name (including spaces) without any arguments\nfunc (p *Process) cmdNameWithContext(_ context.Context) (string, error) {\n\tr, err := p.cmdlineSlice()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif len(r) == 0 {\n\t\treturn \"\", nil\n\t}\n\n\treturn r[0], err\n}\n\nfunc (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {\n\tr, err := p.CmdlineSliceWithContext(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn strings.Join(r, \" \"), err\n}\n\nfunc (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) {\n\tfuncs, err := loadProcFuncs()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer funcs.Close()\n\n\tvar ti ProcTaskInfo\n\tfuncs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))\n\n\treturn int32(ti.Threadnum), nil\n}\n\nfunc (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {\n\tfuncs, err := loadProcFuncs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer funcs.Close()\n\n\tvar ti ProcTaskInfo\n\tfuncs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))\n\n\ttimescaleToNanoSeconds := funcs.getTimeScaleToNanoSeconds()\n\tret := &cpu.TimesStat{\n\t\tCPU:    \"cpu\",\n\t\tUser:   float64(ti.Total_user) * timescaleToNanoSeconds / 1e9,\n\t\tSystem: float64(ti.Total_system) * timescaleToNanoSeconds / 1e9,\n\t}\n\treturn ret, nil\n}\n\nfunc (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {\n\tfuncs, err := loadProcFuncs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer funcs.Close()\n\n\tvar ti ProcTaskInfo\n\tfuncs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))\n\n\tret := &MemoryInfoStat{\n\t\tRSS: uint64(ti.Resident_size),\n\t\tVMS: uint64(ti.Virtual_size),\n\t}\n\treturn ret, nil\n}\n\n// procFDInfo represents a file descriptor entry from sys/proc_info.h\ntype procFDInfo struct {\n\tProcFd     int32\n\tProcFdtype uint32\n}\n\n// NumFDsWithContext returns the number of file descriptors used by the process.\n// It uses proc_pidinfo with PROC_PIDLISTFDS to query the kernel for the count\n// of open file descriptors. The method makes a single syscall and calculates\n// the count from the buffer size returned by the kernel.\nfunc (p *Process) NumFDsWithContext(_ context.Context) (int32, error) {\n\tfuncs, err := loadProcFuncs()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer funcs.Close()\n\n\t// First call: get required buffer size\n\tbufferSize := funcs.lib.ProcPidInfo(\n\t\tp.Pid,\n\t\tcommon.PROC_PIDLISTFDS,\n\t\t0,\n\t\t0, // NULL buffer\n\t\t0, // 0 size\n\t)\n\tif bufferSize <= 0 {\n\t\treturn 0, fmt.Errorf(\"unknown error: proc_pidinfo returned %d\", bufferSize)\n\t}\n\n\t// Allocate buffer of the required size\n\tconst sizeofProcFDInfo = int32(unsafe.Sizeof(procFDInfo{}))\n\tnumEntries := bufferSize / sizeofProcFDInfo\n\tbuf := make([]procFDInfo, numEntries)\n\n\t// Second call: get actual data\n\tret := funcs.lib.ProcPidInfo(\n\t\tp.Pid,\n\t\tcommon.PROC_PIDLISTFDS,\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&buf[0])), // Real buffer\n\t\tbufferSize,                       // Size from first call\n\t)\n\tif ret <= 0 {\n\t\treturn 0, fmt.Errorf(\"unknown error: proc_pidinfo returned %d\", ret)\n\t}\n\n\t// Calculate actual number of FDs returned\n\tnumFDs := ret / sizeofProcFDInfo\n\treturn numFDs, nil\n}\n"
  },
  {
    "path": "process/process_darwin_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_darwin.go\n\npackage process\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int64\n}\n\ntype Timeval struct {\n\tSec       int64\n\tUsec      int32\n\tPad_cgo_0 [4]byte\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int64\n\tIxrss    int64\n\tIdrss    int64\n\tIsrss    int64\n\tMinflt   int64\n\tMajflt   int64\n\tNswap    int64\n\tInblock  int64\n\tOublock  int64\n\tMsgsnd   int64\n\tMsgrcv   int64\n\tNsignals int64\n\tNvcsw    int64\n\tNivcsw   int64\n}\n\ntype Rlimit struct {\n\tCur uint64\n\tMax uint64\n}\n\ntype UGid_t uint32\n\ntype KinfoProc struct {\n\tProc  ExternProc\n\tEproc Eproc\n}\n\ntype Eproc struct {\n\tPaddr     *uint64\n\tSess      *Session\n\tPcred     Upcred\n\tUcred     Uucred\n\tPad_cgo_0 [4]byte\n\tVm        Vmspace\n\tPpid      int32\n\tPgid      int32\n\tJobc      int16\n\tPad_cgo_1 [2]byte\n\tTdev      int32\n\tTpgid     int32\n\tPad_cgo_2 [4]byte\n\tTsess     *Session\n\tWmesg     [8]int8\n\tXsize     int32\n\tXrssize   int16\n\tXccount   int16\n\tXswrss    int16\n\tPad_cgo_3 [2]byte\n\tFlag      int32\n\tLogin     [12]int8\n\tSpare     [4]int32\n\tPad_cgo_4 [4]byte\n}\n\ntype Proc struct{}\n\ntype Session struct{}\n\ntype ucred struct {\n\tLink  _Ctype_struct___0\n\tRef   uint64\n\tPosix Posix_cred\n\tLabel *Label\n\tAudit Au_session\n}\n\ntype Uucred struct {\n\tRef       int32\n\tUID       uint32\n\tNgroups   int16\n\tPad_cgo_0 [2]byte\n\tGroups    [16]uint32\n}\n\ntype Upcred struct {\n\tPc_lock   [72]int8\n\tPc_ucred  *ucred\n\tP_ruid    uint32\n\tP_svuid   uint32\n\tP_rgid    uint32\n\tP_svgid   uint32\n\tP_refcnt  int32\n\tPad_cgo_0 [4]byte\n}\n\ntype Vmspace struct {\n\tDummy     int32\n\tPad_cgo_0 [4]byte\n\tDummy2    *int8\n\tDummy3    [5]int32\n\tPad_cgo_1 [4]byte\n\tDummy4    [3]*int8\n}\n\ntype Sigacts struct{}\n\ntype ExternProc struct {\n\tP_un        [16]byte\n\tP_vmspace   uint64\n\tP_sigacts   uint64\n\tPad_cgo_0   [3]byte\n\tP_flag      int32\n\tP_stat      int8\n\tP_pid       int32\n\tP_oppid     int32\n\tP_dupfd     int32\n\tPad_cgo_1   [4]byte\n\tUser_stack  uint64\n\tExit_thread uint64\n\tP_debugger  int32\n\tSigwait     int32\n\tP_estcpu    uint32\n\tP_cpticks   int32\n\tP_pctcpu    uint32\n\tPad_cgo_2   [4]byte\n\tP_wchan     uint64\n\tP_wmesg     uint64\n\tP_swtime    uint32\n\tP_slptime   uint32\n\tP_realtimer Itimerval\n\tP_rtime     Timeval\n\tP_uticks    uint64\n\tP_sticks    uint64\n\tP_iticks    uint64\n\tP_traceflag int32\n\tPad_cgo_3   [4]byte\n\tP_tracep    uint64\n\tP_siglist   int32\n\tPad_cgo_4   [4]byte\n\tP_textvp    uint64\n\tP_holdcnt   int32\n\tP_sigmask   uint32\n\tP_sigignore uint32\n\tP_sigcatch  uint32\n\tP_priority  uint8\n\tP_usrpri    uint8\n\tP_nice      int8\n\tP_comm      [17]int8\n\tPad_cgo_5   [4]byte\n\tP_pgrp      uint64\n\tP_addr      uint64\n\tP_xstat     uint16\n\tP_acflag    uint16\n\tPad_cgo_6   [4]byte\n\tP_ru        uint64\n}\n\ntype Itimerval struct {\n\tInterval Timeval\n\tValue    Timeval\n}\n\ntype Vnode struct{}\n\ntype Pgrp struct{}\n\ntype UserStruct struct{}\n\ntype Au_session struct {\n\tAia_p *AuditinfoAddr\n\tMask  AuMask\n}\n\ntype Posix_cred struct {\n\tUID       uint32\n\tRuid      uint32\n\tSvuid     uint32\n\tNgroups   int16\n\tPad_cgo_0 [2]byte\n\tGroups    [16]uint32\n\tRgid      uint32\n\tSvgid     uint32\n\tGmuid     uint32\n\tFlags     int32\n}\n\ntype Label struct{}\n\ntype ProcTaskInfo struct {\n\tVirtual_size      uint64\n\tResident_size     uint64\n\tTotal_user        uint64\n\tTotal_system      uint64\n\tThreads_user      uint64\n\tThreads_system    uint64\n\tPolicy            int32\n\tFaults            int32\n\tPageins           int32\n\tCow_faults        int32\n\tMessages_sent     int32\n\tMessages_received int32\n\tSyscalls_mach     int32\n\tSyscalls_unix     int32\n\tCsw               int32\n\tThreadnum         int32\n\tNumrunning        int32\n\tPriority          int32\n}\n\ntype vinfoStat struct {\n\tDev           uint32\n\tMode          uint16\n\tNlink         uint16\n\tIno           uint64\n\tUid           uint32\n\tGid           uint32\n\tAtime         int64\n\tAtimensec     int64\n\tMtime         int64\n\tMtimensec     int64\n\tCtime         int64\n\tCtimensec     int64\n\tBirthtime     int64\n\tBirthtimensec int64\n\tSize          int64\n\tBlocks        int64\n\tBlksize       int32\n\tFlags         uint32\n\tGen           uint32\n\tRdev          uint32\n\tQspare        [2]int64\n}\n\ntype fsid struct {\n\tVal [2]int32\n}\n\ntype vnodeInfo struct {\n\tStat vinfoStat\n\tType int32\n\tPad  int32\n\tFsid fsid\n}\n\ntype vnodeInfoPath struct {\n\tVi   vnodeInfo\n\tPath [1024]int8\n}\n\ntype vnodePathInfo struct {\n\tCdir vnodeInfoPath\n\tRdir vnodeInfoPath\n}\n\ntype AuditinfoAddr struct {\n\tAuid   uint32\n\tMask   AuMask\n\tTermid AuTidAddr\n\tAsid   int32\n\tFlags  uint64\n}\n\ntype AuMask struct {\n\tSuccess uint32\n\tFailure uint32\n}\n\ntype AuTidAddr struct {\n\tPort int32\n\tType uint32\n\tAddr [4]uint32\n}\n\ntype UcredQueue struct {\n\tNext *ucred\n\tPrev **ucred\n}\n"
  },
  {
    "path": "process/process_darwin_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs process/types_darwin.go\n\npackage process\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int64\n}\n\ntype Timeval struct {\n\tSec       int64\n\tUsec      int32\n\tPad_cgo_0 [4]byte\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int64\n\tIxrss    int64\n\tIdrss    int64\n\tIsrss    int64\n\tMinflt   int64\n\tMajflt   int64\n\tNswap    int64\n\tInblock  int64\n\tOublock  int64\n\tMsgsnd   int64\n\tMsgrcv   int64\n\tNsignals int64\n\tNvcsw    int64\n\tNivcsw   int64\n}\n\ntype Rlimit struct {\n\tCur uint64\n\tMax uint64\n}\n\ntype UGid_t uint32\n\ntype KinfoProc struct {\n\tProc  ExternProc\n\tEproc Eproc\n}\n\ntype Eproc struct {\n\tPaddr     *Proc\n\tSess      *Session\n\tPcred     Upcred\n\tUcred     Uucred\n\tVm        Vmspace\n\tPpid      int32\n\tPgid      int32\n\tJobc      int16\n\tTdev      int32\n\tTpgid     int32\n\tTsess     *Session\n\tWmesg     [8]int8\n\tXsize     int32\n\tXrssize   int16\n\tXccount   int16\n\tXswrss    int16\n\tFlag      int32\n\tLogin     [12]int8\n\tSpare     [4]int32\n\tPad_cgo_0 [4]byte\n}\n\ntype Proc struct{}\n\ntype Session struct{}\n\ntype ucred struct{}\n\ntype Uucred struct {\n\tRef     int32\n\tUID     uint32\n\tNgroups int16\n\tGroups  [16]uint32\n}\n\ntype Upcred struct {\n\tPc_lock   [72]int8\n\tPc_ucred  *ucred\n\tP_ruid    uint32\n\tP_svuid   uint32\n\tP_rgid    uint32\n\tP_svgid   uint32\n\tP_refcnt  int32\n\tPad_cgo_0 [4]byte\n}\n\ntype Vmspace struct {\n\tDummy  int32\n\tDummy2 *int8\n\tDummy3 [5]int32\n\tDummy4 [3]*int8\n}\n\ntype Sigacts struct{}\n\ntype ExternProc struct {\n\tP_un        [16]byte\n\tP_vmspace   uint64\n\tP_sigacts   uint64\n\tPad_cgo_0   [3]byte\n\tP_flag      int32\n\tP_stat      int8\n\tP_pid       int32\n\tP_oppid     int32\n\tP_dupfd     int32\n\tPad_cgo_1   [4]byte\n\tUser_stack  uint64\n\tExit_thread uint64\n\tP_debugger  int32\n\tSigwait     int32\n\tP_estcpu    uint32\n\tP_cpticks   int32\n\tP_pctcpu    uint32\n\tPad_cgo_2   [4]byte\n\tP_wchan     uint64\n\tP_wmesg     uint64\n\tP_swtime    uint32\n\tP_slptime   uint32\n\tP_realtimer Itimerval\n\tP_rtime     Timeval\n\tP_uticks    uint64\n\tP_sticks    uint64\n\tP_iticks    uint64\n\tP_traceflag int32\n\tPad_cgo_3   [4]byte\n\tP_tracep    uint64\n\tP_siglist   int32\n\tPad_cgo_4   [4]byte\n\tP_textvp    uint64\n\tP_holdcnt   int32\n\tP_sigmask   uint32\n\tP_sigignore uint32\n\tP_sigcatch  uint32\n\tP_priority  uint8\n\tP_usrpri    uint8\n\tP_nice      int8\n\tP_comm      [17]int8\n\tPad_cgo_5   [4]byte\n\tP_pgrp      uint64\n\tP_addr      uint64\n\tP_xstat     uint16\n\tP_acflag    uint16\n\tPad_cgo_6   [4]byte\n\tP_ru        uint64\n}\n\ntype Itimerval struct {\n\tInterval Timeval\n\tValue    Timeval\n}\n\ntype Vnode struct{}\n\ntype Pgrp struct{}\n\ntype UserStruct struct{}\n\ntype Au_session struct {\n\tAia_p *AuditinfoAddr\n\tMask  AuMask\n}\n\ntype Posix_cred struct{}\n\ntype Label struct{}\n\ntype ProcTaskInfo struct {\n\tVirtual_size      uint64\n\tResident_size     uint64\n\tTotal_user        uint64\n\tTotal_system      uint64\n\tThreads_user      uint64\n\tThreads_system    uint64\n\tPolicy            int32\n\tFaults            int32\n\tPageins           int32\n\tCow_faults        int32\n\tMessages_sent     int32\n\tMessages_received int32\n\tSyscalls_mach     int32\n\tSyscalls_unix     int32\n\tCsw               int32\n\tThreadnum         int32\n\tNumrunning        int32\n\tPriority          int32\n}\n\ntype vinfoStat struct {\n\tDev           uint32\n\tMode          uint16\n\tNlink         uint16\n\tIno           uint64\n\tUid           uint32\n\tGid           uint32\n\tAtime         int64\n\tAtimensec     int64\n\tMtime         int64\n\tMtimensec     int64\n\tCtime         int64\n\tCtimensec     int64\n\tBirthtime     int64\n\tBirthtimensec int64\n\tSize          int64\n\tBlocks        int64\n\tBlksize       int32\n\tFlags         uint32\n\tGen           uint32\n\tRdev          uint32\n\tQspare        [2]int64\n}\n\ntype fsid struct {\n\tVal [2]int32\n}\n\ntype vnodeInfo struct {\n\tStat vinfoStat\n\tType int32\n\tPad  int32\n\tFsid fsid\n}\n\ntype vnodeInfoPath struct {\n\tVi   vnodeInfo\n\tPath [1024]int8\n}\n\ntype vnodePathInfo struct {\n\tCdir vnodeInfoPath\n\tRdir vnodeInfoPath\n}\n\ntype AuditinfoAddr struct {\n\tAuid   uint32\n\tMask   AuMask\n\tTermid AuTidAddr\n\tAsid   int32\n\tFlags  uint64\n}\ntype AuMask struct {\n\tSuccess uint32\n\tFailure uint32\n}\ntype AuTidAddr struct {\n\tPort int32\n\tType uint32\n\tAddr [4]uint32\n}\n\ntype UcredQueue struct {\n\tNext *ucred\n\tPrev **ucred\n}\n"
  },
  {
    "path": "process/process_darwin_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin\n\npackage process\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNumFDs(t *testing.T) {\n\tpid := os.Getpid()\n\tp, err := NewProcess(int32(pid))\n\trequire.NoError(t, err)\n\n\tctx := context.Background()\n\n\tbefore, err := p.NumFDsWithContext(ctx)\n\trequire.NoError(t, err)\n\n\t// Open files to increase FD count\n\tf1, err := os.Open(\"/dev/null\")\n\trequire.NoError(t, err)\n\tdefer f1.Close()\n\n\tf2, err := os.Open(\"/dev/null\")\n\trequire.NoError(t, err)\n\tdefer f2.Close()\n\n\tafter, err := p.NumFDsWithContext(ctx)\n\trequire.NoError(t, err)\n\n\tassert.GreaterOrEqual(t, after, before+2)\n}\n\nfunc TestNumFDs_NonExistent(t *testing.T) {\n\tp := &Process{Pid: 99999}\n\t_, err := p.NumFDsWithContext(context.Background())\n\tassert.Error(t, err)\n}\n\nfunc BenchmarkNumFDs(b *testing.B) {\n\tpid := int32(os.Getpid())\n\tp, err := NewProcess(pid)\n\tif err != nil {\n\t\tb.Skip(err)\n\t}\n\n\tctx := context.Background()\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_, err := p.NumFDsWithContext(ctx)\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "process/process_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !plan9\n\npackage process\n\nimport (\n\t\"context\"\n\t\"syscall\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\ntype Signal = syscall.Signal\n\ntype MemoryMapsStat struct {\n\tPath         string `json:\"path\"`\n\tRss          uint64 `json:\"rss\"`\n\tSize         uint64 `json:\"size\"`\n\tPss          uint64 `json:\"pss\"`\n\tSharedClean  uint64 `json:\"sharedClean\"`\n\tSharedDirty  uint64 `json:\"sharedDirty\"`\n\tPrivateClean uint64 `json:\"privateClean\"`\n\tPrivateDirty uint64 `json:\"privateDirty\"`\n\tReferenced   uint64 `json:\"referenced\"`\n\tAnonymous    uint64 `json:\"anonymous\"`\n\tSwap         uint64 `json:\"swap\"`\n}\n\ntype MemoryInfoExStat struct{}\n\nfunc pidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProcessesWithContext(_ context.Context) ([]*Process, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc PidExistsWithContext(_ context.Context, _ int32) (bool, error) {\n\treturn false, common.ErrNotImplementedError\n}\n\nfunc (*Process) PpidWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) NameWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) TgidWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) ExeWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) CmdlineWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) createTimeWithContext(_ context.Context) (int64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) CwdWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) StatusWithContext(_ context.Context) ([]string, error) {\n\treturn []string{\"\"}, common.ErrNotImplementedError\n}\n\nfunc (*Process) ForegroundWithContext(_ context.Context) (bool, error) {\n\treturn false, common.ErrNotImplementedError\n}\n\nfunc (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) TerminalWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) NiceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) IOniceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) NumFDsWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) SendSignalWithContext(_ context.Context, _ Signal) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) SuspendWithContext(_ context.Context) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) ResumeWithContext(_ context.Context) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) TerminateWithContext(_ context.Context) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) KillWithContext(_ context.Context) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) UsernameWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) EnvironWithContext(_ context.Context) ([]string, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "process/process_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd\n\npackage process\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\nfunc pidsWithContext(ctx context.Context) ([]int32, error) {\n\tvar ret []int32\n\tprocs, err := ProcessesWithContext(ctx)\n\tif err != nil {\n\t\treturn ret, nil\n\t}\n\n\tfor _, p := range procs {\n\t\tret = append(ret, p.Pid)\n\t}\n\n\treturn ret, nil\n}\n\nfunc (p *Process) PpidWithContext(_ context.Context) (int32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn k.Ppid, nil\n}\n\nfunc (p *Process) NameWithContext(ctx context.Context) (string, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tname := common.IntToString(k.Comm[:])\n\n\tif len(name) >= 15 {\n\t\tcmdlineSlice, err := p.CmdlineSliceWithContext(ctx)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif len(cmdlineSlice) > 0 {\n\t\t\textendedName := filepath.Base(cmdlineSlice[0])\n\t\t\tif strings.HasPrefix(extendedName, p.name) {\n\t\t\t\tname = extendedName\n\t\t\t}\n\t\t}\n\t}\n\n\treturn name, nil\n}\n\nfunc (p *Process) CwdWithContext(_ context.Context) (string, error) {\n\tmib := []int32{CTLKern, KernProc, KernProcCwd, p.Pid}\n\tbuf, length, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif length != sizeOfKinfoFile {\n\t\treturn \"\", errors.New(\"unexpected size of KinfoFile\")\n\t}\n\n\tvar k kinfoFile\n\tbr := bytes.NewReader(buf)\n\tif err := binary.Read(br, binary.LittleEndian, &k); err != nil {\n\t\treturn \"\", err\n\t}\n\tcwd := common.IntToString(k.Path[:])\n\n\treturn cwd, nil\n}\n\nfunc (p *Process) ExeWithContext(_ context.Context) (string, error) {\n\tmib := []int32{CTLKern, KernProc, KernProcPathname, p.Pid}\n\tbuf, _, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn strings.Trim(string(buf), \"\\x00\"), nil\n}\n\nfunc (p *Process) CmdlineWithContext(_ context.Context) (string, error) {\n\tmib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}\n\tbuf, _, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tret := strings.FieldsFunc(string(buf), func(r rune) bool {\n\t\treturn r == '\\u0000'\n\t})\n\n\treturn strings.Join(ret, \" \"), nil\n}\n\nfunc (p *Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {\n\tmib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}\n\tbuf, _, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(buf) == 0 {\n\t\treturn nil, nil\n\t}\n\tif buf[len(buf)-1] == 0 {\n\t\tbuf = buf[:len(buf)-1]\n\t}\n\tparts := bytes.Split(buf, []byte{0})\n\tvar strParts []string\n\tfor _, p := range parts {\n\t\tstrParts = append(strParts, string(p))\n\t}\n\n\treturn strParts, nil\n}\n\nfunc (p *Process) createTimeWithContext(_ context.Context) (int64, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int64(k.Start.Sec)*1000 + int64(k.Start.Usec)/1000, nil\n}\n\nfunc (p *Process) StatusWithContext(_ context.Context) ([]string, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn []string{\"\"}, err\n\t}\n\tvar s string\n\tswitch k.Stat {\n\tcase SIDL:\n\t\ts = Idle\n\tcase SRUN:\n\t\ts = Running\n\tcase SSLEEP:\n\t\ts = Sleep\n\tcase SSTOP:\n\t\ts = Stop\n\tcase SZOMB:\n\t\ts = Zombie\n\tcase SWAIT:\n\t\ts = Wait\n\tcase SLOCK:\n\t\ts = Lock\n\t}\n\n\treturn []string{s}, nil\n}\n\nfunc (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {\n\t// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details\n\tpid := p.Pid\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", \"-o\", \"stat=\", \"-p\", strconv.Itoa(int(pid)))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn strings.IndexByte(string(out), '+') != -1, nil\n}\n\nfunc (p *Process) UidsWithContext(_ context.Context) ([]uint32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tuids := make([]uint32, 0, 3)\n\n\tuids = append(uids, uint32(k.Ruid), uint32(k.Uid), uint32(k.Svuid))\n\n\treturn uids, nil\n}\n\nfunc (p *Process) GidsWithContext(_ context.Context) ([]uint32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgids := make([]uint32, 0, 3)\n\tgids = append(gids, uint32(k.Rgid), uint32(k.Ngroups), uint32(k.Svgid))\n\n\treturn gids, nil\n}\n\nfunc (p *Process) GroupsWithContext(_ context.Context) ([]uint32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgroups := make([]uint32, k.Ngroups)\n\tfor i := int16(0); i < k.Ngroups; i++ {\n\t\tgroups[i] = uint32(k.Groups[i])\n\t}\n\n\treturn groups, nil\n}\n\nfunc (p *Process) TerminalWithContext(_ context.Context) (string, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tttyNr := uint64(k.Tdev)\n\n\ttermmap, err := getTerminalMap()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn termmap[ttyNr], nil\n}\n\nfunc (p *Process) NiceWithContext(_ context.Context) (int32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int32(k.Nice), nil\n}\n\nfunc (p *Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &IOCountersStat{\n\t\tReadCount:  uint64(k.Rusage.Inblock),\n\t\tWriteCount: uint64(k.Rusage.Oublock),\n\t}, nil\n}\n\nfunc (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn k.Numthreads, nil\n}\n\nfunc (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &cpu.TimesStat{\n\t\tCPU:    \"cpu\",\n\t\tUser:   float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000,\n\t\tSystem: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000,\n\t}, nil\n}\n\nfunc (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tv, err := unix.Sysctl(\"vm.stats.vm.v_page_size\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpageSize := binary.LittleEndian.Uint16([]byte(v))\n\n\treturn &MemoryInfoStat{\n\t\tRSS: uint64(k.Rssize) * uint64(pageSize),\n\t\tVMS: uint64(k.Size),\n\t}, nil\n}\n\nfunc (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {\n\tprocs, err := ProcessesWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil\n\t}\n\tret := make([]*Process, 0, len(procs))\n\tfor _, proc := range procs {\n\t\tppid, err := proc.PpidWithContext(ctx)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif ppid == p.Pid {\n\t\t\tret = append(ret, proc)\n\t\t}\n\t}\n\tsort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })\n\treturn ret, nil\n}\n\nfunc (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {\n\treturn net.ConnectionsPidWithContext(ctx, \"all\", p.Pid)\n}\n\nfunc (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {\n\treturn net.ConnectionsPidMaxWithContext(ctx, \"all\", p.Pid, maxConn)\n}\n\nfunc ProcessesWithContext(ctx context.Context) ([]*Process, error) {\n\tresults := []*Process{}\n\n\tmib := []int32{CTLKern, KernProc, KernProcProc, 0}\n\tbuf, length, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn results, err\n\t}\n\n\t// get kinfo_proc size\n\tcount := int(length / uint64(sizeOfKinfoProc))\n\n\t// parse buf to procs\n\tfor i := 0; i < count; i++ {\n\t\tb := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]\n\t\tk, err := parseKinfoProc(b)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tp, err := NewProcessWithContext(ctx, int32(k.Pid))\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tresults = append(results, p)\n\t}\n\n\treturn results, nil\n}\n\nfunc (*Process) NumFDsWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (p *Process) getKProc() (*KinfoProc, error) {\n\tmib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}\n\n\tbuf, length, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif length != sizeOfKinfoProc {\n\t\treturn nil, errors.New(\"unexpected size of KinfoProc\")\n\t}\n\n\tk, err := parseKinfoProc(buf)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &k, nil\n}\n"
  },
  {
    "path": "process/process_freebsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_freebsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 14\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 7\n\tKernProcCwd      = 42\n)\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x488\n\tsizeOfKinfoProc    = 0x300\n\tsizeOfKinfoFile    = 0x570 // TODO: should be changed by running on the target machine\n)\n\nconst (\n\tSIDL   = 1\n\tSRUN   = 2\n\tSSLEEP = 3\n\tSSTOP  = 4\n\tSZOMB  = 5\n\tSWAIT  = 6\n\tSLOCK  = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int32\n\tNsec int32\n}\n\ntype Timeval struct {\n\tSec  int32\n\tUsec int32\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int32\n\tIxrss    int32\n\tIdrss    int32\n\tIsrss    int32\n\tMinflt   int32\n\tMajflt   int32\n\tNswap    int32\n\tInblock  int32\n\tOublock  int32\n\tMsgsnd   int32\n\tMsgrcv   int32\n\tNsignals int32\n\tNvcsw    int32\n\tNivcsw   int32\n}\n\ntype Rlimit struct {\n\tCur int64\n\tMax int64\n}\n\ntype KinfoProc struct {\n\tStructsize   int32\n\tLayout       int32\n\tArgs         int32 /* pargs */\n\tPaddr        int32 /* proc */\n\tAddr         int32 /* user */\n\tTracep       int32 /* vnode */\n\tTextvp       int32 /* vnode */\n\tFd           int32 /* filedesc */\n\tVmspace      int32 /* vmspace */\n\tWchan        int32\n\tPid          int32\n\tPpid         int32\n\tPgid         int32\n\tTpgid        int32\n\tSid          int32\n\tTsid         int32\n\tJobc         int16\n\tSpare_short1 int16\n\tTdev         uint32\n\tSiglist      [16]byte /* sigset */\n\tSigmask      [16]byte /* sigset */\n\tSigignore    [16]byte /* sigset */\n\tSigcatch     [16]byte /* sigset */\n\tUid          uint32\n\tRuid         uint32\n\tSvuid        uint32\n\tRgid         uint32\n\tSvgid        uint32\n\tNgroups      int16\n\tSpare_short2 int16\n\tGroups       [16]uint32\n\tSize         uint32\n\tRssize       int32\n\tSwrss        int32\n\tTsize        int32\n\tDsize        int32\n\tSsize        int32\n\tXstat        uint16\n\tAcflag       uint16\n\tPctcpu       uint32\n\tEstcpu       uint32\n\tSlptime      uint32\n\tSwtime       uint32\n\tCow          uint32\n\tRuntime      uint64\n\tStart        Timeval\n\tChildtime    Timeval\n\tFlag         int32\n\tKiflag       int32\n\tTraceflag    int32\n\tStat         int8\n\tNice         int8\n\tLock         int8\n\tRqindex      int8\n\tOncpu        uint8\n\tLastcpu      uint8\n\tTdname       [17]int8\n\tWmesg        [9]int8\n\tLogin        [18]int8\n\tLockname     [9]int8\n\tComm         [20]int8\n\tEmul         [17]int8\n\tLoginclass   [18]int8\n\tSparestrings [50]int8\n\tSpareints    [7]int32\n\tFlag2        int32\n\tFibnum       int32\n\tCr_flags     uint32\n\tJid          int32\n\tNumthreads   int32\n\tTid          int32\n\tPri          Priority\n\tRusage       Rusage\n\tRusage_ch    Rusage\n\tPcb          int32 /* pcb */\n\tKstack       int32\n\tUdata        int32\n\tTdaddr       int32 /* thread */\n\tSpareptrs    [6]int32\n\tSparelongs   [12]int32\n\tSflag        int32\n\tTdflags      int32\n}\n\ntype Priority struct {\n\tClass  uint8\n\tLevel  uint8\n\tNative uint8\n\tUser   uint8\n}\n\ntype KinfoVmentry struct {\n\tStructsize       int32\n\tType             int32\n\tStart            uint64\n\tEnd              uint64\n\tOffset           uint64\n\tVn_fileid        uint64\n\tVn_fsid          uint32\n\tFlags            int32\n\tResident         int32\n\tPrivate_resident int32\n\tProtection       int32\n\tRef_count        int32\n\tShadow_count     int32\n\tVn_type          int32\n\tVn_size          uint64\n\tVn_rdev          uint32\n\tVn_mode          uint16\n\tStatus           uint16\n\tX_kve_ispare     [12]int32\n\tPath             [1024]int8\n}\n\n// TODO: should be changed by running on the target machine\ntype kinfoFile struct {\n\tStructsize     int32\n\tType           int32\n\tFd             int32\n\tRef_count      int32\n\tFlags          int32\n\tPad0           int32\n\tOffset         int64\n\tAnon0          [304]byte\n\tStatus         uint16\n\tPad1           uint16\n\tX_kf_ispare0   int32\n\tCap_rights     capRights\n\tX_kf_cap_spare uint64\n\tPath           [1024]int8 // changed from uint8 by hand\n}\n\n// TODO: should be changed by running on the target machine\ntype capRights struct {\n\tRights [2]uint64\n}\n"
  },
  {
    "path": "process/process_freebsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs types_freebsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 14\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 7\n\tKernProcCwd      = 42\n)\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x488\n\tsizeOfKinfoProc    = 0x440\n\tsizeOfKinfoFile    = 0x570\n)\n\nconst (\n\tSIDL   = 1\n\tSRUN   = 2\n\tSSLEEP = 3\n\tSSTOP  = 4\n\tSZOMB  = 5\n\tSWAIT  = 6\n\tSLOCK  = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int64\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int64\n\tIxrss    int64\n\tIdrss    int64\n\tIsrss    int64\n\tMinflt   int64\n\tMajflt   int64\n\tNswap    int64\n\tInblock  int64\n\tOublock  int64\n\tMsgsnd   int64\n\tMsgrcv   int64\n\tNsignals int64\n\tNvcsw    int64\n\tNivcsw   int64\n}\n\ntype Rlimit struct {\n\tCur int64\n\tMax int64\n}\n\ntype KinfoProc struct {\n\tStructsize     int32\n\tLayout         int32\n\tArgs           int64 /* pargs */\n\tPaddr          int64 /* proc */\n\tAddr           int64 /* user */\n\tTracep         int64 /* vnode */\n\tTextvp         int64 /* vnode */\n\tFd             int64 /* filedesc */\n\tVmspace        int64 /* vmspace */\n\tWchan          int64\n\tPid            int32\n\tPpid           int32\n\tPgid           int32\n\tTpgid          int32\n\tSid            int32\n\tTsid           int32\n\tJobc           int16\n\tSpare_short1   int16\n\tTdev_freebsd11 uint32\n\tSiglist        [16]byte /* sigset */\n\tSigmask        [16]byte /* sigset */\n\tSigignore      [16]byte /* sigset */\n\tSigcatch       [16]byte /* sigset */\n\tUid            uint32\n\tRuid           uint32\n\tSvuid          uint32\n\tRgid           uint32\n\tSvgid          uint32\n\tNgroups        int16\n\tSpare_short2   int16\n\tGroups         [16]uint32\n\tSize           uint64\n\tRssize         int64\n\tSwrss          int64\n\tTsize          int64\n\tDsize          int64\n\tSsize          int64\n\tXstat          uint16\n\tAcflag         uint16\n\tPctcpu         uint32\n\tEstcpu         uint32\n\tSlptime        uint32\n\tSwtime         uint32\n\tCow            uint32\n\tRuntime        uint64\n\tStart          Timeval\n\tChildtime      Timeval\n\tFlag           int64\n\tKiflag         int64\n\tTraceflag      int32\n\tStat           int8\n\tNice           int8\n\tLock           int8\n\tRqindex        int8\n\tOncpu_old      uint8\n\tLastcpu_old    uint8\n\tTdname         [17]int8\n\tWmesg          [9]int8\n\tLogin          [18]int8\n\tLockname       [9]int8\n\tComm           [20]int8\n\tEmul           [17]int8\n\tLoginclass     [18]int8\n\tMoretdname     [4]int8\n\tSparestrings   [46]int8\n\tSpareints      [2]int32\n\tTdev           uint64\n\tOncpu          int32\n\tLastcpu        int32\n\tTracer         int32\n\tFlag2          int32\n\tFibnum         int32\n\tCr_flags       uint32\n\tJid            int32\n\tNumthreads     int32\n\tTid            int32\n\tPri            Priority\n\tRusage         Rusage\n\tRusage_ch      Rusage\n\tPcb            int64 /* pcb */\n\tKstack         int64\n\tUdata          int64\n\tTdaddr         int64 /* thread */\n\tPd             int64 /* pwddesc, not accurate */\n\tSpareptrs      [5]int64\n\tSparelongs     [12]int64\n\tSflag          int64\n\tTdflags        int64\n}\n\ntype Priority struct {\n\tClass  uint8\n\tLevel  uint8\n\tNative uint8\n\tUser   uint8\n}\n\ntype KinfoVmentry struct {\n\tStructsize        int32\n\tType              int32\n\tStart             uint64\n\tEnd               uint64\n\tOffset            uint64\n\tVn_fileid         uint64\n\tVn_fsid_freebsd11 uint32\n\tFlags             int32\n\tResident          int32\n\tPrivate_resident  int32\n\tProtection        int32\n\tRef_count         int32\n\tShadow_count      int32\n\tVn_type           int32\n\tVn_size           uint64\n\tVn_rdev_freebsd11 uint32\n\tVn_mode           uint16\n\tStatus            uint16\n\tType_spec         [8]byte\n\tVn_rdev           uint64\n\tX_kve_ispare      [8]int32\n\tPath              [1024]int8\n}\n\ntype kinfoFile struct {\n\tStructsize     int32\n\tType           int32\n\tFd             int32\n\tRef_count      int32\n\tFlags          int32\n\tPad0           int32\n\tOffset         int64\n\tAnon0          [304]byte\n\tStatus         uint16\n\tPad1           uint16\n\tX_kf_ispare0   int32\n\tCap_rights     capRights\n\tX_kf_cap_spare uint64\n\tPath           [1024]int8\n}\n\ntype capRights struct {\n\tRights [2]uint64\n}\n"
  },
  {
    "path": "process/process_freebsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_freebsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 14\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 7\n\tKernProcCwd      = 42\n)\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x488\n\tsizeOfKinfoProc    = 0x440\n\tsizeOfKinfoFile    = 0x570 // TODO: should be changed by running on the target machine\n)\n\nconst (\n\tSIDL   = 1\n\tSRUN   = 2\n\tSSLEEP = 3\n\tSSTOP  = 4\n\tSZOMB  = 5\n\tSWAIT  = 6\n\tSLOCK  = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int64\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int32\n\tIxrss    int32\n\tIdrss    int32\n\tIsrss    int32\n\tMinflt   int32\n\tMajflt   int32\n\tNswap    int32\n\tInblock  int32\n\tOublock  int32\n\tMsgsnd   int32\n\tMsgrcv   int32\n\tNsignals int32\n\tNvcsw    int32\n\tNivcsw   int32\n}\n\ntype Rlimit struct {\n\tCur int32\n\tMax int32\n}\n\ntype KinfoProc struct {\n\tStructsize   int32\n\tLayout       int32\n\tArgs         int32 /* pargs */\n\tPaddr        int32 /* proc */\n\tAddr         int32 /* user */\n\tTracep       int32 /* vnode */\n\tTextvp       int32 /* vnode */\n\tFd           int32 /* filedesc */\n\tVmspace      int32 /* vmspace */\n\tWchan        int32\n\tPid          int32\n\tPpid         int32\n\tPgid         int32\n\tTpgid        int32\n\tSid          int32\n\tTsid         int32\n\tJobc         int16\n\tSpare_short1 int16\n\tTdev         uint32\n\tSiglist      [16]byte /* sigset */\n\tSigmask      [16]byte /* sigset */\n\tSigignore    [16]byte /* sigset */\n\tSigcatch     [16]byte /* sigset */\n\tUid          uint32\n\tRuid         uint32\n\tSvuid        uint32\n\tRgid         uint32\n\tSvgid        uint32\n\tNgroups      int16\n\tSpare_short2 int16\n\tGroups       [16]uint32\n\tSize         uint32\n\tRssize       int32\n\tSwrss        int32\n\tTsize        int32\n\tDsize        int32\n\tSsize        int32\n\tXstat        uint16\n\tAcflag       uint16\n\tPctcpu       uint32\n\tEstcpu       uint32\n\tSlptime      uint32\n\tSwtime       uint32\n\tCow          uint32\n\tRuntime      uint64\n\tStart        Timeval\n\tChildtime    Timeval\n\tFlag         int32\n\tKiflag       int32\n\tTraceflag    int32\n\tStat         int8\n\tNice         int8\n\tLock         int8\n\tRqindex      int8\n\tOncpu        uint8\n\tLastcpu      uint8\n\tTdname       [17]int8\n\tWmesg        [9]int8\n\tLogin        [18]int8\n\tLockname     [9]int8\n\tComm         [20]int8\n\tEmul         [17]int8\n\tLoginclass   [18]int8\n\tSparestrings [50]int8\n\tSpareints    [4]int32\n\tFlag2        int32\n\tFibnum       int32\n\tCr_flags     uint32\n\tJid          int32\n\tNumthreads   int32\n\tTid          int32\n\tPri          Priority\n\tRusage       Rusage\n\tRusage_ch    Rusage\n\tPcb          int32 /* pcb */\n\tKstack       int32\n\tUdata        int32\n\tTdaddr       int32 /* thread */\n\tSpareptrs    [6]int64\n\tSparelongs   [12]int64\n\tSflag        int64\n\tTdflags      int64\n}\n\ntype Priority struct {\n\tClass  uint8\n\tLevel  uint8\n\tNative uint8\n\tUser   uint8\n}\n\ntype KinfoVmentry struct {\n\tStructsize       int32\n\tType             int32\n\tStart            uint64\n\tEnd              uint64\n\tOffset           uint64\n\tVn_fileid        uint64\n\tVn_fsid          uint32\n\tFlags            int32\n\tResident         int32\n\tPrivate_resident int32\n\tProtection       int32\n\tRef_count        int32\n\tShadow_count     int32\n\tVn_type          int32\n\tVn_size          uint64\n\tVn_rdev          uint32\n\tVn_mode          uint16\n\tStatus           uint16\n\tX_kve_ispare     [12]int32\n\tPath             [1024]int8\n}\n\n// TODO: should be changed by running on the target machine\ntype kinfoFile struct {\n\tStructsize     int32\n\tType           int32\n\tFd             int32\n\tRef_count      int32\n\tFlags          int32\n\tPad0           int32\n\tOffset         int64\n\tAnon0          [304]byte\n\tStatus         uint16\n\tPad1           uint16\n\tX_kf_ispare0   int32\n\tCap_rights     capRights\n\tX_kf_cap_spare uint64\n\tPath           [1024]int8 // changed from uint8 by hand\n}\n\n// TODO: should be changed by running on the target machine\ntype capRights struct {\n\tRights [2]uint64\n}\n"
  },
  {
    "path": "process/process_freebsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs types_freebsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 14\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 7\n\tKernProcCwd      = 42\n)\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x488\n\tsizeOfKinfoProc    = 0x440\n\tsizeOfKinfoFile    = 0x570\n)\n\nconst (\n\tSIDL   = 1\n\tSRUN   = 2\n\tSSLEEP = 3\n\tSSTOP  = 4\n\tSZOMB  = 5\n\tSWAIT  = 6\n\tSLOCK  = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int64\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int64\n\tIxrss    int64\n\tIdrss    int64\n\tIsrss    int64\n\tMinflt   int64\n\tMajflt   int64\n\tNswap    int64\n\tInblock  int64\n\tOublock  int64\n\tMsgsnd   int64\n\tMsgrcv   int64\n\tNsignals int64\n\tNvcsw    int64\n\tNivcsw   int64\n}\n\ntype Rlimit struct {\n\tCur int64\n\tMax int64\n}\n\ntype KinfoProc struct {\n\tStructsize     int32\n\tLayout         int32\n\tArgs           int64 /* pargs */\n\tPaddr          int64 /* proc */\n\tAddr           int64 /* user */\n\tTracep         int64 /* vnode */\n\tTextvp         int64 /* vnode */\n\tFd             int64 /* filedesc */\n\tVmspace        int64 /* vmspace */\n\tWchan          int64\n\tPid            int32\n\tPpid           int32\n\tPgid           int32\n\tTpgid          int32\n\tSid            int32\n\tTsid           int32\n\tJobc           int16\n\tSpare_short1   int16\n\tTdev_freebsd11 uint32\n\tSiglist        [16]byte /* sigset */\n\tSigmask        [16]byte /* sigset */\n\tSigignore      [16]byte /* sigset */\n\tSigcatch       [16]byte /* sigset */\n\tUid            uint32\n\tRuid           uint32\n\tSvuid          uint32\n\tRgid           uint32\n\tSvgid          uint32\n\tNgroups        int16\n\tSpare_short2   int16\n\tGroups         [16]uint32\n\tSize           uint64\n\tRssize         int64\n\tSwrss          int64\n\tTsize          int64\n\tDsize          int64\n\tSsize          int64\n\tXstat          uint16\n\tAcflag         uint16\n\tPctcpu         uint32\n\tEstcpu         uint32\n\tSlptime        uint32\n\tSwtime         uint32\n\tCow            uint32\n\tRuntime        uint64\n\tStart          Timeval\n\tChildtime      Timeval\n\tFlag           int64\n\tKiflag         int64\n\tTraceflag      int32\n\tStat           uint8\n\tNice           int8\n\tLock           uint8\n\tRqindex        uint8\n\tOncpu_old      uint8\n\tLastcpu_old    uint8\n\tTdname         [17]uint8\n\tWmesg          [9]uint8\n\tLogin          [18]uint8\n\tLockname       [9]uint8\n\tComm           [20]int8 // changed from uint8 by hand\n\tEmul           [17]uint8\n\tLoginclass     [18]uint8\n\tMoretdname     [4]uint8\n\tSparestrings   [46]uint8\n\tSpareints      [2]int32\n\tTdev           uint64\n\tOncpu          int32\n\tLastcpu        int32\n\tTracer         int32\n\tFlag2          int32\n\tFibnum         int32\n\tCr_flags       uint32\n\tJid            int32\n\tNumthreads     int32\n\tTid            int32\n\tPri            Priority\n\tRusage         Rusage\n\tRusage_ch      Rusage\n\tPcb            int64 /* pcb */\n\tKstack         int64\n\tUdata          int64\n\tTdaddr         int64 /* thread */\n\tPd             int64 /* pwddesc, not accurate */\n\tSpareptrs      [5]int64\n\tSparelongs     [12]int64\n\tSflag          int64\n\tTdflags        int64\n}\n\ntype Priority struct {\n\tClass  uint8\n\tLevel  uint8\n\tNative uint8\n\tUser   uint8\n}\n\ntype KinfoVmentry struct {\n\tStructsize        int32\n\tType              int32\n\tStart             uint64\n\tEnd               uint64\n\tOffset            uint64\n\tVn_fileid         uint64\n\tVn_fsid_freebsd11 uint32\n\tFlags             int32\n\tResident          int32\n\tPrivate_resident  int32\n\tProtection        int32\n\tRef_count         int32\n\tShadow_count      int32\n\tVn_type           int32\n\tVn_size           uint64\n\tVn_rdev_freebsd11 uint32\n\tVn_mode           uint16\n\tStatus            uint16\n\tType_spec         [8]byte\n\tVn_rdev           uint64\n\tX_kve_ispare      [8]int32\n\tPath              [1024]uint8\n}\n\ntype kinfoFile struct {\n\tStructsize     int32\n\tType           int32\n\tFd             int32\n\tRef_count      int32\n\tFlags          int32\n\tPad0           int32\n\tOffset         int64\n\tAnon0          [304]byte\n\tStatus         uint16\n\tPad1           uint16\n\tX_kf_ispare0   int32\n\tCap_rights     capRights\n\tX_kf_cap_spare uint64\n\tPath           [1024]int8 // changed from uint8 by hand\n}\n\ntype capRights struct {\n\tRights [2]uint64\n}\n"
  },
  {
    "path": "process/process_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage process\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/tklauser/go-sysconf\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\nvar pageSize = uint64(os.Getpagesize())\n\nconst prioProcess = 0 // linux/resource.h\n\nvar clockTicks = 100 // default value\n\nfunc init() {\n\tclkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)\n\t// ignore errors\n\tif err == nil {\n\t\tclockTicks = int(clkTck)\n\t}\n}\n\n// MemoryInfoExStat is different between OSes\ntype MemoryInfoExStat struct {\n\tRSS    uint64 `json:\"rss\"`    // bytes\n\tVMS    uint64 `json:\"vms\"`    // bytes\n\tShared uint64 `json:\"shared\"` // bytes\n\tText   uint64 `json:\"text\"`   // bytes\n\tLib    uint64 `json:\"lib\"`    // bytes\n\tData   uint64 `json:\"data\"`   // bytes\n\tDirty  uint64 `json:\"dirty\"`  // bytes\n}\n\nfunc (m MemoryInfoExStat) String() string {\n\ts, _ := json.Marshal(m)\n\treturn string(s)\n}\n\ntype MemoryMapsStat struct {\n\tPath         string `json:\"path\"`\n\tRss          uint64 `json:\"rss\"`\n\tSize         uint64 `json:\"size\"`\n\tPss          uint64 `json:\"pss\"`\n\tSharedClean  uint64 `json:\"sharedClean\"`\n\tSharedDirty  uint64 `json:\"sharedDirty\"`\n\tPrivateClean uint64 `json:\"privateClean\"`\n\tPrivateDirty uint64 `json:\"privateDirty\"`\n\tReferenced   uint64 `json:\"referenced\"`\n\tAnonymous    uint64 `json:\"anonymous\"`\n\tSwap         uint64 `json:\"swap\"`\n}\n\n// String returns JSON value of the process.\nfunc (m MemoryMapsStat) String() string {\n\ts, _ := json.Marshal(m)\n\treturn string(s)\n}\n\nfunc (p *Process) PpidWithContext(ctx context.Context) (int32, error) {\n\t_, ppid, _, _, _, _, _, err := p.fillFromStatWithContext(ctx)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\treturn ppid, nil\n}\n\nfunc (p *Process) NameWithContext(ctx context.Context) (string, error) {\n\tif p.name == \"\" {\n\t\tif err := p.fillNameWithContext(ctx); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\treturn p.name, nil\n}\n\nfunc (p *Process) TgidWithContext(ctx context.Context) (int32, error) {\n\tif p.tgid == 0 {\n\t\tif err := p.fillFromStatusWithContext(ctx); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\treturn p.tgid, nil\n}\n\nfunc (p *Process) ExeWithContext(ctx context.Context) (string, error) {\n\treturn p.fillFromExeWithContext(ctx)\n}\n\nfunc (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {\n\treturn p.fillFromCmdlineWithContext(ctx)\n}\n\nfunc (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {\n\treturn p.fillSliceFromCmdlineWithContext(ctx)\n}\n\nfunc (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {\n\t_, _, _, createTime, _, _, _, err := p.fillFromStatWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn createTime, nil\n}\n\nfunc (p *Process) CwdWithContext(ctx context.Context) (string, error) {\n\treturn p.fillFromCwdWithContext(ctx)\n}\n\nfunc (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {\n\terr := p.fillFromStatusWithContext(ctx)\n\tif err != nil {\n\t\treturn []string{\"\"}, err\n\t}\n\treturn []string{p.status}, nil\n}\n\nfunc (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {\n\t// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details\n\tpid := p.Pid\n\tstatPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"stat\")\n\tcontents, err := os.ReadFile(statPath)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tfields := strings.Fields(string(contents))\n\tif len(fields) < 8 {\n\t\treturn false, fmt.Errorf(\"insufficient data in %s\", statPath)\n\t}\n\tpgid := fields[4]\n\ttpgid := fields[7]\n\treturn pgid == tpgid, nil\n}\n\nfunc (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {\n\terr := p.fillFromStatusWithContext(ctx)\n\tif err != nil {\n\t\treturn []uint32{}, err\n\t}\n\treturn p.uids, nil\n}\n\nfunc (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {\n\terr := p.fillFromStatusWithContext(ctx)\n\tif err != nil {\n\t\treturn []uint32{}, err\n\t}\n\treturn p.gids, nil\n}\n\nfunc (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {\n\terr := p.fillFromStatusWithContext(ctx)\n\tif err != nil {\n\t\treturn []uint32{}, err\n\t}\n\treturn p.groups, nil\n}\n\nfunc (p *Process) TerminalWithContext(ctx context.Context) (string, error) {\n\tt, _, _, _, _, _, _, err := p.fillFromStatWithContext(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\ttermmap, err := getTerminalMap()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tterminal := termmap[t]\n\treturn terminal, nil\n}\n\nfunc (p *Process) NiceWithContext(ctx context.Context) (int32, error) {\n\t_, _, _, _, _, nice, _, err := p.fillFromStatWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn nice, nil\n}\n\nfunc (*Process) IOniceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {\n\treturn p.RlimitUsageWithContext(ctx, false)\n}\n\nfunc (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {\n\trlimits, err := p.fillFromLimitsWithContext(ctx)\n\tif !gatherUsed || err != nil {\n\t\treturn rlimits, err\n\t}\n\n\t_, _, _, _, rtprio, nice, _, err := p.fillFromStatWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := p.fillFromStatusWithContext(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor i := range rlimits {\n\t\trs := &rlimits[i]\n\t\tswitch rs.Resource {\n\t\tcase RLIMIT_CPU:\n\t\t\ttimes, err := p.TimesWithContext(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\trs.Used = uint64(times.User + times.System)\n\t\tcase RLIMIT_DATA:\n\t\t\trs.Used = uint64(p.memInfo.Data)\n\t\tcase RLIMIT_STACK:\n\t\t\trs.Used = uint64(p.memInfo.Stack)\n\t\tcase RLIMIT_RSS:\n\t\t\trs.Used = uint64(p.memInfo.RSS)\n\t\tcase RLIMIT_NOFILE:\n\t\t\tn, err := p.NumFDsWithContext(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\trs.Used = uint64(n)\n\t\tcase RLIMIT_MEMLOCK:\n\t\t\trs.Used = uint64(p.memInfo.Locked)\n\t\tcase RLIMIT_AS:\n\t\t\trs.Used = uint64(p.memInfo.VMS)\n\t\tcase RLIMIT_LOCKS:\n\t\t\t// TODO we can get the used value from /proc/$pid/locks. But linux doesn't enforce it, so not a high priority.\n\t\tcase RLIMIT_SIGPENDING:\n\t\t\trs.Used = p.sigInfo.PendingProcess\n\t\tcase RLIMIT_NICE:\n\t\t\t// 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.\n\t\t\t// So effectively: if rs.Soft == 0 { rs.Soft = rs.Used }\n\t\t\trs.Used = uint64(nice)\n\t\tcase RLIMIT_RTPRIO:\n\t\t\trs.Used = uint64(rtprio)\n\t\t}\n\t}\n\n\treturn rlimits, err\n}\n\nfunc (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {\n\treturn p.fillFromIOWithContext(ctx)\n}\n\nfunc (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {\n\terr := p.fillFromStatusWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn p.numCtxSwitches, nil\n}\n\nfunc (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {\n\t_, fnames, err := p.fillFromfdListWithContext(ctx)\n\treturn int32(len(fnames)), err\n}\n\nfunc (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {\n\terr := p.fillFromStatusWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn p.numThreads, nil\n}\n\nfunc (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {\n\tret := make(map[int32]*cpu.TimesStat)\n\ttaskPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), \"task\")\n\n\ttids, err := readPidsFromDir(taskPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, tid := range tids {\n\t\t_, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStatWithContext(ctx, tid)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tret[tid] = cpuTimes\n\t}\n\n\treturn ret, nil\n}\n\nfunc (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {\n\t_, _, cpuTimes, _, _, _, _, err := p.fillFromStatWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn cpuTimes, nil\n}\n\nfunc (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {\n\tmeminfo, _, err := p.fillFromStatmWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn meminfo, nil\n}\n\nfunc (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {\n\t_, memInfoEx, err := p.fillFromStatmWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn memInfoEx, nil\n}\n\nfunc (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {\n\t_, _, _, _, _, _, pageFaults, err := p.fillFromStatWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn pageFaults, nil\n}\n\nfunc (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {\n\tstatFiles, err := filepath.Glob(common.HostProcWithContext(ctx, \"[0-9]*/stat\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := make([]*Process, 0, len(statFiles))\n\tfor _, statFile := range statFiles {\n\t\tstatContents, err := os.ReadFile(statFile)\n\t\tif err != nil || len(statContents) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tfields := splitProcStat(statContents)\n\t\tpid, err := strconv.ParseInt(fields[1], 10, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tppid, err := strconv.ParseInt(fields[4], 10, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif ppid == int64(p.Pid) {\n\t\t\tnp, err := NewProcessWithContext(ctx, int32(pid))\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tret = append(ret, np)\n\t\t}\n\t}\n\tsort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })\n\treturn ret, nil\n}\n\nfunc (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {\n\t_, ofs, err := p.fillFromfdWithContext(ctx)\n\treturn ofs, err\n}\n\nfunc (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {\n\treturn net.ConnectionsPidWithContext(ctx, \"all\", p.Pid)\n}\n\nfunc (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {\n\treturn net.ConnectionsPidMaxWithContext(ctx, \"all\", p.Pid, maxConn)\n}\n\nfunc (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {\n\tpid := p.Pid\n\tvar ret []MemoryMapsStat\n\tsmapsPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"smaps\")\n\tif grouped {\n\t\tret = make([]MemoryMapsStat, 1)\n\t\t// If smaps_rollup exists (require kernel >= 4.15), then we will use it\n\t\t// for pre-summed memory information for a process.\n\t\tsmapsRollupPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"smaps_rollup\")\n\t\tif _, err := os.Stat(smapsRollupPath); !os.IsNotExist(err) {\n\t\t\tsmapsPath = smapsRollupPath\n\t\t}\n\t}\n\tcontents, err := os.ReadFile(smapsPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlines := strings.Split(string(contents), \"\\n\")\n\n\t// function of parsing a block\n\tgetBlock := func(firstLine []string, block []string) (MemoryMapsStat, error) {\n\t\tm := MemoryMapsStat{}\n\t\tif len(firstLine) >= 6 {\n\t\t\tm.Path = strings.Join(firstLine[5:], \" \")\n\t\t}\n\n\t\tfor _, line := range block {\n\t\t\tif strings.Contains(line, \"VmFlags\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfield := strings.Split(line, \":\")\n\t\t\tif len(field) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tv := strings.Trim(field[1], \"kB\") // remove last \"kB\"\n\t\t\tv = strings.TrimSpace(v)\n\t\t\tt, err := strconv.ParseUint(v, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn m, err\n\t\t\t}\n\n\t\t\tswitch field[0] {\n\t\t\tcase \"Size\":\n\t\t\t\tm.Size = t\n\t\t\tcase \"Rss\":\n\t\t\t\tm.Rss = t\n\t\t\tcase \"Pss\":\n\t\t\t\tm.Pss = t\n\t\t\tcase \"Shared_Clean\":\n\t\t\t\tm.SharedClean = t\n\t\t\tcase \"Shared_Dirty\":\n\t\t\t\tm.SharedDirty = t\n\t\t\tcase \"Private_Clean\":\n\t\t\t\tm.PrivateClean = t\n\t\t\tcase \"Private_Dirty\":\n\t\t\t\tm.PrivateDirty = t\n\t\t\tcase \"Referenced\":\n\t\t\t\tm.Referenced = t\n\t\t\tcase \"Anonymous\":\n\t\t\t\tm.Anonymous = t\n\t\t\tcase \"Swap\":\n\t\t\t\tm.Swap = t\n\t\t\t}\n\t\t}\n\t\treturn m, nil\n\t}\n\n\tvar firstLine []string\n\tblocks := make([]string, 0, 16)\n\n\tfor i, line := range lines {\n\t\tfields := strings.Fields(line)\n\t\tif (len(fields) > 0 && !strings.HasSuffix(fields[0], \":\")) || i == len(lines)-1 {\n\t\t\t// new block section\n\t\t\tif len(firstLine) > 0 && len(blocks) > 0 {\n\t\t\t\tg, err := getBlock(firstLine, blocks)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn &ret, err\n\t\t\t\t}\n\t\t\t\tif grouped {\n\t\t\t\t\tret[0].Size += g.Size\n\t\t\t\t\tret[0].Rss += g.Rss\n\t\t\t\t\tret[0].Pss += g.Pss\n\t\t\t\t\tret[0].SharedClean += g.SharedClean\n\t\t\t\t\tret[0].SharedDirty += g.SharedDirty\n\t\t\t\t\tret[0].PrivateClean += g.PrivateClean\n\t\t\t\t\tret[0].PrivateDirty += g.PrivateDirty\n\t\t\t\t\tret[0].Referenced += g.Referenced\n\t\t\t\t\tret[0].Anonymous += g.Anonymous\n\t\t\t\t\tret[0].Swap += g.Swap\n\t\t\t\t} else {\n\t\t\t\t\tret = append(ret, g)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// starts new block\n\t\t\tblocks = make([]string, 0, 16)\n\t\t\tfirstLine = fields\n\t\t} else {\n\t\t\tblocks = append(blocks, line)\n\t\t}\n\t}\n\n\treturn &ret, nil\n}\n\nfunc (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {\n\tenvironPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), \"environ\")\n\n\tenvironContent, err := os.ReadFile(environPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn strings.Split(string(environContent), \"\\000\"), nil\n}\n\n/**\n** Internal functions\n**/\n\nfunc limitToUint(val string) (uint64, error) {\n\tif val == \"unlimited\" {\n\t\treturn math.MaxUint64, nil\n\t}\n\tres, err := strconv.ParseUint(val, 10, 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn res, nil\n}\n\n// Get num_fds from /proc/(pid)/limits\nfunc (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, error) {\n\tpid := p.Pid\n\tlimitsFile := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"limits\")\n\td, err := os.Open(limitsFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer d.Close()\n\n\tvar limitStats []RlimitStat\n\n\tlimitsScanner := bufio.NewScanner(d)\n\tfor limitsScanner.Scan() {\n\t\tvar statItem RlimitStat\n\n\t\tstr := strings.Fields(limitsScanner.Text())\n\n\t\t// Remove the header line\n\t\tif strings.Contains(str[len(str)-1], \"Units\") {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Assert that last item is a Hard limit\n\t\tstatItem.Hard, err = limitToUint(str[len(str)-1])\n\t\tif err != nil {\n\t\t\t// On error remove last item and try once again since it can be unit or header line\n\t\t\tstr = str[:len(str)-1]\n\t\t\tstatItem.Hard, err = limitToUint(str[len(str)-1])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\t// Remove last item from string\n\t\tstr = str[:len(str)-1]\n\n\t\t// Now last item is a Soft limit\n\t\tstatItem.Soft, err = limitToUint(str[len(str)-1])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Remove last item from string\n\t\tstr = str[:len(str)-1]\n\n\t\t// The rest is a stats name\n\t\tresourceName := strings.Join(str, \" \")\n\t\tswitch resourceName {\n\t\tcase \"Max cpu time\":\n\t\t\tstatItem.Resource = RLIMIT_CPU\n\t\tcase \"Max file size\":\n\t\t\tstatItem.Resource = RLIMIT_FSIZE\n\t\tcase \"Max data size\":\n\t\t\tstatItem.Resource = RLIMIT_DATA\n\t\tcase \"Max stack size\":\n\t\t\tstatItem.Resource = RLIMIT_STACK\n\t\tcase \"Max core file size\":\n\t\t\tstatItem.Resource = RLIMIT_CORE\n\t\tcase \"Max resident set\":\n\t\t\tstatItem.Resource = RLIMIT_RSS\n\t\tcase \"Max processes\":\n\t\t\tstatItem.Resource = RLIMIT_NPROC\n\t\tcase \"Max open files\":\n\t\t\tstatItem.Resource = RLIMIT_NOFILE\n\t\tcase \"Max locked memory\":\n\t\t\tstatItem.Resource = RLIMIT_MEMLOCK\n\t\tcase \"Max address space\":\n\t\t\tstatItem.Resource = RLIMIT_AS\n\t\tcase \"Max file locks\":\n\t\t\tstatItem.Resource = RLIMIT_LOCKS\n\t\tcase \"Max pending signals\":\n\t\t\tstatItem.Resource = RLIMIT_SIGPENDING\n\t\tcase \"Max msgqueue size\":\n\t\t\tstatItem.Resource = RLIMIT_MSGQUEUE\n\t\tcase \"Max nice priority\":\n\t\t\tstatItem.Resource = RLIMIT_NICE\n\t\tcase \"Max realtime priority\":\n\t\t\tstatItem.Resource = RLIMIT_RTPRIO\n\t\tcase \"Max realtime timeout\":\n\t\t\tstatItem.Resource = RLIMIT_RTTIME\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\tlimitStats = append(limitStats, statItem)\n\t}\n\n\tif err := limitsScanner.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn limitStats, nil\n}\n\n// Get list of /proc/(pid)/fd files\nfunc (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) {\n\tpid := p.Pid\n\tstatPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"fd\")\n\td, err := os.Open(statPath)\n\tif err != nil {\n\t\treturn statPath, []string{}, err\n\t}\n\tdefer d.Close()\n\tfnames, err := d.Readdirnames(-1)\n\treturn statPath, fnames, err\n}\n\n// Get num_fds from /proc/(pid)/fd\nfunc (p *Process) fillFromfdWithContext(ctx context.Context) (int32, []OpenFilesStat, error) {\n\tstatPath, fnames, err := p.fillFromfdListWithContext(ctx)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\tnumFDs := int32(len(fnames))\n\n\topenfiles := make([]OpenFilesStat, 0, numFDs)\n\tfor _, fd := range fnames {\n\t\tfpath := filepath.Join(statPath, fd)\n\t\tpath, err := common.Readlink(fpath)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tt, err := strconv.ParseUint(fd, 10, 64)\n\t\tif err != nil {\n\t\t\treturn numFDs, openfiles, err\n\t\t}\n\t\to := OpenFilesStat{\n\t\t\tPath: path,\n\t\t\tFd:   t,\n\t\t}\n\t\topenfiles = append(openfiles, o)\n\t}\n\n\treturn numFDs, openfiles, nil\n}\n\n// Get cwd from /proc/(pid)/cwd\nfunc (p *Process) fillFromCwdWithContext(ctx context.Context) (string, error) {\n\tpid := p.Pid\n\tcwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"cwd\")\n\tcwd, err := os.Readlink(cwdPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(cwd), nil\n}\n\n// Get exe from /proc/(pid)/exe\nfunc (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) {\n\tpid := p.Pid\n\texePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"exe\")\n\texe, err := os.Readlink(exePath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(exe), nil\n}\n\n// Get cmdline from /proc/(pid)/cmdline\nfunc (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {\n\tpid := p.Pid\n\tcmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"cmdline\")\n\tcmdline, err := os.ReadFile(cmdPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tret := strings.FieldsFunc(string(cmdline), func(r rune) bool {\n\t\treturn r == '\\u0000'\n\t})\n\n\treturn strings.Join(ret, \" \"), nil\n}\n\nfunc (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {\n\tpid := p.Pid\n\tcmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"cmdline\")\n\tcmdline, err := os.ReadFile(cmdPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(cmdline) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tcmdline = bytes.TrimRight(cmdline, \"\\x00\")\n\n\tparts := bytes.Split(cmdline, []byte{0})\n\tvar strParts []string\n\tfor _, p := range parts {\n\t\tstrParts = append(strParts, string(p))\n\t}\n\n\treturn strParts, nil\n}\n\n// Get IO status from /proc/(pid)/io\nfunc (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) {\n\tpid := p.Pid\n\tioPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"io\")\n\tioline, err := os.ReadFile(ioPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlines := strings.Split(string(ioline), \"\\n\")\n\tret := &IOCountersStat{}\n\n\tfor _, line := range lines {\n\t\tfield := strings.Fields(line)\n\t\tif len(field) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tt, err := strconv.ParseUint(field[1], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tparam := strings.TrimSuffix(field[0], \":\")\n\t\tswitch param {\n\t\tcase \"syscr\":\n\t\t\tret.ReadCount = t\n\t\tcase \"syscw\":\n\t\t\tret.WriteCount = t\n\t\tcase \"read_bytes\":\n\t\t\tret.DiskReadBytes = t\n\t\tcase \"write_bytes\":\n\t\t\tret.DiskWriteBytes = t\n\t\tcase \"rchar\":\n\t\t\tret.ReadBytes = t\n\t\tcase \"wchar\":\n\t\t\tret.WriteBytes = t\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n\n// Get memory info from /proc/(pid)/statm\nfunc (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) {\n\tpid := p.Pid\n\tmemPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"statm\")\n\tcontents, err := os.ReadFile(memPath)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tfields := strings.Split(string(contents), \" \")\n\n\tvms, err := strconv.ParseUint(fields[0], 10, 64)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\trss, err := strconv.ParseUint(fields[1], 10, 64)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tmemInfo := &MemoryInfoStat{\n\t\tRSS: rss * pageSize,\n\t\tVMS: vms * pageSize,\n\t}\n\n\tshared, err := strconv.ParseUint(fields[2], 10, 64)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\ttext, err := strconv.ParseUint(fields[3], 10, 64)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tlib, err := strconv.ParseUint(fields[4], 10, 64)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tdirty, err := strconv.ParseUint(fields[5], 10, 64)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tmemInfoEx := &MemoryInfoExStat{\n\t\tRSS:    rss * pageSize,\n\t\tVMS:    vms * pageSize,\n\t\tShared: shared * pageSize,\n\t\tText:   text * pageSize,\n\t\tLib:    lib * pageSize,\n\t\tDirty:  dirty * pageSize,\n\t}\n\n\treturn memInfo, memInfoEx, nil\n}\n\n// Get name from /proc/(pid)/comm or /proc/(pid)/status\nfunc (p *Process) fillNameWithContext(ctx context.Context) error {\n\terr := p.fillFromCommWithContext(ctx)\n\tif err == nil && p.name != \"\" && len(p.name) < 15 {\n\t\treturn nil\n\t}\n\treturn p.fillFromStatusWithContext(ctx)\n}\n\n// Get name from /proc/(pid)/comm\nfunc (p *Process) fillFromCommWithContext(ctx context.Context) error {\n\tpid := p.Pid\n\tstatPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"comm\")\n\tcontents, err := os.ReadFile(statPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tp.name = strings.TrimSuffix(string(contents), \"\\n\")\n\treturn nil\n}\n\n// Get various status from /proc/(pid)/status\nfunc (p *Process) fillFromStatus() error {\n\treturn p.fillFromStatusWithContext(context.Background())\n}\n\nfunc (p *Process) fillFromStatusWithContext(ctx context.Context) error {\n\tpid := p.Pid\n\tstatPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"status\")\n\tcontents, err := os.ReadFile(statPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlines := strings.Split(string(contents), \"\\n\")\n\tp.numCtxSwitches = &NumCtxSwitchesStat{}\n\tp.memInfo = &MemoryInfoStat{}\n\tp.sigInfo = &SignalInfoStat{}\n\tfor _, line := range lines {\n\t\ttabParts := strings.SplitN(line, \"\\t\", 2)\n\t\tif len(tabParts) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tvalue := tabParts[1]\n\t\tswitch strings.TrimRight(tabParts[0], \":\") {\n\t\tcase \"Name\":\n\t\t\tp.name = strings.Trim(value, \" \\t\")\n\t\t\tif len(p.name) >= 15 {\n\t\t\t\tcmdlineSlice, err := p.CmdlineSliceWithContext(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif len(cmdlineSlice) > 0 {\n\t\t\t\t\textendedName := filepath.Base(cmdlineSlice[0])\n\t\t\t\t\tif strings.HasPrefix(extendedName, p.name) {\n\t\t\t\t\t\tp.name = extendedName\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Ensure we have a copy and not reference into slice\n\t\t\tp.name = string([]byte(p.name))\n\t\tcase \"State\":\n\t\t\tp.status = convertStatusChar(value[0:1])\n\t\t\t// Ensure we have a copy and not reference into slice\n\t\t\tp.status = string([]byte(p.status))\n\t\tcase \"PPid\", \"Ppid\":\n\t\t\tpval, err := strconv.ParseInt(value, 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.parent = int32(pval)\n\t\tcase \"Tgid\":\n\t\t\tpval, err := strconv.ParseInt(value, 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.tgid = int32(pval)\n\t\tcase \"Uid\":\n\t\t\tp.uids = make([]uint32, 0, 4)\n\t\t\tfor _, i := range strings.Split(value, \"\\t\") {\n\t\t\t\tv, err := strconv.ParseUint(i, 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tp.uids = append(p.uids, uint32(v))\n\t\t\t}\n\t\tcase \"Gid\":\n\t\t\tp.gids = make([]uint32, 0, 4)\n\t\t\tfor _, i := range strings.Split(value, \"\\t\") {\n\t\t\t\tv, err := strconv.ParseUint(i, 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tp.gids = append(p.gids, uint32(v))\n\t\t\t}\n\t\tcase \"Groups\":\n\t\t\tgroups := strings.Fields(value)\n\t\t\tp.groups = make([]uint32, 0, len(groups))\n\t\t\tfor _, i := range groups {\n\t\t\t\tv, err := strconv.ParseUint(i, 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tp.groups = append(p.groups, uint32(v))\n\t\t\t}\n\t\tcase \"Threads\":\n\t\t\tv, err := strconv.ParseInt(value, 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.numThreads = int32(v)\n\t\tcase \"voluntary_ctxt_switches\":\n\t\t\tv, err := strconv.ParseInt(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.numCtxSwitches.Voluntary = v\n\t\tcase \"nonvoluntary_ctxt_switches\":\n\t\t\tv, err := strconv.ParseInt(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.numCtxSwitches.Involuntary = v\n\t\tcase \"VmRSS\":\n\t\t\tvalue = strings.Trim(value, \" kB\") // remove last \"kB\"\n\t\t\tv, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.memInfo.RSS = v * 1024\n\t\tcase \"VmSize\":\n\t\t\tvalue = strings.Trim(value, \" kB\") // remove last \"kB\"\n\t\t\tv, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.memInfo.VMS = v * 1024\n\t\tcase \"VmSwap\":\n\t\t\tvalue = strings.Trim(value, \" kB\") // remove last \"kB\"\n\t\t\tv, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.memInfo.Swap = v * 1024\n\t\tcase \"VmHWM\":\n\t\t\tvalue = strings.Trim(value, \" kB\") // remove last \"kB\"\n\t\t\tv, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.memInfo.HWM = v * 1024\n\t\tcase \"VmData\":\n\t\t\tvalue = strings.Trim(value, \" kB\") // remove last \"kB\"\n\t\t\tv, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.memInfo.Data = v * 1024\n\t\tcase \"VmStk\":\n\t\t\tvalue = strings.Trim(value, \" kB\") // remove last \"kB\"\n\t\t\tv, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.memInfo.Stack = v * 1024\n\t\tcase \"VmLck\":\n\t\t\tvalue = strings.Trim(value, \" kB\") // remove last \"kB\"\n\t\t\tv, err := strconv.ParseUint(value, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.memInfo.Locked = v * 1024\n\t\tcase \"SigPnd\":\n\t\t\tif len(value) > 16 {\n\t\t\t\tvalue = value[len(value)-16:]\n\t\t\t}\n\t\t\tv, err := strconv.ParseUint(value, 16, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.sigInfo.PendingThread = v\n\t\tcase \"ShdPnd\":\n\t\t\tif len(value) > 16 {\n\t\t\t\tvalue = value[len(value)-16:]\n\t\t\t}\n\t\t\tv, err := strconv.ParseUint(value, 16, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.sigInfo.PendingProcess = v\n\t\tcase \"SigBlk\":\n\t\t\tif len(value) > 16 {\n\t\t\t\tvalue = value[len(value)-16:]\n\t\t\t}\n\t\t\tv, err := strconv.ParseUint(value, 16, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.sigInfo.Blocked = v\n\t\tcase \"SigIgn\":\n\t\t\tif len(value) > 16 {\n\t\t\t\tvalue = value[len(value)-16:]\n\t\t\t}\n\t\t\tv, err := strconv.ParseUint(value, 16, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.sigInfo.Ignored = v\n\t\tcase \"SigCgt\":\n\t\t\tif len(value) > 16 {\n\t\t\t\tvalue = value[len(value)-16:]\n\t\t\t}\n\t\t\tv, err := strconv.ParseUint(value, 16, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tp.sigInfo.Caught = v\n\t\t}\n\n\t}\n\treturn nil\n}\n\nfunc (p *Process) fillFromTIDStat(tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {\n\treturn p.fillFromTIDStatWithContext(context.Background(), tid)\n}\n\nfunc (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {\n\tpid := p.Pid\n\tvar statPath string\n\n\tif tid == -1 {\n\t\tstatPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"stat\")\n\t} else {\n\t\tstatPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"task\", strconv.Itoa(int(tid)), \"stat\")\n\t}\n\n\tcontents, err := os.ReadFile(statPath)\n\tif err == nil && len(contents) == 0 {\n\t\terr = fmt.Errorf(\"process %d: stat file is empty, process may have terminated\", pid)\n\t}\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\t// Indexing from one, as described in `man proc` about the file /proc/[pid]/stat\n\tfields := splitProcStat(contents)\n\n\tterminal, err := strconv.ParseUint(fields[7], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\n\tppid, err := strconv.ParseInt(fields[4], 10, 32)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\tutime, err := strconv.ParseFloat(fields[14], 64)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\n\tstime, err := strconv.ParseFloat(fields[15], 64)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\n\t// There is no such thing as iotime in stat file.  As an approximation, we\n\t// will use delayacct_blkio_ticks (aggregated block I/O delays, as per Linux\n\t// docs).  Note: I am assuming at least Linux 2.6.18\n\tvar iotime float64\n\tif len(fields) > 42 {\n\t\tiotime, err = strconv.ParseFloat(fields[42], 64)\n\t\tif err != nil {\n\t\t\tiotime = 0 // Ancient linux version, most likely\n\t\t}\n\t} else {\n\t\tiotime = 0 // e.g. SmartOS containers\n\t}\n\n\tcpuTimes := &cpu.TimesStat{\n\t\tCPU:    \"cpu\",\n\t\tUser:   utime / float64(clockTicks),\n\t\tSystem: stime / float64(clockTicks),\n\t\tIowait: iotime / float64(clockTicks),\n\t}\n\n\tbootTime, _ := common.BootTimeWithContext(ctx, enableBootTimeCache)\n\tt, err := strconv.ParseUint(fields[22], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\tcreateTime := int64((t * 1000 / uint64(clockTicks)) + uint64(bootTime*1000))\n\n\trtpriority, err := strconv.ParseInt(fields[18], 10, 32)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\tif rtpriority < 0 {\n\t\trtpriority = rtpriority*-1 - 1\n\t} else {\n\t\trtpriority = 0\n\t}\n\n\t//\tp.Nice = mustParseInt32(fields[18])\n\t// use syscall instead of parse Stat file\n\tsnice, _ := unix.Getpriority(prioProcess, int(pid))\n\tnice := int32(snice) // FIXME: is this true?\n\n\tminFault, err := strconv.ParseUint(fields[10], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\tcMinFault, err := strconv.ParseUint(fields[11], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\tmajFault, err := strconv.ParseUint(fields[12], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\tcMajFault, err := strconv.ParseUint(fields[13], 10, 64)\n\tif err != nil {\n\t\treturn 0, 0, nil, 0, 0, 0, nil, err\n\t}\n\n\tfaults := &PageFaultsStat{\n\t\tMinorFaults:      minFault,\n\t\tMajorFaults:      majFault,\n\t\tChildMinorFaults: cMinFault,\n\t\tChildMajorFaults: cMajFault,\n\t}\n\n\treturn terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, faults, nil\n}\n\nfunc (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {\n\treturn p.fillFromTIDStatWithContext(ctx, -1)\n}\n\nfunc pidsWithContext(ctx context.Context) ([]int32, error) {\n\treturn readPidsFromDir(common.HostProcWithContext(ctx))\n}\n\nfunc ProcessesWithContext(ctx context.Context) ([]*Process, error) {\n\tout := []*Process{}\n\n\tpids, err := PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn out, err\n\t}\n\n\tfor _, pid := range pids {\n\t\tp, err := NewProcessWithContext(ctx, pid)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tout = append(out, p)\n\t}\n\n\treturn out, nil\n}\n\nfunc readPidsFromDir(path string) ([]int32, error) {\n\tvar ret []int32\n\n\td, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer d.Close()\n\n\tfnames, err := d.Readdirnames(-1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, fname := range fnames {\n\t\tif !strictIntPtrn.MatchString(fname) {\n\t\t\tcontinue\n\t\t}\n\t\tpid, err := strconv.ParseInt(fname, 10, 32)\n\t\tif err != nil {\n\t\t\t// if not numeric name, just skip\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, int32(pid))\n\t}\n\n\treturn ret, nil\n}\n\nfunc splitProcStat(content []byte) []string {\n\tnameStart := bytes.IndexByte(content, '(')\n\tnameEnd := bytes.LastIndexByte(content, ')')\n\trestFields := strings.Fields(string(content[nameEnd+2:])) // +2 skip ') '\n\tname := content[nameStart+1 : nameEnd]\n\tpid := strings.TrimSpace(string(content[:nameStart]))\n\tfields := make([]string, 3, len(restFields)+3)\n\tfields[1] = string(pid)\n\tfields[2] = string(name)\n\tfields = append(fields, restFields...)\n\treturn fields\n}\n"
  },
  {
    "path": "process/process_linux_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage process\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFillFromfdWithContext(t *testing.T) {\n\ttype expect struct {\n\t\tnumFDs    int32\n\t\topenFiles []OpenFilesStat\n\t\terr       error\n\t}\n\ttype testCase struct {\n\t\tname     string\n\t\tpid      int32\n\t\texpected *expect\n\t}\n\n\tcases := []testCase{\n\t\t{\n\t\t\tname: \"good path\",\n\t\t\tpid:  1,\n\t\t\texpected: &expect{\n\t\t\t\tnumFDs: 3,\n\t\t\t\topenFiles: []OpenFilesStat{\n\t\t\t\t\t{\n\t\t\t\t\t\tPath: \"/foo\",\n\t\t\t\t\t\tFd:   0,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tPath: \"/bar\",\n\t\t\t\t\t\tFd:   1,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tPath: \"/baz\",\n\t\t\t\t\t\tFd:   2,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux\")\n\tfor _, tt := range cases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tp, err := NewProcess(tt.pid)\n\t\t\trequire.NoError(t, err)\n\t\t\tnumFDs, openFiles, err := p.fillFromfdWithContext(context.TODO())\n\t\t\tif tt.expected.err != nil {\n\t\t\t\tassert.ErrorContains(t, err, tt.expected.err.Error())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t//nolint:testifylint // false positive\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, tt.expected.numFDs, numFDs)\n\t\t\tassert.ElementsMatch(t, tt.expected.openFiles, openFiles)\n\t\t})\n\t}\n}\n\nfunc TestSplitProcStat(t *testing.T) {\n\texpectedFieldsNum := 53\n\tstatLineContent := make([]string, expectedFieldsNum-1)\n\tfor i := 0; i < expectedFieldsNum-1; i++ {\n\t\tstatLineContent[i] = strconv.Itoa(i + 1)\n\t}\n\n\tcases := []string{\n\t\t\"ok\",\n\t\t\"ok)\",\n\t\t\"(ok\",\n\t\t\"ok )\",\n\t\t\"ok )(\",\n\t\t\"ok )()\",\n\t\t\"() ok )()\",\n\t\t\"() ok (()\",\n\t\t\" ) ok )\",\n\t\t\"(ok) (ok)\",\n\t}\n\n\tconsideredFields := []int{4, 7, 10, 11, 12, 13, 14, 15, 18, 22, 42}\n\n\tcommandNameIndex := 2\n\tfor _, expectedName := range cases {\n\t\tstatLineContent[commandNameIndex-1] = \"(\" + expectedName + \")\"\n\t\tstatLine := strings.Join(statLineContent, \" \")\n\t\tt.Run(\"name: \"+expectedName, func(t *testing.T) {\n\t\t\tparsedStatLine := splitProcStat([]byte(statLine))\n\t\t\tassert.Equal(t, expectedName, parsedStatLine[commandNameIndex])\n\t\t\tfor _, idx := range consideredFields {\n\t\t\t\texpected := strconv.Itoa(idx)\n\t\t\t\tparsed := parsedStatLine[idx]\n\t\t\t\tassert.Equalf(\n\t\t\t\t\tt, expected, parsed,\n\t\t\t\t\t\"field %d (index from 1 as in man proc) must be %q but %q is received\",\n\t\t\t\t\tidx, expected, parsed,\n\t\t\t\t)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestSplitProcStat_fromFile(t *testing.T) {\n\tpids, err := os.ReadDir(\"testdata/linux/\")\n\trequire.NoError(t, err)\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux\")\n\tfor _, pid := range pids {\n\t\tpid, err := strconv.ParseInt(pid.Name(), 0, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tstatFile := fmt.Sprintf(\"testdata/linux/%d/stat\", pid)\n\t\tif _, err := os.Stat(statFile); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tcontents, err := os.ReadFile(statFile)\n\t\trequire.NoError(t, err)\n\n\t\tpidStr := strconv.Itoa(int(pid))\n\n\t\tppid := \"68044\" // TODO: how to pass ppid to test?\n\n\t\tfields := splitProcStat(contents)\n\t\tassert.Equal(t, pidStr, fields[1])\n\t\tassert.Equal(t, \"test(cmd).sh\", fields[2])\n\t\tassert.Equal(t, \"S\", fields[3])\n\t\tassert.Equal(t, ppid, fields[4])\n\t\tassert.Equal(t, pidStr, fields[5]) // pgrp\n\t\tassert.Equal(t, ppid, fields[6])   // session\n\t\tassert.Equal(t, pidStr, fields[8]) // tpgrp\n\t\tassert.Equal(t, \"20\", fields[18])  // priority\n\t\tassert.Equal(t, \"1\", fields[20])   // num threads\n\t\tassert.Equal(t, \"0\", fields[52])   // exit code\n\t}\n}\n\nfunc TestFillFromCommWithContext(t *testing.T) {\n\tpids, err := os.ReadDir(\"testdata/linux/\")\n\trequire.NoError(t, err)\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux\")\n\tfor _, pid := range pids {\n\t\tpid, err := strconv.ParseInt(pid.Name(), 0, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif _, err := os.Stat(fmt.Sprintf(\"testdata/linux/%d/status\", pid)); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tp, _ := NewProcess(int32(pid))\n\t\tassert.NoError(t, p.fillFromCommWithContext(context.Background()))\n\t}\n}\n\nfunc TestFillFromStatusWithContext(t *testing.T) {\n\tpids, err := os.ReadDir(\"testdata/linux/\")\n\trequire.NoError(t, err)\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux\")\n\tfor _, pid := range pids {\n\t\tpid, err := strconv.ParseInt(pid.Name(), 0, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif _, err := os.Stat(fmt.Sprintf(\"testdata/linux/%d/status\", pid)); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tp, _ := NewProcess(int32(pid))\n\t\tassert.NoError(t, p.fillFromStatus())\n\t}\n}\n\nfunc Benchmark_fillFromCommWithContext(b *testing.B) {\n\tb.Setenv(\"HOST_PROC\", \"testdata/linux\")\n\tpid := 1060\n\tp, _ := NewProcess(int32(pid))\n\tfor i := 0; i < b.N; i++ {\n\t\tp.fillFromCommWithContext(context.Background())\n\t}\n}\n\nfunc Benchmark_fillFromStatusWithContext(b *testing.B) {\n\tb.Setenv(\"HOST_PROC\", \"testdata/linux\")\n\tpid := 1060\n\tp, _ := NewProcess(int32(pid))\n\tfor i := 0; i < b.N; i++ {\n\t\tp.fillFromStatus()\n\t}\n}\n\nfunc TestFillFromTIDStatWithContext_lx_brandz(t *testing.T) {\n\tpids, err := os.ReadDir(\"testdata/lx_brandz/\")\n\trequire.NoError(t, err)\n\tt.Setenv(\"HOST_PROC\", \"testdata/lx_brandz\")\n\tfor _, pid := range pids {\n\t\tpid, err := strconv.ParseInt(pid.Name(), 0, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif _, err := os.Stat(fmt.Sprintf(\"testdata/lx_brandz/%d/stat\", pid)); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tp, _ := NewProcess(int32(pid))\n\t\t_, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStat(-1)\n\t\trequire.NoError(t, err)\n\t\tassert.Zero(t, cpuTimes.Iowait)\n\t}\n}\n\nfunc TestProcessMemoryMaps(t *testing.T) {\n\tt.Setenv(\"HOST_PROC\", \"testdata/linux\")\n\tpid := 1\n\tp, err := NewProcess(int32(pid))\n\trequire.NoError(t, err)\n\tmaps, err := p.MemoryMaps(false)\n\trequire.NoError(t, err)\n\n\texpected := &[]MemoryMapsStat{\n\t\t{\n\t\t\t\"[vvar]\",\n\t\t\t0,\n\t\t\t1,\n\t\t\t0,\n\t\t\t3,\n\t\t\t4,\n\t\t\t5,\n\t\t\t6,\n\t\t\t7,\n\t\t\t8,\n\t\t\t9,\n\t\t},\n\t\t{\n\t\t\t\"\",\n\t\t\t0,\n\t\t\t1,\n\t\t\t2,\n\t\t\t3,\n\t\t\t4,\n\t\t\t0,\n\t\t\t6,\n\t\t\t7,\n\t\t\t8,\n\t\t\t9,\n\t\t},\n\t\t{\n\t\t\t\"[vdso]\",\n\t\t\t0,\n\t\t\t1,\n\t\t\t2,\n\t\t\t3,\n\t\t\t4,\n\t\t\t5,\n\t\t\t0,\n\t\t\t7,\n\t\t\t8,\n\t\t\t9,\n\t\t},\n\t\t{\n\t\t\t\"/usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1\",\n\t\t\t0,\n\t\t\t1,\n\t\t\t2,\n\t\t\t3,\n\t\t\t4,\n\t\t\t5,\n\t\t\t6,\n\t\t\t7,\n\t\t\t0,\n\t\t\t9,\n\t\t},\n\t}\n\n\trequire.Equal(t, expected, maps)\n}\n"
  },
  {
    "path": "process/process_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage process\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/mem\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\nfunc pidsWithContext(ctx context.Context) ([]int32, error) {\n\tvar ret []int32\n\tprocs, err := ProcessesWithContext(ctx)\n\tif err != nil {\n\t\treturn ret, nil\n\t}\n\n\tfor _, p := range procs {\n\t\tret = append(ret, p.Pid)\n\t}\n\n\treturn ret, nil\n}\n\nfunc (p *Process) PpidWithContext(_ context.Context) (int32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn k.Ppid, nil\n}\n\nfunc (p *Process) NameWithContext(ctx context.Context) (string, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tname := common.IntToString(k.Comm[:])\n\n\tif len(name) >= 15 {\n\t\tcmdlineSlice, err := p.CmdlineSliceWithContext(ctx)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif len(cmdlineSlice) > 0 {\n\t\t\textendedName := filepath.Base(cmdlineSlice[0])\n\t\t\tif strings.HasPrefix(extendedName, p.name) {\n\t\t\t\tname = extendedName\n\t\t\t}\n\t\t}\n\t}\n\n\treturn name, nil\n}\n\nfunc (p *Process) CwdWithContext(_ context.Context) (string, error) {\n\tmib := []int32{CTLKern, KernProcCwd, p.Pid}\n\tbuf, _, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn common.ByteToString(buf), nil\n}\n\nfunc (*Process) ExeWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (p *Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {\n\tmib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv}\n\tbuf, _, err := common.CallSyscall(mib)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t/* From man sysctl(2):\n\tThe buffer pointed to by oldp is filled with an array of char\n\tpointers followed by the strings themselves. The last char\n\tpointer is a NULL pointer. */\n\tvar strParts []string\n\tr := bytes.NewReader(buf)\n\tbaseAddr := uintptr(unsafe.Pointer(&buf[0]))\n\tfor {\n\t\targvp, err := readPtr(r)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif argvp == 0 { // check for a NULL pointer\n\t\t\tbreak\n\t\t}\n\t\toffset := argvp - baseAddr\n\t\tlength := uintptr(bytes.IndexByte(buf[offset:], 0))\n\t\tstr := string(buf[offset : offset+length])\n\t\tstrParts = append(strParts, str)\n\t}\n\n\treturn strParts, nil\n}\n\n// readPtr reads a pointer data from a given reader. WARNING: only little\n// endian architectures are supported.\nfunc readPtr(r io.Reader) (uintptr, error) {\n\tswitch sizeofPtr {\n\tcase 4:\n\t\tvar p uint32\n\t\tif err := binary.Read(r, binary.LittleEndian, &p); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\treturn uintptr(p), nil\n\tcase 8:\n\t\tvar p uint64\n\t\tif err := binary.Read(r, binary.LittleEndian, &p); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\treturn uintptr(p), nil\n\tdefault:\n\t\treturn 0, errors.New(\"unsupported pointer size\")\n\t}\n}\n\nfunc (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {\n\targv, err := p.CmdlineSliceWithContext(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn strings.Join(argv, \" \"), nil\n}\n\nfunc (*Process) createTimeWithContext(_ context.Context) (int64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (p *Process) StatusWithContext(_ context.Context) ([]string, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn []string{\"\"}, err\n\t}\n\tvar s string\n\tswitch k.Stat {\n\tcase SIDL:\n\tcase SRUN:\n\tcase SONPROC:\n\t\ts = Running\n\tcase SSLEEP:\n\t\ts = Sleep\n\tcase SSTOP:\n\t\ts = Stop\n\tcase SDEAD:\n\t\ts = Zombie\n\t}\n\n\treturn []string{s}, nil\n}\n\nfunc (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {\n\t// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details\n\tpid := p.Pid\n\tout, err := invoke.CommandWithContext(ctx, \"ps\", \"-o\", \"stat=\", \"-p\", strconv.Itoa(int(pid)))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn strings.IndexByte(string(out), '+') != -1, nil\n}\n\nfunc (p *Process) UidsWithContext(_ context.Context) ([]uint32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tuids := make([]uint32, 0, 3)\n\n\tuids = append(uids, uint32(k.Ruid), uint32(k.Uid), uint32(k.Svuid))\n\n\treturn uids, nil\n}\n\nfunc (p *Process) GidsWithContext(_ context.Context) ([]uint32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgids := make([]uint32, 0, 3)\n\tgids = append(gids, uint32(k.Rgid), uint32(k.Ngroups), uint32(k.Svgid))\n\n\treturn gids, nil\n}\n\nfunc (p *Process) GroupsWithContext(_ context.Context) ([]uint32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgroups := make([]uint32, k.Ngroups)\n\tfor i := int16(0); i < k.Ngroups; i++ {\n\t\tgroups[i] = uint32(k.Groups[i])\n\t}\n\n\treturn groups, nil\n}\n\nfunc (p *Process) TerminalWithContext(_ context.Context) (string, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tttyNr := uint64(k.Tdev)\n\n\ttermmap, err := getTerminalMap()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn termmap[ttyNr], nil\n}\n\nfunc (p *Process) NiceWithContext(_ context.Context) (int32, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int32(k.Nice), nil\n}\n\nfunc (p *Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &IOCountersStat{\n\t\tReadCount:  uint64(k.Uru_inblock),\n\t\tWriteCount: uint64(k.Uru_oublock),\n\t}, nil\n}\n\nfunc (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {\n\t/* not supported, just return 1 */\n\treturn 1, nil\n}\n\nfunc (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &cpu.TimesStat{\n\t\tCPU:    \"cpu\",\n\t\tUser:   float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000,\n\t\tSystem: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000,\n\t}, nil\n}\n\nfunc (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {\n\tk, err := p.getKProc()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpageSize, err := mem.GetPageSizeWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &MemoryInfoStat{\n\t\tRSS: uint64(k.Vm_rssize) * pageSize,\n\t\tVMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) +\n\t\t\tuint64(k.Vm_ssize),\n\t}, nil\n}\n\nfunc (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {\n\tprocs, err := ProcessesWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, nil\n\t}\n\tret := make([]*Process, 0, len(procs))\n\tfor _, proc := range procs {\n\t\tppid, err := proc.PpidWithContext(ctx)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif ppid == p.Pid {\n\t\t\tret = append(ret, proc)\n\t\t}\n\t}\n\tsort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })\n\treturn ret, nil\n}\n\nfunc (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProcessesWithContext(ctx context.Context) ([]*Process, error) {\n\tresults := []*Process{}\n\n\tbuf, length, err := callKernProcSyscall(KernProcAll, 0)\n\tif err != nil {\n\t\treturn results, err\n\t}\n\n\t// get kinfo_proc size\n\tcount := int(length / uint64(sizeOfKinfoProc))\n\n\t// parse buf to procs\n\tfor i := 0; i < count; i++ {\n\t\tb := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]\n\t\tk, err := parseKinfoProc(b)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tp, err := NewProcessWithContext(ctx, int32(k.Pid))\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tresults = append(results, p)\n\t}\n\n\treturn results, nil\n}\n\nfunc (*Process) NumFDsWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (p *Process) getKProc() (*KinfoProc, error) {\n\tbuf, length, err := callKernProcSyscall(KernProcPID, p.Pid)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif length != sizeOfKinfoProc {\n\t\treturn nil, errors.New(\"unexpected size of KinfoProc\")\n\t}\n\n\tk, err := parseKinfoProc(buf)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &k, nil\n}\n\nfunc callKernProcSyscall(op, arg int32) ([]byte, uint64, error) {\n\tmib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0}\n\tmibptr := unsafe.Pointer(&mib[0])\n\tmiblen := uint64(len(mib))\n\tlength := uint64(0)\n\t_, _, err := unix.Syscall6(\n\t\tunix.SYS___SYSCTL,\n\t\tuintptr(mibptr),\n\t\tuintptr(miblen),\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\t0,\n\t\t0)\n\tif err != 0 {\n\t\treturn nil, length, err\n\t}\n\n\tcount := int32(length / uint64(sizeOfKinfoProc))\n\tmib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count}\n\tmibptr = unsafe.Pointer(&mib[0])\n\tmiblen = uint64(len(mib))\n\t// get proc info itself\n\tbuf := make([]byte, length)\n\t_, _, err = unix.Syscall6(\n\t\tunix.SYS___SYSCTL,\n\t\tuintptr(mibptr),\n\t\tuintptr(miblen),\n\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\t0,\n\t\t0)\n\tif err != 0 {\n\t\treturn buf, length, err\n\t}\n\n\treturn buf, length, nil\n}\n"
  },
  {
    "path": "process/process_openbsd_386.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && 386\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs process/types_openbsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 66\n\tKernProcAll      = 0\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 55\n\tKernProcCwd      = 78\n\tKernProcArgv     = 1\n\tKernProcEnv      = 3\n)\n\nconst (\n\tArgMax = 256 * 1024\n)\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x38\n\tsizeOfKinfoProc    = 0x264\n)\n\nconst (\n\tSIDL    = 1\n\tSRUN    = 2\n\tSSLEEP  = 3\n\tSSTOP   = 4\n\tSZOMB   = 5\n\tSDEAD   = 6\n\tSONPROC = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int32\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int32\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int32\n\tIxrss    int32\n\tIdrss    int32\n\tIsrss    int32\n\tMinflt   int32\n\tMajflt   int32\n\tNswap    int32\n\tInblock  int32\n\tOublock  int32\n\tMsgsnd   int32\n\tMsgrcv   int32\n\tNsignals int32\n\tNvcsw    int32\n\tNivcsw   int32\n}\n\ntype Rlimit struct {\n\tCur uint64\n\tMax uint64\n}\n\ntype KinfoProc struct {\n\tForw         uint64\n\tBack         uint64\n\tPaddr        uint64\n\tAddr         uint64\n\tFd           uint64\n\tStats        uint64\n\tLimit        uint64\n\tVmspace      uint64\n\tSigacts      uint64\n\tSess         uint64\n\tTsess        uint64\n\tRu           uint64\n\tEflag        int32\n\tExitsig      int32\n\tFlag         int32\n\tPid          int32\n\tPpid         int32\n\tSid          int32\n\tX_pgid       int32\n\tTpgid        int32\n\tUid          uint32\n\tRuid         uint32\n\tGid          uint32\n\tRgid         uint32\n\tGroups       [16]uint32\n\tNgroups      int16\n\tJobc         int16\n\tTdev         uint32\n\tEstcpu       uint32\n\tRtime_sec    uint32\n\tRtime_usec   uint32\n\tCpticks      int32\n\tPctcpu       uint32\n\tSwtime       uint32\n\tSlptime      uint32\n\tSchedflags   int32\n\tUticks       uint64\n\tSticks       uint64\n\tIticks       uint64\n\tTracep       uint64\n\tTraceflag    int32\n\tHoldcnt      int32\n\tSiglist      int32\n\tSigmask      uint32\n\tSigignore    uint32\n\tSigcatch     uint32\n\tStat         int8\n\tPriority     uint8\n\tUsrpri       uint8\n\tNice         uint8\n\tXstat        uint16\n\tAcflag       uint16\n\tComm         [24]int8\n\tWmesg        [8]int8\n\tWchan        uint64\n\tLogin        [32]int8\n\tVm_rssize    int32\n\tVm_tsize     int32\n\tVm_dsize     int32\n\tVm_ssize     int32\n\tUvalid       int64\n\tUstart_sec   uint64\n\tUstart_usec  uint32\n\tUutime_sec   uint32\n\tUutime_usec  uint32\n\tUstime_sec   uint32\n\tUstime_usec  uint32\n\tUru_maxrss   uint64\n\tUru_ixrss    uint64\n\tUru_idrss    uint64\n\tUru_isrss    uint64\n\tUru_minflt   uint64\n\tUru_majflt   uint64\n\tUru_nswap    uint64\n\tUru_inblock  uint64\n\tUru_oublock  uint64\n\tUru_msgsnd   uint64\n\tUru_msgrcv   uint64\n\tUru_nsignals uint64\n\tUru_nvcsw    uint64\n\tUru_nivcsw   uint64\n\tUctime_sec   uint32\n\tUctime_usec  uint32\n\tPsflags      int32\n\tSpare        int32\n\tSvuid        uint32\n\tSvgid        uint32\n\tEmul         [8]int8\n\tRlim_rss_cur uint64\n\tCpuid        uint64\n\tVm_map_size  uint64\n\tTid          int32\n\tRtableid     uint32\n}\n\ntype Priority struct{}\n\ntype KinfoVmentry struct {\n\tStart          uint32\n\tEnd            uint32\n\tGuard          uint32\n\tFspace         uint32\n\tFspace_augment uint32\n\tOffset         uint64\n\tWired_count    int32\n\tEtype          int32\n\tProtection     int32\n\tMax_protection int32\n\tAdvice         int32\n\tInheritance    int32\n\tFlags          uint8\n\tPad_cgo_0      [3]byte\n}\n"
  },
  {
    "path": "process/process_openbsd_amd64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Created by cgo -godefs - DO NOT EDIT\n// cgo -godefs types_openbsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 66\n\tKernProcAll      = 0\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 55\n\tKernProcCwd      = 78\n\tKernProcArgv     = 1\n\tKernProcEnv      = 3\n)\n\nconst (\n\tArgMax = 256 * 1024\n)\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x50\n\tsizeOfKinfoProc    = 0x268\n)\n\nconst (\n\tSIDL    = 1\n\tSRUN    = 2\n\tSSLEEP  = 3\n\tSSTOP   = 4\n\tSZOMB   = 5\n\tSDEAD   = 6\n\tSONPROC = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int64\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int64\n\tIxrss    int64\n\tIdrss    int64\n\tIsrss    int64\n\tMinflt   int64\n\tMajflt   int64\n\tNswap    int64\n\tInblock  int64\n\tOublock  int64\n\tMsgsnd   int64\n\tMsgrcv   int64\n\tNsignals int64\n\tNvcsw    int64\n\tNivcsw   int64\n}\n\ntype Rlimit struct {\n\tCur uint64\n\tMax uint64\n}\n\ntype KinfoProc struct {\n\tForw         uint64\n\tBack         uint64\n\tPaddr        uint64\n\tAddr         uint64\n\tFd           uint64\n\tStats        uint64\n\tLimit        uint64\n\tVmspace      uint64\n\tSigacts      uint64\n\tSess         uint64\n\tTsess        uint64\n\tRu           uint64\n\tEflag        int32\n\tExitsig      int32\n\tFlag         int32\n\tPid          int32\n\tPpid         int32\n\tSid          int32\n\tX_pgid       int32\n\tTpgid        int32\n\tUid          uint32\n\tRuid         uint32\n\tGid          uint32\n\tRgid         uint32\n\tGroups       [16]uint32\n\tNgroups      int16\n\tJobc         int16\n\tTdev         uint32\n\tEstcpu       uint32\n\tRtime_sec    uint32\n\tRtime_usec   uint32\n\tCpticks      int32\n\tPctcpu       uint32\n\tSwtime       uint32\n\tSlptime      uint32\n\tSchedflags   int32\n\tUticks       uint64\n\tSticks       uint64\n\tIticks       uint64\n\tTracep       uint64\n\tTraceflag    int32\n\tHoldcnt      int32\n\tSiglist      int32\n\tSigmask      uint32\n\tSigignore    uint32\n\tSigcatch     uint32\n\tStat         int8\n\tPriority     uint8\n\tUsrpri       uint8\n\tNice         uint8\n\tXstat        uint16\n\tAcflag       uint16\n\tComm         [24]int8\n\tWmesg        [8]int8\n\tWchan        uint64\n\tLogin        [32]int8\n\tVm_rssize    int32\n\tVm_tsize     int32\n\tVm_dsize     int32\n\tVm_ssize     int32\n\tUvalid       int64\n\tUstart_sec   uint64\n\tUstart_usec  uint32\n\tUutime_sec   uint32\n\tUutime_usec  uint32\n\tUstime_sec   uint32\n\tUstime_usec  uint32\n\tPad_cgo_0    [4]byte\n\tUru_maxrss   uint64\n\tUru_ixrss    uint64\n\tUru_idrss    uint64\n\tUru_isrss    uint64\n\tUru_minflt   uint64\n\tUru_majflt   uint64\n\tUru_nswap    uint64\n\tUru_inblock  uint64\n\tUru_oublock  uint64\n\tUru_msgsnd   uint64\n\tUru_msgrcv   uint64\n\tUru_nsignals uint64\n\tUru_nvcsw    uint64\n\tUru_nivcsw   uint64\n\tUctime_sec   uint32\n\tUctime_usec  uint32\n\tPsflags      int32\n\tSpare        int32\n\tSvuid        uint32\n\tSvgid        uint32\n\tEmul         [8]int8\n\tRlim_rss_cur uint64\n\tCpuid        uint64\n\tVm_map_size  uint64\n\tTid          int32\n\tRtableid     uint32\n}\n\ntype Priority struct{}\n\ntype KinfoVmentry struct {\n\tStart          uint64\n\tEnd            uint64\n\tGuard          uint64\n\tFspace         uint64\n\tFspace_augment uint64\n\tOffset         uint64\n\tWired_count    int32\n\tEtype          int32\n\tProtection     int32\n\tMax_protection int32\n\tAdvice         int32\n\tInheritance    int32\n\tFlags          uint8\n\tPad_cgo_0      [7]byte\n}\n"
  },
  {
    "path": "process/process_openbsd_arm.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && arm\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs process/types_openbsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 66\n\tKernProcAll      = 0\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 55\n\tKernProcCwd      = 78\n\tKernProcArgv     = 1\n\tKernProcEnv      = 3\n)\n\nconst (\n\tArgMax = 256 * 1024\n)\n\nconst (\n\tsizeofPtr      = 0x4\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x4\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x38\n\tsizeOfKinfoProc    = 0x264\n)\n\nconst (\n\tSIDL    = 1\n\tSRUN    = 2\n\tSSLEEP  = 3\n\tSSTOP   = 4\n\tSZOMB   = 5\n\tSDEAD   = 6\n\tSONPROC = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int32\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int32\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int32\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int32\n\tIxrss    int32\n\tIdrss    int32\n\tIsrss    int32\n\tMinflt   int32\n\tMajflt   int32\n\tNswap    int32\n\tInblock  int32\n\tOublock  int32\n\tMsgsnd   int32\n\tMsgrcv   int32\n\tNsignals int32\n\tNvcsw    int32\n\tNivcsw   int32\n}\n\ntype Rlimit struct {\n\tCur uint64\n\tMax uint64\n}\n\ntype KinfoProc struct {\n\tForw         uint64\n\tBack         uint64\n\tPaddr        uint64\n\tAddr         uint64\n\tFd           uint64\n\tStats        uint64\n\tLimit        uint64\n\tVmspace      uint64\n\tSigacts      uint64\n\tSess         uint64\n\tTsess        uint64\n\tRu           uint64\n\tEflag        int32\n\tExitsig      int32\n\tFlag         int32\n\tPid          int32\n\tPpid         int32\n\tSid          int32\n\tX_pgid       int32\n\tTpgid        int32\n\tUid          uint32\n\tRuid         uint32\n\tGid          uint32\n\tRgid         uint32\n\tGroups       [16]uint32\n\tNgroups      int16\n\tJobc         int16\n\tTdev         uint32\n\tEstcpu       uint32\n\tRtime_sec    uint32\n\tRtime_usec   uint32\n\tCpticks      int32\n\tPctcpu       uint32\n\tSwtime       uint32\n\tSlptime      uint32\n\tSchedflags   int32\n\tUticks       uint64\n\tSticks       uint64\n\tIticks       uint64\n\tTracep       uint64\n\tTraceflag    int32\n\tHoldcnt      int32\n\tSiglist      int32\n\tSigmask      uint32\n\tSigignore    uint32\n\tSigcatch     uint32\n\tStat         int8\n\tPriority     uint8\n\tUsrpri       uint8\n\tNice         uint8\n\tXstat        uint16\n\tAcflag       uint16\n\tComm         [24]int8\n\tWmesg        [8]int8\n\tWchan        uint64\n\tLogin        [32]int8\n\tVm_rssize    int32\n\tVm_tsize     int32\n\tVm_dsize     int32\n\tVm_ssize     int32\n\tUvalid       int64\n\tUstart_sec   uint64\n\tUstart_usec  uint32\n\tUutime_sec   uint32\n\tUutime_usec  uint32\n\tUstime_sec   uint32\n\tUstime_usec  uint32\n\tUru_maxrss   uint64\n\tUru_ixrss    uint64\n\tUru_idrss    uint64\n\tUru_isrss    uint64\n\tUru_minflt   uint64\n\tUru_majflt   uint64\n\tUru_nswap    uint64\n\tUru_inblock  uint64\n\tUru_oublock  uint64\n\tUru_msgsnd   uint64\n\tUru_msgrcv   uint64\n\tUru_nsignals uint64\n\tUru_nvcsw    uint64\n\tUru_nivcsw   uint64\n\tUctime_sec   uint32\n\tUctime_usec  uint32\n\tPsflags      int32\n\tSpare        int32\n\tSvuid        uint32\n\tSvgid        uint32\n\tEmul         [8]int8\n\tRlim_rss_cur uint64\n\tCpuid        uint64\n\tVm_map_size  uint64\n\tTid          int32\n\tRtableid     uint32\n}\n\ntype Priority struct{}\n\ntype KinfoVmentry struct {\n\tStart          uint32\n\tEnd            uint32\n\tGuard          uint32\n\tFspace         uint32\n\tFspace_augment uint32\n\tOffset         uint64\n\tWired_count    int32\n\tEtype          int32\n\tProtection     int32\n\tMax_protection int32\n\tAdvice         int32\n\tInheritance    int32\n\tFlags          uint8\n\tPad_cgo_0      [3]byte\n}\n"
  },
  {
    "path": "process/process_openbsd_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && arm64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs process/types_openbsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 66\n\tKernProcAll      = 0\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 55\n\tKernProcCwd      = 78\n\tKernProcArgv     = 1\n\tKernProcEnv      = 3\n)\n\nconst (\n\tArgMax = 256 * 1024\n)\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x50\n\tsizeOfKinfoProc    = 0x270\n)\n\nconst (\n\tSIDL    = 1\n\tSRUN    = 2\n\tSSLEEP  = 3\n\tSSTOP   = 4\n\tSZOMB   = 5\n\tSDEAD   = 6\n\tSONPROC = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int64\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int64\n\tIxrss    int64\n\tIdrss    int64\n\tIsrss    int64\n\tMinflt   int64\n\tMajflt   int64\n\tNswap    int64\n\tInblock  int64\n\tOublock  int64\n\tMsgsnd   int64\n\tMsgrcv   int64\n\tNsignals int64\n\tNvcsw    int64\n\tNivcsw   int64\n}\n\ntype Rlimit struct {\n\tCur uint64\n\tMax uint64\n}\n\ntype KinfoProc struct {\n\tForw         uint64\n\tBack         uint64\n\tPaddr        uint64\n\tAddr         uint64\n\tFd           uint64\n\tStats        uint64\n\tLimit        uint64\n\tVmspace      uint64\n\tSigacts      uint64\n\tSess         uint64\n\tTsess        uint64\n\tRu           uint64\n\tEflag        int32\n\tExitsig      int32\n\tFlag         int32\n\tPid          int32\n\tPpid         int32\n\tSid          int32\n\tX_pgid       int32\n\tTpgid        int32\n\tUid          uint32\n\tRuid         uint32\n\tGid          uint32\n\tRgid         uint32\n\tGroups       [16]uint32\n\tNgroups      int16\n\tJobc         int16\n\tTdev         uint32\n\tEstcpu       uint32\n\tRtime_sec    uint32\n\tRtime_usec   uint32\n\tCpticks      int32\n\tPctcpu       uint32\n\tSwtime       uint32\n\tSlptime      uint32\n\tSchedflags   int32\n\tUticks       uint64\n\tSticks       uint64\n\tIticks       uint64\n\tTracep       uint64\n\tTraceflag    int32\n\tHoldcnt      int32\n\tSiglist      int32\n\tSigmask      uint32\n\tSigignore    uint32\n\tSigcatch     uint32\n\tStat         int8\n\tPriority     uint8\n\tUsrpri       uint8\n\tNice         uint8\n\tXstat        uint16\n\tAcflag       uint16\n\tComm         [24]int8\n\tWmesg        [8]uint8\n\tWchan        uint64\n\tLogin        [32]uint8\n\tVm_rssize    int32\n\tVm_tsize     int32\n\tVm_dsize     int32\n\tVm_ssize     int32\n\tUvalid       int64\n\tUstart_sec   uint64\n\tUstart_usec  uint32\n\tUutime_sec   uint32\n\tUutime_usec  uint32\n\tUstime_sec   uint32\n\tUstime_usec  uint32\n\tUru_maxrss   uint64\n\tUru_ixrss    uint64\n\tUru_idrss    uint64\n\tUru_isrss    uint64\n\tUru_minflt   uint64\n\tUru_majflt   uint64\n\tUru_nswap    uint64\n\tUru_inblock  uint64\n\tUru_oublock  uint64\n\tUru_msgsnd   uint64\n\tUru_msgrcv   uint64\n\tUru_nsignals uint64\n\tUru_nvcsw    uint64\n\tUru_nivcsw   uint64\n\tUctime_sec   uint32\n\tUctime_usec  uint32\n\tPsflags      uint32\n\tSpare        int32\n\tSvuid        uint32\n\tSvgid        uint32\n\tEmul         [8]uint8\n\tRlim_rss_cur uint64\n\tCpuid        uint64\n\tVm_map_size  uint64\n\tTid          int32\n\tRtableid     uint32\n\tPledge       uint64\n}\n\ntype Priority struct{}\n\ntype KinfoVmentry struct {\n\tStart          uint64\n\tEnd            uint64\n\tGuard          uint64\n\tFspace         uint64\n\tFspace_augment uint64\n\tOffset         uint64\n\tWired_count    int32\n\tEtype          int32\n\tProtection     int32\n\tMax_protection int32\n\tAdvice         int32\n\tInheritance    int32\n\tFlags          uint8\n\tPad_cgo_0      [7]byte\n}\n"
  },
  {
    "path": "process/process_openbsd_riscv64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd && riscv64\n\n// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n// cgo -godefs process/types_openbsd.go\n\npackage process\n\nconst (\n\tCTLKern          = 1\n\tKernProc         = 66\n\tKernProcAll      = 0\n\tKernProcPID      = 1\n\tKernProcProc     = 8\n\tKernProcPathname = 12\n\tKernProcArgs     = 55\n\tKernProcCwd      = 78\n\tKernProcArgv     = 1\n\tKernProcEnv      = 3\n)\n\nconst (\n\tArgMax = 256 * 1024\n)\n\nconst (\n\tsizeofPtr      = 0x8\n\tsizeofShort    = 0x2\n\tsizeofInt      = 0x4\n\tsizeofLong     = 0x8\n\tsizeofLongLong = 0x8\n)\n\nconst (\n\tsizeOfKinfoVmentry = 0x50\n\tsizeOfKinfoProc    = 0x288\n)\n\nconst (\n\tSIDL    = 1\n\tSRUN    = 2\n\tSSLEEP  = 3\n\tSSTOP   = 4\n\tSZOMB   = 5\n\tSDEAD   = 6\n\tSONPROC = 7\n)\n\ntype (\n\t_C_short     int16\n\t_C_int       int32\n\t_C_long      int64\n\t_C_long_long int64\n)\n\ntype Timespec struct {\n\tSec  int64\n\tNsec int64\n}\n\ntype Timeval struct {\n\tSec  int64\n\tUsec int64\n}\n\ntype Rusage struct {\n\tUtime    Timeval\n\tStime    Timeval\n\tMaxrss   int64\n\tIxrss    int64\n\tIdrss    int64\n\tIsrss    int64\n\tMinflt   int64\n\tMajflt   int64\n\tNswap    int64\n\tInblock  int64\n\tOublock  int64\n\tMsgsnd   int64\n\tMsgrcv   int64\n\tNsignals int64\n\tNvcsw    int64\n\tNivcsw   int64\n}\n\ntype Rlimit struct {\n\tCur uint64\n\tMax uint64\n}\n\ntype KinfoProc struct {\n\tForw         uint64\n\tBack         uint64\n\tPaddr        uint64\n\tAddr         uint64\n\tFd           uint64\n\tStats        uint64\n\tLimit        uint64\n\tVmspace      uint64\n\tSigacts      uint64\n\tSess         uint64\n\tTsess        uint64\n\tRu           uint64\n\tEflag        int32\n\tExitsig      int32\n\tFlag         int32\n\tPid          int32\n\tPpid         int32\n\tSid          int32\n\tX_pgid       int32\n\tTpgid        int32\n\tUid          uint32\n\tRuid         uint32\n\tGid          uint32\n\tRgid         uint32\n\tGroups       [16]uint32\n\tNgroups      int16\n\tJobc         int16\n\tTdev         uint32\n\tEstcpu       uint32\n\tRtime_sec    uint32\n\tRtime_usec   uint32\n\tCpticks      int32\n\tPctcpu       uint32\n\tSwtime       uint32\n\tSlptime      uint32\n\tSchedflags   int32\n\tUticks       uint64\n\tSticks       uint64\n\tIticks       uint64\n\tTracep       uint64\n\tTraceflag    int32\n\tHoldcnt      int32\n\tSiglist      int32\n\tSigmask      uint32\n\tSigignore    uint32\n\tSigcatch     uint32\n\tStat         int8\n\tPriority     uint8\n\tUsrpri       uint8\n\tNice         uint8\n\tXstat        uint16\n\tSpare        uint16\n\tComm         [24]int8\n\tWmesg        [8]uint8\n\tWchan        uint64\n\tLogin        [32]uint8\n\tVm_rssize    int32\n\tVm_tsize     int32\n\tVm_dsize     int32\n\tVm_ssize     int32\n\tUvalid       int64\n\tUstart_sec   uint64\n\tUstart_usec  uint32\n\tUutime_sec   uint32\n\tUutime_usec  uint32\n\tUstime_sec   uint32\n\tUstime_usec  uint32\n\tUru_maxrss   uint64\n\tUru_ixrss    uint64\n\tUru_idrss    uint64\n\tUru_isrss    uint64\n\tUru_minflt   uint64\n\tUru_majflt   uint64\n\tUru_nswap    uint64\n\tUru_inblock  uint64\n\tUru_oublock  uint64\n\tUru_msgsnd   uint64\n\tUru_msgrcv   uint64\n\tUru_nsignals uint64\n\tUru_nvcsw    uint64\n\tUru_nivcsw   uint64\n\tUctime_sec   uint32\n\tUctime_usec  uint32\n\tPsflags      uint32\n\tAcflag       uint32\n\tSvuid        uint32\n\tSvgid        uint32\n\tEmul         [8]uint8\n\tRlim_rss_cur uint64\n\tCpuid        uint64\n\tVm_map_size  uint64\n\tTid          int32\n\tRtableid     uint32\n\tPledge       uint64\n\tName         [24]uint8\n}\n\ntype Priority struct{}\n\ntype KinfoVmentry struct {\n\tStart          uint64\n\tEnd            uint64\n\tGuard          uint64\n\tFspace         uint64\n\tFspace_augment uint64\n\tOffset         uint64\n\tWired_count    int32\n\tEtype          int32\n\tProtection     int32\n\tMax_protection int32\n\tAdvice         int32\n\tInheritance    int32\n\tFlags          uint8\n\tPad_cgo_0      [7]byte\n}\n"
  },
  {
    "path": "process/process_plan9.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build plan9\n\npackage process\n\nimport (\n\t\"context\"\n\t\"syscall\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\ntype Signal = syscall.Note\n\ntype MemoryMapsStat struct {\n\tPath         string `json:\"path\"`\n\tRss          uint64 `json:\"rss\"`\n\tSize         uint64 `json:\"size\"`\n\tPss          uint64 `json:\"pss\"`\n\tSharedClean  uint64 `json:\"sharedClean\"`\n\tSharedDirty  uint64 `json:\"sharedDirty\"`\n\tPrivateClean uint64 `json:\"privateClean\"`\n\tPrivateDirty uint64 `json:\"privateDirty\"`\n\tReferenced   uint64 `json:\"referenced\"`\n\tAnonymous    uint64 `json:\"anonymous\"`\n\tSwap         uint64 `json:\"swap\"`\n}\n\ntype MemoryInfoExStat struct{}\n\nfunc pidsWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc ProcessesWithContext(_ context.Context) ([]*Process, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc PidExistsWithContext(_ context.Context, _ int32) (bool, error) {\n\treturn false, common.ErrNotImplementedError\n}\n\nfunc (*Process) PpidWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) NameWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) TgidWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) ExeWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) CmdlineWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) createTimeWithContext(_ context.Context) (int64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) CwdWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) StatusWithContext(_ context.Context) ([]string, error) {\n\treturn []string{\"\"}, common.ErrNotImplementedError\n}\n\nfunc (*Process) ForegroundWithContext(_ context.Context) (bool, error) {\n\treturn false, common.ErrNotImplementedError\n}\n\nfunc (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) TerminalWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) NiceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) IOniceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) NumFDsWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) SendSignalWithContext(_ context.Context, _ Signal) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) SuspendWithContext(_ context.Context) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) ResumeWithContext(_ context.Context) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) TerminateWithContext(_ context.Context) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) KillWithContext(_ context.Context) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (*Process) UsernameWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) EnvironWithContext(_ context.Context) ([]string, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "process/process_posix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux || freebsd || openbsd || darwin || solaris\n\npackage process\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/user\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\ntype Signal = syscall.Signal\n\n// POSIX\nfunc getTerminalMap() (map[uint64]string, error) {\n\tret := make(map[uint64]string)\n\tvar termfiles []string\n\n\tdevPath := common.HostDev()\n\n\td, err := os.Open(devPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer d.Close()\n\n\tdevnames, err := d.Readdirnames(-1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, devname := range devnames {\n\t\tif strings.HasPrefix(devname, \"tty\") {\n\t\t\ttermfiles = append(termfiles, filepath.Join(devPath, devname))\n\t\t}\n\t}\n\n\tvar ptsnames []string\n\tptsPath := filepath.Join(devPath, \"pts\")\n\tptsd, err := os.Open(ptsPath)\n\tif err != nil {\n\t\tptsnames, _ = filepath.Glob(filepath.Join(devPath, \"ttyp*\"))\n\t\tif ptsnames == nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttermfiles = append(termfiles, ptsnames...)\n\t} else {\n\t\tdefer ptsd.Close()\n\t\tptsnames, err = ptsd.Readdirnames(-1)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor _, ptsname := range ptsnames {\n\t\t\ttermfiles = append(termfiles, filepath.Join(ptsPath, ptsname))\n\t\t}\n\t}\n\n\tfor _, name := range termfiles {\n\t\tstat := unix.Stat_t{}\n\t\terr = unix.Stat(name, &stat)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trdev := uint64(stat.Rdev)\n\t\tret[rdev] = strings.TrimPrefix(name, devPath+string(os.PathSeparator))\n\t}\n\treturn ret, nil\n}\n\n// isMount is a port of python's os.path.ismount()\n// https://github.com/python/cpython/blob/08ff4369afca84587b1c82034af4e9f64caddbf2/Lib/posixpath.py#L186-L216\n// https://docs.python.org/3/library/os.path.html#os.path.ismount\nfunc isMount(path string) bool {\n\t// Check symlinkness with os.Lstat; unix.DT_LNK is not portable\n\tfileInfo, err := os.Lstat(path)\n\tif err != nil {\n\t\treturn false\n\t}\n\tif fileInfo.Mode()&os.ModeSymlink != 0 {\n\t\treturn false\n\t}\n\tvar stat1 unix.Stat_t\n\tif err := unix.Lstat(path, &stat1); err != nil {\n\t\treturn false\n\t}\n\tparent := filepath.Join(path, \"..\")\n\tvar stat2 unix.Stat_t\n\tif err := unix.Lstat(parent, &stat2); err != nil {\n\t\treturn false\n\t}\n\treturn stat1.Dev != stat2.Dev || stat1.Ino == stat2.Ino\n}\n\nfunc PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {\n\tif pid <= 0 {\n\t\treturn false, fmt.Errorf(\"invalid pid %v\", pid)\n\t}\n\tproc, err := os.FindProcess(int(pid))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tdefer proc.Release()\n\n\tif isMount(common.HostProcWithContext(ctx)) { // if /<HOST_PROC>/proc exists and is mounted, check if /<HOST_PROC>/proc/<PID> folder exists\n\t\t_, err := os.Stat(common.HostProcWithContext(ctx, strconv.Itoa(int(pid))))\n\t\tif os.IsNotExist(err) {\n\t\t\treturn false, nil\n\t\t}\n\t\treturn err == nil, err\n\t}\n\n\t// procfs does not exist or is not mounted, check PID existence by signalling the pid\n\terr = proc.Signal(syscall.Signal(0))\n\tif err == nil {\n\t\treturn true, nil\n\t}\n\tif errors.Is(err, os.ErrProcessDone) {\n\t\treturn false, nil\n\t}\n\tvar errno syscall.Errno\n\tif !errors.As(err, &errno) {\n\t\treturn false, err\n\t}\n\tswitch errno {\n\tcase syscall.ESRCH:\n\t\treturn false, nil\n\tcase syscall.EPERM:\n\t\treturn true, nil\n\t}\n\n\treturn false, err\n}\n\nfunc (p *Process) SendSignalWithContext(_ context.Context, sig syscall.Signal) error {\n\tprocess, err := os.FindProcess(int(p.Pid))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer process.Release()\n\n\terr = process.Signal(sig)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (p *Process) SuspendWithContext(ctx context.Context) error {\n\treturn p.SendSignalWithContext(ctx, unix.SIGSTOP)\n}\n\nfunc (p *Process) ResumeWithContext(ctx context.Context) error {\n\treturn p.SendSignalWithContext(ctx, unix.SIGCONT)\n}\n\nfunc (p *Process) TerminateWithContext(ctx context.Context) error {\n\treturn p.SendSignalWithContext(ctx, unix.SIGTERM)\n}\n\nfunc (p *Process) KillWithContext(ctx context.Context) error {\n\treturn p.SendSignalWithContext(ctx, unix.SIGKILL)\n}\n\nfunc (p *Process) UsernameWithContext(ctx context.Context) (string, error) {\n\tuids, err := p.UidsWithContext(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(uids) > 0 {\n\t\tu, err := user.LookupId(strconv.Itoa(int(uids[0])))\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn u.Username, nil\n\t}\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "process/process_posix_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux || freebsd\n\npackage process\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc Test_SendSignal(t *testing.T) {\n\tcheckPid := os.Getpid()\n\n\tp, _ := NewProcess(int32(checkPid))\n\tassert.NoErrorf(t, p.SendSignal(unix.SIGCONT), \"send signal\")\n}\n\nfunc TestGetTerminalMapPathsExist(t *testing.T) {\n\ttermmap, err := getTerminalMap()\n\tif err != nil {\n\t\tt.Skipf(\"getTerminalMap not available: %v\", err)\n\t}\n\n\tfor _, name := range termmap {\n\t\tfullPath := common.HostDev(name)\n\t\t_, err := os.Stat(fullPath)\n\t\tassert.NoErrorf(t, err, \"terminal device should exist: %s\", fullPath)\n\t}\n}\n"
  },
  {
    "path": "process/process_race_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build race\n\npackage process\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestPpid_Race(t *testing.T) {\n\twg := sync.WaitGroup{}\n\ttestCount := 10\n\tp := testGetProcess()\n\twg.Add(testCount)\n\tfor i := 0; i < testCount; i++ {\n\t\tgo func(j int) {\n\t\t\tppid, err := p.Ppid()\n\t\t\twg.Done()\n\n\t\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\t\tt.Skip(\"not implemented\")\n\t\t\t}\n\n\t\t\trequire.NoError(t, err, \"Ppid() failed, %v\", err)\n\n\t\t\tif j == 9 {\n\t\t\t\tt.Logf(\"Ppid(): %d\", ppid)\n\t\t\t}\n\t\t}(i)\n\t}\n\twg.Wait()\n}\n"
  },
  {
    "path": "process/process_solaris.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage process\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\ntype MemoryMapsStat struct {\n\tPath         string `json:\"path\"`\n\tRss          uint64 `json:\"rss\"`\n\tSize         uint64 `json:\"size\"`\n\tPss          uint64 `json:\"pss\"`\n\tSharedClean  uint64 `json:\"sharedClean\"`\n\tSharedDirty  uint64 `json:\"sharedDirty\"`\n\tPrivateClean uint64 `json:\"privateClean\"`\n\tPrivateDirty uint64 `json:\"privateDirty\"`\n\tReferenced   uint64 `json:\"referenced\"`\n\tAnonymous    uint64 `json:\"anonymous\"`\n\tSwap         uint64 `json:\"swap\"`\n}\n\ntype MemoryInfoExStat struct{}\n\nfunc pidsWithContext(ctx context.Context) ([]int32, error) {\n\treturn readPidsFromDir(common.HostProcWithContext(ctx))\n}\n\nfunc ProcessesWithContext(ctx context.Context) ([]*Process, error) {\n\tout := []*Process{}\n\n\tpids, err := PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn out, err\n\t}\n\n\tfor _, pid := range pids {\n\t\tp, err := NewProcessWithContext(ctx, pid)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tout = append(out, p)\n\t}\n\n\treturn out, nil\n}\n\nfunc (*Process) PpidWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) NameWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) TgidWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (p *Process) ExeWithContext(ctx context.Context) (string, error) {\n\texe, err := p.fillFromPathAOutWithContext(ctx)\n\tif os.IsNotExist(err) {\n\t\texe, err = p.fillFromExecnameWithContext(ctx)\n\t}\n\treturn exe, err\n}\n\nfunc (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {\n\treturn p.fillFromCmdlineWithContext(ctx)\n}\n\nfunc (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {\n\treturn p.fillSliceFromCmdlineWithContext(ctx)\n}\n\nfunc (*Process) createTimeWithContext(_ context.Context) (int64, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (p *Process) CwdWithContext(ctx context.Context) (string, error) {\n\treturn p.fillFromPathCwdWithContext(ctx)\n}\n\nfunc (*Process) StatusWithContext(_ context.Context) ([]string, error) {\n\treturn []string{\"\"}, common.ErrNotImplementedError\n}\n\nfunc (*Process) ForegroundWithContext(_ context.Context) (bool, error) {\n\treturn false, common.ErrNotImplementedError\n}\n\nfunc (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) TerminalWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\nfunc (*Process) NiceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) IOniceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {\n\t_, fnames, err := p.fillFromfdListWithContext(ctx)\n\treturn int32(len(fnames)), err\n}\n\nfunc (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) EnvironWithContext(_ context.Context) ([]string, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\n/**\n** Internal functions\n**/\n\nfunc (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) {\n\tpid := p.Pid\n\tstatPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"fd\")\n\td, err := os.Open(statPath)\n\tif err != nil {\n\t\treturn statPath, []string{}, err\n\t}\n\tdefer d.Close()\n\tfnames, err := d.Readdirnames(-1)\n\treturn statPath, fnames, err\n}\n\nfunc (p *Process) fillFromPathCwdWithContext(ctx context.Context) (string, error) {\n\tpid := p.Pid\n\tcwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"path\", \"cwd\")\n\tcwd, err := os.Readlink(cwdPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn cwd, nil\n}\n\nfunc (p *Process) fillFromPathAOutWithContext(ctx context.Context) (string, error) {\n\tpid := p.Pid\n\tcwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"path\", \"a.out\")\n\texe, err := os.Readlink(cwdPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn exe, nil\n}\n\nfunc (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, error) {\n\tpid := p.Pid\n\texecNamePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"execname\")\n\texe, err := os.ReadFile(execNamePath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(exe), nil\n}\n\nfunc (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {\n\tpid := p.Pid\n\tcmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"cmdline\")\n\tcmdline, err := os.ReadFile(cmdPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tret := strings.FieldsFunc(string(cmdline), func(r rune) bool {\n\t\treturn r == '\\u0000'\n\t})\n\n\treturn strings.Join(ret, \" \"), nil\n}\n\nfunc (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {\n\tpid := p.Pid\n\tcmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), \"cmdline\")\n\tcmdline, err := os.ReadFile(cmdPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(cmdline) == 0 {\n\t\treturn nil, nil\n\t}\n\tif cmdline[len(cmdline)-1] == 0 {\n\t\tcmdline = cmdline[:len(cmdline)-1]\n\t}\n\tparts := bytes.Split(cmdline, []byte{0})\n\tvar strParts []string\n\tfor _, p := range parts {\n\t\tstrParts = append(strParts, string(p))\n\t}\n\n\treturn strParts, nil\n}\n\nfunc readPidsFromDir(path string) ([]int32, error) {\n\tvar ret []int32\n\n\td, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer d.Close()\n\n\tfnames, err := d.Readdirnames(-1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, fname := range fnames {\n\t\tif !strictIntPtrn.MatchString(fname) {\n\t\t\tcontinue\n\t\t}\n\t\tpid, err := strconv.ParseInt(fname, 10, 32)\n\t\tif err != nil {\n\t\t\t// if not numeric name, just skip\n\t\t\tcontinue\n\t\t}\n\t\tret = append(ret, int32(pid))\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "process/process_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\npackage process\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/user\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nvar mu sync.Mutex\n\nfunc testGetProcess() Process {\n\tcheckPid := os.Getpid() // process.test\n\tret, _ := NewProcess(int32(checkPid))\n\treturn *ret\n}\n\nfunc TestPids(t *testing.T) {\n\tret, err := Pids()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, ret, \"could not get pids %v\", ret)\n}\n\nfunc TestPid_exists(t *testing.T) {\n\tcheckPid := os.Getpid()\n\n\tret, err := PidExists(int32(checkPid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tassert.Truef(t, ret, \"could not get process exists: %v\", ret)\n}\n\nfunc TestNewProcess(t *testing.T) {\n\tcheckPid := os.Getpid()\n\n\tret, err := NewProcess(int32(checkPid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tempty := &Process{}\n\tif runtime.GOOS != \"windows\" { // Windows pid is 0\n\t\tassert.NotSamef(t, empty, ret, \"error %v\", ret)\n\t}\n}\n\nfunc TestMemoryMaps(t *testing.T) {\n\tcheckPid := os.Getpid()\n\n\tret, err := NewProcess(int32(checkPid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\t// ungrouped memory maps\n\tmmaps, err := ret.MemoryMaps(false)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"memory map get error %v\", err)\n\tempty := MemoryMapsStat{}\n\tfor _, m := range *mmaps {\n\t\tassert.NotEqualf(t, m, empty, \"memory map get error %v\", m)\n\t}\n\n\t// grouped memory maps\n\tmmaps, err = ret.MemoryMaps(true)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"memory map get error %v\", err)\n\tassert.Lenf(t, *mmaps, 1, \"grouped memory maps length (%v) is not equal to 1\", len(*mmaps))\n\tassert.NotEqualf(t, (*mmaps)[0], empty, \"memory map is empty\")\n}\n\nfunc TestMemoryInfo(t *testing.T) {\n\tp := testGetProcess()\n\n\tv, err := p.MemoryInfo()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting memory info error %v\", err)\n\tempty := MemoryInfoStat{}\n\tif v == nil || *v == empty {\n\t\tt.Errorf(\"could not get memory info %v\", v)\n\t}\n}\n\nfunc TestCmdLine(t *testing.T) {\n\tp := testGetProcess()\n\n\tv, err := p.Cmdline()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting cmdline error %v\", err)\n\tassert.Containsf(t, v, \"process.test\", \"invalid cmd line %v\", v)\n}\n\nfunc TestCmdLineSlice(t *testing.T) {\n\tp := testGetProcess()\n\n\tv, err := p.CmdlineSlice()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting cmdline slice error %v\", err)\n\tassert.Truef(t, reflect.DeepEqual(v, os.Args), \"returned cmdline slice not as expected:\\nexp: %v\\ngot: %v\", os.Args, v)\n}\n\nfunc TestPpid(t *testing.T) {\n\tp := testGetProcess()\n\n\tv, err := p.Ppid()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting ppid error %v\", err)\n\tassert.NotZerof(t, v, \"return value is 0 %v\", v)\n\texpected := os.Getppid()\n\tassert.Equalf(t, int32(expected), v, \"return value is %v, expected %v\", v, expected)\n}\n\nfunc TestStatus(t *testing.T) {\n\tp := testGetProcess()\n\n\tv, err := p.Status()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting status error %v\", err)\n\tassert.NotEmptyf(t, v, \"could not get state\")\n\tif v[0] != Running && v[0] != Sleep {\n\t\tt.Errorf(\"got wrong state, %v\", v)\n\t}\n}\n\nfunc TestTerminal(t *testing.T) {\n\tp := testGetProcess()\n\n\t_, err := p.Terminal()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\tassert.NoErrorf(t, err, \"getting terminal error %v\", err)\n}\n\nfunc TestIOCounters(t *testing.T) {\n\tp := testGetProcess()\n\n\tv, err := p.IOCounters()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting iocounter error %v\", err)\n\tempty := &IOCountersStat{}\n\tassert.NotSamef(t, v, empty, \"error %v\", v)\n}\n\nfunc TestNumCtx(t *testing.T) {\n\tp := testGetProcess()\n\n\t_, err := p.NumCtxSwitches()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\tassert.NoErrorf(t, err, \"getting numctx error %v\", err)\n}\n\nfunc TestNice(t *testing.T) {\n\tp := testGetProcess()\n\n\t// https://github.com/shirou/gopsutil/issues/1532\n\tif os.Getenv(\"CI\") == \"true\" && runtime.GOOS == \"darwin\" {\n\t\tt.Skip(\"Skip CI\")\n\t}\n\n\tn, err := p.Nice()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting nice error %v\", err)\n\tif runtime.GOOS != \"windows\" && n != 0 && n != 20 && n != 8 {\n\t\tt.Errorf(\"invalid nice: %d\", n)\n\t}\n}\n\nfunc TestGroups(t *testing.T) {\n\tp := testGetProcess()\n\n\tv, err := p.Groups()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting groups error %v\", err)\n\tif len(v) == 0 {\n\t\tt.Skip(\"Groups is empty\")\n\t}\n}\n\nfunc TestNumThread(t *testing.T) {\n\tp := testGetProcess()\n\n\tn, err := p.NumThreads()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting NumThread error %v\", err)\n\tassert.GreaterOrEqualf(t, n, int32(0), \"invalid NumThread: %d\", n)\n}\n\nfunc TestThreads(t *testing.T) {\n\tp := testGetProcess()\n\n\tn, err := p.NumThreads()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting NumThread error %v\", err)\n\tassert.GreaterOrEqualf(t, n, int32(0), \"invalid NumThread: %d\", n)\n\n\tts, err := p.Threads()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting Threads error %v\", err)\n\tassert.Equalf(t, len(ts), int(n), \"unexpected number of threads: %v vs %v\", len(ts), n)\n}\n\nfunc TestName(t *testing.T) {\n\tp := testGetProcess()\n\n\tn, err := p.Name()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting name error %v\", err)\n\tassert.Containsf(t, n, \"process.test\", \"invalid Name %s\", n)\n}\n\n// #nosec G204\nfunc TestLong_Name_With_Spaces(t *testing.T) {\n\ttmpdir, err := os.MkdirTemp(\"\", \"\")\n\trequire.NoErrorf(t, err, \"unable to create temp dir %v\", err)\n\tdefer os.RemoveAll(tmpdir) // clean up\n\ttmpfilepath := filepath.Join(tmpdir, \"loooong name with spaces.go\")\n\ttmpfile, err := os.Create(tmpfilepath)\n\trequire.NoErrorf(t, err, \"unable to create temp file %v\", err)\n\n\ttmpfilecontent := []byte(\"package main\\nimport(\\n\\\"time\\\"\\n)\\nfunc main(){\\nfor range time.Tick(time.Second) {}\\n}\")\n\tif _, err := tmpfile.Write(tmpfilecontent); err != nil {\n\t\ttmpfile.Close()\n\t\tt.Fatalf(\"unable to write temp file %v\", err)\n\t}\n\trequire.NoErrorf(t, tmpfile.Close(), \"unable to close temp file\")\n\tctx := context.Background()\n\n\terr = exec.CommandContext(ctx, \"go\", \"build\", \"-o\", tmpfile.Name()+\".exe\", tmpfile.Name()).Run()\n\trequire.NoErrorf(t, err, \"unable to build temp file %v\", err)\n\n\tcmd := exec.CommandContext(ctx, tmpfile.Name()+\".exe\")\n\trequire.NoError(t, cmd.Start())\n\ttime.Sleep(100 * time.Millisecond)\n\tp, err := NewProcess(int32(cmd.Process.Pid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tn, err := p.Name()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting name error %v\", err)\n\tbasename := filepath.Base(tmpfile.Name() + \".exe\")\n\trequire.Equalf(t, basename, n, \"%s != %s\", basename, n)\n\tcmd.Process.Kill()\n}\n\n// #nosec G204\nfunc TestLong_Name(t *testing.T) {\n\ttmpdir, err := os.MkdirTemp(\"\", \"\")\n\trequire.NoErrorf(t, err, \"unable to create temp dir %v\", err)\n\tdefer os.RemoveAll(tmpdir) // clean up\n\ttmpfilepath := filepath.Join(tmpdir, \"looooooooooooooooooooong.go\")\n\ttmpfile, err := os.Create(tmpfilepath)\n\trequire.NoErrorf(t, err, \"unable to create temp file %v\", err)\n\n\ttmpfilecontent := []byte(\"package main\\nimport(\\n\\\"time\\\"\\n)\\nfunc main(){\\nfor range time.Tick(time.Second) {}\\n}\")\n\tif _, err := tmpfile.Write(tmpfilecontent); err != nil {\n\t\ttmpfile.Close()\n\t\tt.Fatalf(\"unable to write temp file %v\", err)\n\t}\n\trequire.NoErrorf(t, tmpfile.Close(), \"unable to close temp file\")\n\tctx := context.Background()\n\n\terr = exec.CommandContext(ctx, \"go\", \"build\", \"-o\", tmpfile.Name()+\".exe\", tmpfile.Name()).Run()\n\trequire.NoErrorf(t, err, \"unable to build temp file %v\", err)\n\n\tcmd := exec.CommandContext(ctx, tmpfile.Name()+\".exe\")\n\trequire.NoError(t, cmd.Start())\n\ttime.Sleep(100 * time.Millisecond)\n\tp, err := NewProcess(int32(cmd.Process.Pid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tn, err := p.Name()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting name error %v\", err)\n\tbasename := filepath.Base(tmpfile.Name() + \".exe\")\n\trequire.Equalf(t, basename, n, \"%s != %s\", basename, n)\n\tcmd.Process.Kill()\n}\n\nfunc TestName_Against_Python(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"only applies to posix\")\n\t}\n\tpy3Path, err := exec.LookPath(\"python3\")\n\tif err != nil {\n\t\tt.Skipf(\"python3 not found: %s\", err)\n\t}\n\tctx := context.Background()\n\tif out, err := exec.CommandContext(ctx, py3Path, \"-c\", \"import psutil\").CombinedOutput(); err != nil {\n\t\tt.Skipf(\"psutil not found for %s: %s\", py3Path, out)\n\t}\n\n\ttmpdir, err := os.MkdirTemp(\"\", \"\")\n\trequire.NoErrorf(t, err, \"unable to create temp dir %v\", err)\n\tdefer os.RemoveAll(tmpdir) // clean up\n\ttmpfilepath := filepath.Join(tmpdir, \"looooooooooooooooooooong.py\")\n\ttmpfile, err := os.Create(tmpfilepath)\n\trequire.NoErrorf(t, err, \"unable to create temp file %v\", err)\n\ttmpfilecontent := []byte(\"#!\" + py3Path + \"\\nimport psutil, time\\nprint(psutil.Process().name(), flush=True)\\nwhile True:\\n\\ttime.sleep(1)\")\n\tif _, err := tmpfile.Write(tmpfilecontent); err != nil {\n\t\ttmpfile.Close()\n\t\tt.Fatalf(\"unable to write temp file %v\", err)\n\t}\n\trequire.NoErrorf(t, tmpfile.Chmod(0o744), \"unable to chmod u+x temp file\")\n\trequire.NoErrorf(t, tmpfile.Close(), \"unable to close temp file\")\n\tcmd := exec.CommandContext(ctx, tmpfilepath)\n\toutPipe, _ := cmd.StdoutPipe()\n\tscanner := bufio.NewScanner(outPipe)\n\tcmd.Start()\n\tdefer cmd.Process.Kill()\n\tscanner.Scan()\n\tpyName := scanner.Text() // first line printed by py3 script, its name\n\tt.Logf(\"pyName %s\", pyName)\n\tp, err := NewProcess(int32(cmd.Process.Pid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting process error %v\", err)\n\tname, err := p.Name()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting name error %v\", err)\n\trequire.Equalf(t, pyName, name, \"psutil and gopsutil process.Name() results differ: expected %s, got %s\", pyName, name)\n}\n\nfunc TestExe(t *testing.T) {\n\tp := testGetProcess()\n\n\tn, err := p.Exe()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting Exe error %v\", err)\n\tassert.Containsf(t, n, \"process.test\", \"invalid Exe %s\", n)\n}\n\nfunc TestCpuPercent(t *testing.T) {\n\tp := testGetProcess()\n\t_, err := p.Percent(0)\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tduration := time.Duration(1000) * time.Microsecond\n\ttime.Sleep(duration)\n\tpercent, err := p.Percent(0)\n\trequire.NoError(t, err)\n\n\tnumcpu := runtime.NumCPU()\n\t//\tif percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO\n\trequire.GreaterOrEqualf(t, percent, 0.0, \"CPUPercent value is invalid: %f, %d\", percent, numcpu)\n}\n\nfunc TestCpuPercentLoop(t *testing.T) {\n\tp := testGetProcess()\n\tnumcpu := runtime.NumCPU()\n\n\tfor i := 0; i < 2; i++ {\n\t\tduration := time.Duration(100) * time.Microsecond\n\t\tpercent, err := p.Percent(duration)\n\t\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\t\tt.Skip(\"not implemented\")\n\t\t}\n\t\trequire.NoError(t, err)\n\t\t//\tif percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO\n\t\trequire.GreaterOrEqualf(t, percent, 0.0, \"CPUPercent value is invalid: %f, %d\", percent, numcpu)\n\t}\n}\n\nfunc TestCreateTime(t *testing.T) {\n\tif os.Getenv(\"CI\") == \"true\" {\n\t\tt.Skip(\"Skip CI\")\n\t}\n\n\tp := testGetProcess()\n\n\tc, err := p.CreateTime()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tassert.GreaterOrEqualf(t, c, int64(1420000000), \"process created time is wrong.\")\n\n\tgotElapsed := time.Since(time.Unix(int64(c/1000), 0))\n\tmaxElapsed := time.Duration(20 * time.Second)\n\n\tassert.Lessf(t, gotElapsed, maxElapsed, \"this process has not been running for %v\", gotElapsed)\n}\n\nfunc TestParent(t *testing.T) {\n\tp := testGetProcess()\n\n\tc, err := p.Parent()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\trequire.NotNilf(t, c, \"could not get parent\")\n\trequire.NotZerof(t, c.Pid, \"wrong parent pid\")\n}\n\nfunc TestConnections(t *testing.T) {\n\tp := testGetProcess()\n\tctx := context.Background()\n\n\taddr, err := net.ResolveTCPAddr(\"tcp\", \"localhost:0\") // dynamically get a random open port from OS\n\trequire.NoErrorf(t, err, \"unable to resolve localhost: %v\", err)\n\tl, err := net.ListenTCP(addr.Network(), addr)\n\trequire.NoErrorf(t, err, \"unable to listen on %v: %v\", addr, err)\n\tdefer l.Close()\n\n\ttcpServerAddr := l.Addr().String()\n\ttcpServerAddrIP := strings.Split(tcpServerAddr, \":\")[0]\n\ttcpServerAddrPort, err := strconv.ParseUint(strings.Split(tcpServerAddr, \":\")[1], 10, 32)\n\trequire.NoErrorf(t, err, \"unable to parse tcpServerAddr port: %v\", err)\n\n\tserverEstablished := make(chan struct{})\n\tgo func() { // TCP listening goroutine\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tdefer conn.Close()\n\n\t\tserverEstablished <- struct{}{}\n\t\t_, err = io.ReadAll(conn)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}()\n\td := &net.Dialer{}\n\tconn, err := d.DialContext(ctx, \"tcp\", tcpServerAddr)\n\trequire.NoErrorf(t, err, \"unable to dial %v: %v\", tcpServerAddr, err)\n\tdefer conn.Close()\n\n\t// Rarely the call to net.Dial returns before the server connection is\n\t// established. Wait so that the test doesn't fail.\n\t<-serverEstablished\n\n\tc, err := p.Connections()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\trequire.NotEmptyf(t, c, \"no connections found\")\n\n\tserverConnections := 0\n\tfor _, connection := range c {\n\t\tif connection.Laddr.IP == tcpServerAddrIP && uint64(connection.Laddr.Port) == tcpServerAddrPort && connection.Raddr.Port != 0 {\n\t\t\trequire.Equalf(t, \"ESTABLISHED\", connection.Status, \"expected server connection to be ESTABLISHED, have %+v\", connection)\n\t\t\tserverConnections++\n\t\t}\n\t}\n\n\tclientConnections := 0\n\tfor _, connection := range c {\n\t\tif connection.Raddr.IP == tcpServerAddrIP && uint64(connection.Raddr.Port) == tcpServerAddrPort {\n\t\t\trequire.Equalf(t, \"ESTABLISHED\", connection.Status, \"expected client connection to be ESTABLISHED, have %+v\", connection)\n\t\t\tclientConnections++\n\t\t}\n\t}\n\t// two established connections, one for the server, the other for the client\n\trequire.Equalf(t, 1, serverConnections, \"expected 1 server connection, have %d.\\nDetails: %+v\", serverConnections, c)\n\t// two established connections, one for the server, the other for the client\n\trequire.Equalf(t, 1, clientConnections, \"expected 1 server connection, have %d.\\nDetails: %+v\", clientConnections, c)\n}\n\nfunc TestChildren(t *testing.T) {\n\tp := testGetProcess()\n\tctx := context.Background()\n\n\tvar cmd *exec.Cmd\n\tif runtime.GOOS == \"windows\" {\n\t\tcmd = exec.CommandContext(ctx, \"ping\", \"localhost\", \"-n\", \"4\")\n\t} else {\n\t\tcmd = exec.CommandContext(ctx, \"sleep\", \"3\")\n\t}\n\trequire.NoError(t, cmd.Start())\n\ttime.Sleep(100 * time.Millisecond)\n\n\tc, err := p.Children()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\trequire.NotEmptyf(t, c, \"children is empty\")\n\tfound := false\n\tfor _, child := range c {\n\t\tif child.Pid == int32(cmd.Process.Pid) {\n\t\t\tfound = true\n\t\t\tbreak\n\t\t}\n\t}\n\tassert.Truef(t, found, \"could not find child %d\", cmd.Process.Pid)\n}\n\nfunc TestUsername(t *testing.T) {\n\tmyPid := os.Getpid()\n\tcurrentUser, _ := user.Current()\n\tmyUsername := currentUser.Username\n\n\tprocess, _ := NewProcess(int32(myPid))\n\tpidUsername, err := process.Username()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\tassert.Equal(t, myUsername, pidUsername)\n\n\tt.Log(pidUsername)\n}\n\nfunc TestCPUTimes(t *testing.T) {\n\tpid := os.Getpid()\n\tprocess, err := NewProcess(int32(pid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tspinSeconds := 0.2\n\tcpuTimes0, err := process.Times()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\t// Spin for a duration of spinSeconds\n\tt0 := time.Now()\n\ttGoal := t0.Add(time.Duration(spinSeconds*1000) * time.Millisecond)\n\trequire.NoError(t, err)\n\tfor time.Now().Before(tGoal) {\n\t\t// This block intentionally left blank\n\t}\n\n\tcpuTimes1, err := process.Times()\n\trequire.NoError(t, err)\n\n\tif cpuTimes0 == nil || cpuTimes1 == nil {\n\t\tt.FailNow()\n\t}\n\tmeasuredElapsed := cpuTimes1.Total() - cpuTimes0.Total()\n\tmessage := fmt.Sprintf(\"Measured %fs != spun time of %fs\\ncpuTimes0=%v\\ncpuTimes1=%v\",\n\t\tmeasuredElapsed, spinSeconds, cpuTimes0, cpuTimes1)\n\tassert.Greaterf(t, measuredElapsed, float64(spinSeconds)/5, message)\n\tassert.Lessf(t, measuredElapsed, float64(spinSeconds)*5, message)\n}\n\nfunc TestOpenFiles(t *testing.T) {\n\tfp, err := os.Open(\"process_test.go\")\n\trequire.NoError(t, err)\n\tdefer func() {\n\t\tassert.NoError(t, fp.Close())\n\t}()\n\n\tpid := os.Getpid()\n\tp, err := NewProcess(int32(pid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tv, err := p.OpenFiles()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmpty(t, v) // test always open files.\n\n\tfor _, vv := range v {\n\t\tassert.NotEmpty(t, vv.Path)\n\t}\n}\n\nfunc TestKill(t *testing.T) {\n\tctx := context.Background()\n\tvar cmd *exec.Cmd\n\tif runtime.GOOS == \"windows\" {\n\t\tcmd = exec.CommandContext(ctx, \"ping\", \"localhost\", \"-n\", \"4\")\n\t} else {\n\t\tcmd = exec.CommandContext(ctx, \"sleep\", \"3\")\n\t}\n\trequire.NoError(t, cmd.Start())\n\ttime.Sleep(100 * time.Millisecond)\n\tp, err := NewProcess(int32(cmd.Process.Pid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\terr = p.Kill()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tcmd.Wait()\n}\n\nfunc TestIsRunning(t *testing.T) {\n\tctx := context.Background()\n\tvar cmd *exec.Cmd\n\tif runtime.GOOS == \"windows\" {\n\t\tcmd = exec.CommandContext(ctx, \"ping\", \"localhost\", \"-n\", \"2\")\n\t} else {\n\t\tcmd = exec.CommandContext(ctx, \"sleep\", \"1\")\n\t}\n\tcmd.Start()\n\tp, err := NewProcess(int32(cmd.Process.Pid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\trunning, err := p.IsRunning()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"IsRunning error: %v\", err)\n\trequire.Truef(t, running, \"process should be found running\")\n\tcmd.Wait()\n\trunning, err = p.IsRunning()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"IsRunning error: %v\", err)\n\trequire.Falsef(t, running, \"process should NOT be found running\")\n}\n\n// #nosec G204\nfunc TestEnviron(t *testing.T) {\n\ttmpdir, err := os.MkdirTemp(\"\", \"\")\n\trequire.NoErrorf(t, err, \"unable to create temp dir %v\", err)\n\tdefer os.RemoveAll(tmpdir) // clean up\n\ttmpfilepath := filepath.Join(tmpdir, \"test.go\")\n\ttmpfile, err := os.Create(tmpfilepath)\n\trequire.NoErrorf(t, err, \"unable to create temp file %v\", err)\n\n\ttmpfilecontent := []byte(\"package main\\nimport(\\n\\\"time\\\"\\n)\\nfunc main(){\\nfor range time.Tick(time.Second) {}\\n}\")\n\tif _, err := tmpfile.Write(tmpfilecontent); err != nil {\n\t\ttmpfile.Close()\n\t\tt.Fatalf(\"unable to write temp file %v\", err)\n\t}\n\trequire.NoErrorf(t, tmpfile.Close(), \"unable to close temp file\")\n\tctx := context.Background()\n\n\terr = exec.CommandContext(ctx, \"go\", \"build\", \"-o\", tmpfile.Name()+\".exe\", tmpfile.Name()).Run()\n\trequire.NoErrorf(t, err, \"unable to build temp file %v\", err)\n\n\tcmd := exec.CommandContext(ctx, tmpfile.Name()+\".exe\")\n\tcmd.Env = []string{\"testkey=envvalue\"}\n\n\trequire.NoError(t, cmd.Start())\n\tdefer cmd.Process.Kill()\n\ttime.Sleep(100 * time.Millisecond)\n\tp, err := NewProcess(int32(cmd.Process.Pid))\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\n\tenvs, err := p.Environ()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting environ error %v\", err)\n\tvar envvarFound bool\n\tif slices.Contains(envs, \"testkey=envvalue\") {\n\t\tenvvarFound = true\n\t}\n\tassert.Truef(t, envvarFound, \"environment variable not found\")\n}\n\nfunc TestCwd(t *testing.T) {\n\tmyPid := os.Getpid()\n\tcurrentWorkingDirectory, _ := os.Getwd()\n\n\tprocess, _ := NewProcess(int32(myPid))\n\tpidCwd, err := process.Cwd()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoErrorf(t, err, \"getting cwd error %v\", err)\n\tpidCwd = strings.TrimSuffix(pidCwd, string(os.PathSeparator))\n\tassert.Equal(t, currentWorkingDirectory, pidCwd)\n\n\tt.Log(pidCwd)\n}\n\nfunc TestConcurrent(t *testing.T) {\n\tconst goroutines int = 5\n\tvar wg sync.WaitGroup\n\tfor range goroutines {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tp, err := NewProcess(int32(os.Getpid()))\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"NewProcess failed: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t_, err = p.Times()\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"process.Times failed: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}()\n\t}\n\twg.Wait()\n}\n\nfunc BenchmarkNewProcess(b *testing.B) {\n\tcheckPid := os.Getpid()\n\tfor i := 0; i < b.N; i++ {\n\t\tNewProcess(int32(checkPid))\n\t}\n}\n\nfunc BenchmarkProcessName(b *testing.B) {\n\tp := testGetProcess()\n\tfor i := 0; i < b.N; i++ {\n\t\tp.Name()\n\t}\n}\n\nfunc BenchmarkProcessPpid(b *testing.B) {\n\tp := testGetProcess()\n\tfor i := 0; i < b.N; i++ {\n\t\tp.Ppid()\n\t}\n}\n\nfunc BenchmarkProcesses(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tps, err := Processes()\n\t\trequire.NoError(b, err)\n\t\trequire.NotEmpty(b, ps)\n\t}\n}\n"
  },
  {
    "path": "process/process_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage process\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"syscall\"\n\t\"time\"\n\t\"unicode/utf16\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/shirou/gopsutil/v4/cpu\"\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n\t\"github.com/shirou/gopsutil/v4/net\"\n)\n\ntype Signal = syscall.Signal\n\nvar (\n\tmodntdll             = windows.NewLazySystemDLL(\"ntdll.dll\")\n\tprocNtResumeProcess  = modntdll.NewProc(\"NtResumeProcess\")\n\tprocNtSuspendProcess = modntdll.NewProc(\"NtSuspendProcess\")\n\n\tmodpsapi                     = windows.NewLazySystemDLL(\"psapi.dll\")\n\tprocGetProcessMemoryInfo     = modpsapi.NewProc(\"GetProcessMemoryInfo\")\n\tprocGetProcessImageFileNameW = modpsapi.NewProc(\"GetProcessImageFileNameW\")\n\n\tadvapi32                  = windows.NewLazySystemDLL(\"advapi32.dll\")\n\tprocLookupPrivilegeValue  = advapi32.NewProc(\"LookupPrivilegeValueW\")\n\tprocAdjustTokenPrivileges = advapi32.NewProc(\"AdjustTokenPrivileges\")\n\n\tprocQueryFullProcessImageNameW = common.Modkernel32.NewProc(\"QueryFullProcessImageNameW\")\n\tprocGetPriorityClass           = common.Modkernel32.NewProc(\"GetPriorityClass\")\n\tprocGetProcessIoCounters       = common.Modkernel32.NewProc(\"GetProcessIoCounters\")\n\tprocGetNativeSystemInfo        = common.Modkernel32.NewProc(\"GetNativeSystemInfo\")\n\tprocGetProcessHandleCount      = common.Modkernel32.NewProc(\"GetProcessHandleCount\")\n\n\tprocessorArchitecture uint\n)\n\nconst processQueryInformation = windows.PROCESS_QUERY_LIMITED_INFORMATION\n\ntype systemProcessorInformation struct {\n\tProcessorArchitecture uint16\n\tProcessorLevel        uint16\n\tProcessorRevision     uint16\n\tReserved              uint16\n\tProcessorFeatureBits  uint16\n}\n\ntype systemInfo struct {\n\twProcessorArchitecture      uint16\n\twReserved                   uint16\n\tdwpageSize                  uint32\n\tlpMinimumApplicationAddress uintptr\n\tlpMaximumApplicationAddress uintptr\n\tdwActiveProcessorMask       uintptr\n\tdwNumberOfProcessors        uint32\n\tdwProcessorType             uint32\n\tdwAllocationGranularity     uint32\n\twProcessorLevel             uint16\n\twProcessorRevision          uint16\n}\n\n// Memory_info_ex is different between OSes\ntype MemoryInfoExStat struct{}\n\ntype MemoryMapsStat struct{}\n\n// ioCounters is an equivalent representation of IO_COUNTERS in the Windows API.\n// https://docs.microsoft.com/windows/win32/api/winnt/ns-winnt-io_counters\ntype ioCounters struct {\n\tReadOperationCount  uint64\n\tWriteOperationCount uint64\n\tOtherOperationCount uint64\n\tReadTransferCount   uint64\n\tWriteTransferCount  uint64\n\tOtherTransferCount  uint64\n}\n\ntype processBasicInformation32 struct {\n\tReserved1       uint32\n\tPebBaseAddress  uint32\n\tReserved2       uint32\n\tReserved3       uint32\n\tUniqueProcessId uint32\n\tReserved4       uint32\n}\n\ntype processBasicInformation64 struct {\n\tReserved1       uint64\n\tPebBaseAddress  uint64\n\tReserved2       uint64\n\tReserved3       uint64\n\tUniqueProcessId uint64\n\tReserved4       uint64\n}\n\ntype processEnvironmentBlock32 struct {\n\tReserved1         [2]uint8\n\tBeingDebugged     uint8\n\tReserved2         uint8\n\tReserved3         [2]uint32\n\tLdr               uint32\n\tProcessParameters uint32\n\t// More fields which we don't use so far\n}\n\ntype processEnvironmentBlock64 struct {\n\tReserved1         [2]uint8\n\tBeingDebugged     uint8\n\tReserved2         uint8\n\t_                 [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)\n\tReserved3         [2]uint64\n\tLdr               uint64\n\tProcessParameters uint64\n\t// More fields which we don't use so far\n}\n\ntype rtlUserProcessParameters32 struct {\n\tReserved1                      [16]uint8\n\tConsoleHandle                  uint32\n\tConsoleFlags                   uint32\n\tStdInputHandle                 uint32\n\tStdOutputHandle                uint32\n\tStdErrorHandle                 uint32\n\tCurrentDirectoryPathNameLength uint16\n\t_                              uint16 // Max Length\n\tCurrentDirectoryPathAddress    uint32\n\tCurrentDirectoryHandle         uint32\n\tDllPathNameLength              uint16\n\t_                              uint16 // Max Length\n\tDllPathAddress                 uint32\n\tImagePathNameLength            uint16\n\t_                              uint16 // Max Length\n\tImagePathAddress               uint32\n\tCommandLineLength              uint16\n\t_                              uint16 // Max Length\n\tCommandLineAddress             uint32\n\tEnvironmentAddress             uint32\n\t// More fields which we don't use so far\n}\n\ntype rtlUserProcessParameters64 struct {\n\tReserved1                      [16]uint8\n\tConsoleHandle                  uint64\n\tConsoleFlags                   uint64\n\tStdInputHandle                 uint64\n\tStdOutputHandle                uint64\n\tStdErrorHandle                 uint64\n\tCurrentDirectoryPathNameLength uint16\n\t_                              uint16 // Max Length\n\t_                              uint32 // Padding\n\tCurrentDirectoryPathAddress    uint64\n\tCurrentDirectoryHandle         uint64\n\tDllPathNameLength              uint16\n\t_                              uint16 // Max Length\n\t_                              uint32 // Padding\n\tDllPathAddress                 uint64\n\tImagePathNameLength            uint16\n\t_                              uint16 // Max Length\n\t_                              uint32 // Padding\n\tImagePathAddress               uint64\n\tCommandLineLength              uint16\n\t_                              uint16 // Max Length\n\t_                              uint32 // Padding\n\tCommandLineAddress             uint64\n\tEnvironmentAddress             uint64\n\t// More fields which we don't use so far\n}\n\ntype winLUID struct {\n\tLowPart  winDWord\n\tHighPart winLong\n}\n\n// LUID_AND_ATTRIBUTES\ntype winLUIDAndAttributes struct {\n\tLuid       winLUID\n\tAttributes winDWord\n}\n\n// TOKEN_PRIVILEGES\ntype winTokenPrivileges struct {\n\tPrivilegeCount winDWord\n\tPrivileges     [1]winLUIDAndAttributes\n}\n\ntype (\n\twinLong  int32\n\twinDWord uint32\n)\n\nfunc init() {\n\tvar sInfo systemInfo\n\n\tprocGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sInfo)))\n\tprocessorArchitecture = uint(sInfo.wProcessorArchitecture)\n\n\t// enable SeDebugPrivilege https://github.com/midstar/proci/blob/6ec79f57b90ba3d9efa2a7b16ef9c9369d4be875/proci_windows.go#L80-L119\n\thandle, err := syscall.GetCurrentProcess()\n\tif err != nil {\n\t\treturn\n\t}\n\n\tvar token syscall.Token\n\terr = syscall.OpenProcessToken(handle, 0x0028, &token)\n\tif err != nil {\n\t\treturn\n\t}\n\tdefer token.Close()\n\n\ttokenPrivileges := winTokenPrivileges{PrivilegeCount: 1}\n\tlpName := syscall.StringToUTF16(\"SeDebugPrivilege\")\n\tret, _, _ := procLookupPrivilegeValue.Call(\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&lpName[0])),\n\t\tuintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0].Luid)))\n\tif ret == 0 {\n\t\treturn\n\t}\n\n\ttokenPrivileges.Privileges[0].Attributes = 0x00000002 // SE_PRIVILEGE_ENABLED\n\n\tprocAdjustTokenPrivileges.Call(\n\t\tuintptr(token),\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&tokenPrivileges)),\n\t\tuintptr(unsafe.Sizeof(tokenPrivileges)),\n\t\t0,\n\t\t0)\n}\n\nfunc pidsWithContext(_ context.Context) ([]int32, error) {\n\t// inspired by https://gist.github.com/henkman/3083408\n\t// and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329\n\tvar ret []int32\n\tvar read uint32\n\tvar psSize uint32 = 1024\n\tconst dwordSize uint32 = 4\n\n\tfor {\n\t\tps := make([]uint32, psSize)\n\t\tif err := windows.EnumProcesses(ps, &read); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif uint32(len(ps)) == read/dwordSize { // ps buffer was too small to host every results, retry with a bigger one\n\t\t\tpsSize += 1024\n\t\t\tcontinue\n\t\t}\n\t\tfor _, pid := range ps[:read/dwordSize] {\n\t\t\tret = append(ret, int32(pid))\n\t\t}\n\t\treturn ret, nil\n\n\t}\n}\n\nfunc PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {\n\tif pid == 0 { // special case for pid 0 System Idle Process\n\t\treturn true, nil\n\t}\n\tif pid < 0 {\n\t\treturn false, fmt.Errorf(\"invalid pid %v\", pid)\n\t}\n\tif pid%4 != 0 {\n\t\t// OpenProcess will succeed even on non-existing pid here https://devblogs.microsoft.com/oldnewthing/20080606-00/?p=22043\n\t\t// so we list every pid just to be sure and be future-proof\n\t\tpids, err := PidsWithContext(ctx)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tfor _, i := range pids {\n\t\t\tif i == pid {\n\t\t\t\treturn true, err\n\t\t\t}\n\t\t}\n\t\treturn false, err\n\t}\n\th, err := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid))\n\tif errors.Is(err, windows.ERROR_ACCESS_DENIED) {\n\t\treturn true, nil\n\t}\n\tif errors.Is(err, windows.ERROR_INVALID_PARAMETER) {\n\t\treturn false, nil\n\t}\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tdefer windows.CloseHandle(h)\n\tevent, err := windows.WaitForSingleObject(h, 0)\n\treturn event == uint32(windows.WAIT_TIMEOUT), err\n}\n\nfunc (p *Process) PpidWithContext(_ context.Context) (int32, error) {\n\t// if cached already, return from cache\n\tcachedPpid := p.getPpid()\n\tif cachedPpid != 0 {\n\t\treturn cachedPpid, nil\n\t}\n\n\tppid, _, _, err := getFromSnapProcess(p.Pid)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// no errors and not cached already, so cache it\n\tp.setPpid(ppid)\n\n\treturn ppid, nil\n}\n\nfunc (p *Process) NameWithContext(ctx context.Context) (string, error) {\n\tif p.Pid == 0 {\n\t\treturn \"System Idle Process\", nil\n\t}\n\tif p.Pid == 4 {\n\t\treturn \"System\", nil\n\t}\n\n\texe, err := p.ExeWithContext(ctx)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not get Name: %w\", err)\n\t}\n\n\treturn filepath.Base(exe), nil\n}\n\nfunc (*Process) TgidWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (p *Process) ExeWithContext(_ context.Context) (string, error) {\n\tc, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer windows.CloseHandle(c)\n\tbuf := make([]uint16, syscall.MAX_LONG_PATH)\n\tsize := uint32(syscall.MAX_LONG_PATH)\n\tif err := procQueryFullProcessImageNameW.Find(); err == nil { // Vista+\n\t\tret, _, err := procQueryFullProcessImageNameW.Call(\n\t\t\tuintptr(c),\n\t\t\tuintptr(0),\n\t\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t\t\tuintptr(unsafe.Pointer(&size)))\n\t\tif ret == 0 {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn windows.UTF16ToString(buf), nil\n\t}\n\t// XP fallback\n\tret, _, err := procGetProcessImageFileNameW.Call(uintptr(c), uintptr(unsafe.Pointer(&buf[0])), uintptr(size))\n\tif ret == 0 {\n\t\treturn \"\", err\n\t}\n\treturn common.ConvertDOSPath(windows.UTF16ToString(buf)), nil\n}\n\nfunc (p *Process) CmdlineWithContext(_ context.Context) (string, error) {\n\tcmdline, err := getProcessCommandLine(p.Pid)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not get CommandLine: %w\", err)\n\t}\n\treturn cmdline, nil\n}\n\nfunc (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {\n\tcmdline, err := p.CmdlineWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn parseCmdline(cmdline)\n}\n\nfunc parseCmdline(cmdline string) ([]string, error) {\n\tcmdlineptr, err := windows.UTF16PtrFromString(cmdline)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar argc int32\n\targvptr, err := windows.CommandLineToArgv(cmdlineptr, &argc)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argvptr))))\n\n\targv := make([]string, argc)\n\tfor i, v := range (*argvptr)[:argc] {\n\t\targv[i] = windows.UTF16ToString((*v)[:])\n\t}\n\treturn argv, nil\n}\n\nfunc (p *Process) createTimeWithContext(_ context.Context) (int64, error) {\n\tru, err := getRusage(p.Pid)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"could not get CreationDate: %w\", err)\n\t}\n\n\treturn ru.CreationTime.Nanoseconds() / 1000000, nil\n}\n\nfunc (p *Process) CwdWithContext(_ context.Context) (string, error) {\n\th, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid))\n\tif errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {\n\t\treturn \"\", nil\n\t}\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer syscall.CloseHandle(syscall.Handle(h))\n\n\tprocIs32Bits := is32BitProcess(h)\n\n\tif procIs32Bits {\n\t\tuserProcParams, err := getUserProcessParams32(h)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif userProcParams.CurrentDirectoryPathNameLength > 0 {\n\t\t\tcwd := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CurrentDirectoryPathAddress), uint(userProcParams.CurrentDirectoryPathNameLength))\n\t\t\tif len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {\n\t\t\t\treturn \"\", errors.New(\"cannot read current working directory\")\n\t\t\t}\n\n\t\t\treturn convertUTF16ToString(cwd), nil\n\t\t}\n\t} else {\n\t\tuserProcParams, err := getUserProcessParams64(h)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif userProcParams.CurrentDirectoryPathNameLength > 0 {\n\t\t\tcwd := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CurrentDirectoryPathAddress, uint(userProcParams.CurrentDirectoryPathNameLength))\n\t\t\tif len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {\n\t\t\t\treturn \"\", errors.New(\"cannot read current working directory\")\n\t\t\t}\n\n\t\t\treturn convertUTF16ToString(cwd), nil\n\t\t}\n\t}\n\n\t// if we reach here, we have no cwd\n\treturn \"\", nil\n}\n\nfunc (*Process) StatusWithContext(_ context.Context) ([]string, error) {\n\treturn []string{\"\"}, common.ErrNotImplementedError\n}\n\nfunc (*Process) ForegroundWithContext(_ context.Context) (bool, error) {\n\treturn false, common.ErrNotImplementedError\n}\n\nfunc (p *Process) UsernameWithContext(_ context.Context) (string, error) {\n\tpid := p.Pid\n\tc, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer windows.CloseHandle(c)\n\n\tvar token syscall.Token\n\terr = syscall.OpenProcessToken(syscall.Handle(c), syscall.TOKEN_QUERY, &token)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer token.Close()\n\ttokenUser, err := token.GetTokenUser()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tuser, domain, _, err := tokenUser.User.Sid.LookupAccount(\"\")\n\treturn domain + \"\\\\\" + user, err\n}\n\nfunc (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) TerminalWithContext(_ context.Context) (string, error) {\n\treturn \"\", common.ErrNotImplementedError\n}\n\n// priorityClasses maps a win32 priority class to its WMI equivalent Win32_Process.Priority\n// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getpriorityclass\n// https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process\nvar priorityClasses = map[int]int32{\n\t0x00008000: 10, // ABOVE_NORMAL_PRIORITY_CLASS\n\t0x00004000: 6,  // BELOW_NORMAL_PRIORITY_CLASS\n\t0x00000080: 13, // HIGH_PRIORITY_CLASS\n\t0x00000040: 4,  // IDLE_PRIORITY_CLASS\n\t0x00000020: 8,  // NORMAL_PRIORITY_CLASS\n\t0x00000100: 24, // REALTIME_PRIORITY_CLASS\n}\n\nfunc (p *Process) NiceWithContext(_ context.Context) (int32, error) {\n\tc, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer windows.CloseHandle(c)\n\tret, _, err := procGetPriorityClass.Call(uintptr(c))\n\tif ret == 0 {\n\t\treturn 0, err\n\t}\n\tpriority, ok := priorityClasses[int(ret)]\n\tif !ok {\n\t\treturn 0, fmt.Errorf(\"unknown priority class %v\", ret)\n\t}\n\treturn priority, nil\n}\n\nfunc (*Process) IOniceWithContext(_ context.Context) (int32, error) {\n\treturn 0, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (p *Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {\n\tc, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer windows.CloseHandle(c)\n\tvar counters ioCounters\n\tret, _, err := procGetProcessIoCounters.Call(uintptr(c), uintptr(unsafe.Pointer(&counters)))\n\tif ret == 0 {\n\t\treturn nil, err\n\t}\n\tstats := &IOCountersStat{\n\t\tReadCount:  counters.ReadOperationCount,\n\t\tReadBytes:  counters.ReadTransferCount,\n\t\tWriteCount: counters.WriteOperationCount,\n\t\tWriteBytes: counters.WriteTransferCount,\n\t}\n\n\treturn stats, nil\n}\n\nfunc (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\n// NumFDsWithContext returns the number of handles for a process on Windows,\n// not the number of file descriptors (FDs).\nfunc (p *Process) NumFDsWithContext(_ context.Context) (int32, error) {\n\thandle, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdefer windows.CloseHandle(handle)\n\n\tvar handleCount uint32\n\tret, _, err := procGetProcessHandleCount.Call(uintptr(handle), uintptr(unsafe.Pointer(&handleCount)))\n\tif ret == 0 {\n\t\treturn 0, err\n\t}\n\treturn int32(handleCount), nil\n}\n\nfunc (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) {\n\tppid, ret, _, err := getFromSnapProcess(p.Pid)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// if no errors and not cached already, cache ppid\n\tp.parent = ppid\n\tif p.getPpid() == 0 {\n\t\tp.setPpid(ppid)\n\t}\n\n\treturn ret, nil\n}\n\nfunc (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {\n\tsysTimes, err := getProcessCPUTimes(p.Pid)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// User and kernel times are represented as a FILETIME structure\n\t// which contains a 64-bit value representing the number of\n\t// 100-nanosecond intervals since January 1, 1601 (UTC):\n\t// http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx\n\t// To convert it into a float representing the seconds that the\n\t// process has executed in user/kernel mode I borrowed the code\n\t// below from psutil's _psutil_windows.c, and in turn from Python's\n\t// Modules/posixmodule.c\n\n\tuser := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7\n\tkernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7\n\n\treturn &cpu.TimesStat{\n\t\tUser:   user,\n\t\tSystem: kernel,\n\t}, nil\n}\n\nfunc (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {\n\tmem, err := getMemoryInfo(p.Pid)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := &MemoryInfoStat{\n\t\tRSS: uint64(mem.WorkingSetSize),\n\t\tVMS: uint64(mem.PagefileUsage),\n\t}\n\n\treturn ret, nil\n}\n\nfunc (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (p *Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {\n\tmem, err := getMemoryInfo(p.Pid)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := &PageFaultsStat{\n\t\t// Since Windows does not distinguish between Major and Minor faults, all faults are treated as Major\n\t\tMajorFaults: uint64(mem.PageFaultCount),\n\t}\n\n\treturn ret, nil\n}\n\nfunc (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {\n\tout := []*Process{}\n\tsnap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(0))\n\tif err != nil {\n\t\treturn out, err\n\t}\n\tdefer windows.CloseHandle(snap)\n\tvar pe32 windows.ProcessEntry32\n\tpe32.Size = uint32(unsafe.Sizeof(pe32))\n\tif err := windows.Process32First(snap, &pe32); err != nil {\n\t\treturn out, err\n\t}\n\tfor {\n\t\tif pe32.ParentProcessID == uint32(p.Pid) {\n\t\t\tp, err := NewProcessWithContext(ctx, int32(pe32.ProcessID))\n\t\t\tif err == nil {\n\t\t\t\tout = append(out, p)\n\t\t\t}\n\t\t}\n\t\tif err = windows.Process32Next(snap, &pe32); err != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn out, nil\n}\n\nfunc (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {\n\tfiles := make([]OpenFilesStat, 0)\n\tfileExists := make(map[string]bool)\n\n\tprocess, err := windows.OpenProcess(common.ProcessQueryInformation, false, uint32(p.Pid))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer windows.CloseHandle(process)\n\n\tbuffer := make([]byte, 1024)\n\tvar size uint32\n\n\tst := common.CallWithExpandingBuffer(\n\t\tfunc() common.NtStatus {\n\t\t\treturn common.NtQuerySystemInformation(\n\t\t\t\tcommon.SystemExtendedHandleInformationClass,\n\t\t\t\t&buffer[0],\n\t\t\t\tuint32(len(buffer)),\n\t\t\t\t&size,\n\t\t\t)\n\t\t},\n\t\t&buffer,\n\t\t&size,\n\t)\n\tif st.IsError() {\n\t\treturn nil, st.Error()\n\t}\n\n\thandlesList := (*common.SystemExtendedHandleInformation)(unsafe.Pointer(&buffer[0]))\n\thandles := make([]common.SystemExtendedHandleTableEntryInformation, int(handlesList.NumberOfHandles))\n\thdr := (*reflect.SliceHeader)(unsafe.Pointer(&handles))\n\thdr.Data = uintptr(unsafe.Pointer(&handlesList.Handles[0]))\n\n\tcurrentProcess, err := windows.GetCurrentProcess()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, handle := range handles {\n\t\tvar file uintptr\n\t\tif int32(handle.UniqueProcessId) != p.Pid {\n\t\t\tcontinue\n\t\t}\n\t\tif windows.DuplicateHandle(process, windows.Handle(handle.HandleValue), currentProcess, (*windows.Handle)(&file),\n\t\t\t0, true, windows.DUPLICATE_SAME_ACCESS) != nil {\n\t\t\tcontinue\n\t\t}\n\t\t// release the new handle\n\t\tdefer windows.CloseHandle(windows.Handle(file))\n\n\t\tfileType, err := windows.GetFileType(windows.Handle(file))\n\t\tif err != nil || fileType != windows.FILE_TYPE_DISK {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar fileName string\n\t\tch := make(chan struct{}, 1)\n\n\t\tgo func() {\n\t\t\tdefer close(ch)\n\t\t\tvar buf [syscall.MAX_LONG_PATH]uint16\n\t\t\tn, err := windows.GetFinalPathNameByHandle(windows.Handle(file), &buf[0], syscall.MAX_LONG_PATH, 0)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfileName = string(utf16.Decode(buf[:n]))\n\t\t\tch <- struct{}{}\n\t\t}()\n\n\t\tselect {\n\t\tcase <-time.NewTimer(100 * time.Millisecond).C:\n\t\t\tcontinue\n\t\tcase <-ch:\n\t\t\tfileInfo, err := os.Stat(fileName)\n\t\t\tif err != nil || fileInfo.IsDir() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, exists := fileExists[fileName]; !exists {\n\t\t\t\tfiles = append(files, OpenFilesStat{\n\t\t\t\t\tPath: fileName,\n\t\t\t\t\tFd:   uint64(file),\n\t\t\t\t})\n\t\t\t\tfileExists[fileName] = true\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn files, ctx.Err()\n\t\t}\n\t}\n\n\treturn files, nil\n}\n\nfunc (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {\n\treturn net.ConnectionsPidWithContext(ctx, \"all\", p.Pid)\n}\n\nfunc (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {\n\treturn nil, common.ErrNotImplementedError\n}\n\nfunc (*Process) SendSignalWithContext(_ context.Context, _ syscall.Signal) error {\n\treturn common.ErrNotImplementedError\n}\n\nfunc (p *Process) SuspendWithContext(_ context.Context) error {\n\tc, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer windows.CloseHandle(c)\n\n\tr1, _, _ := procNtSuspendProcess.Call(uintptr(c))\n\tif r1 != 0 {\n\t\t// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55\n\t\treturn fmt.Errorf(\"NtStatus='0x%.8X'\", r1)\n\t}\n\n\treturn nil\n}\n\nfunc (p *Process) ResumeWithContext(_ context.Context) error {\n\tc, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer windows.CloseHandle(c)\n\n\tr1, _, _ := procNtResumeProcess.Call(uintptr(c))\n\tif r1 != 0 {\n\t\t// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55\n\t\treturn fmt.Errorf(\"NtStatus='0x%.8X'\", r1)\n\t}\n\n\treturn nil\n}\n\nfunc (p *Process) TerminateWithContext(_ context.Context) error {\n\tproc, err := windows.OpenProcess(windows.PROCESS_TERMINATE, false, uint32(p.Pid))\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = windows.TerminateProcess(proc, 0)\n\twindows.CloseHandle(proc)\n\treturn err\n}\n\nfunc (p *Process) KillWithContext(_ context.Context) error {\n\tprocess, err := os.FindProcess(int(p.Pid))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer process.Release()\n\treturn process.Kill()\n}\n\nfunc (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {\n\tenvVars, err := getProcessEnvironmentVariables(ctx, p.Pid)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get environment variables: %w\", err)\n\t}\n\treturn envVars, nil\n}\n\n// retrieve Ppid in a thread-safe manner\nfunc (p *Process) getPpid() int32 {\n\tp.parentMutex.RLock()\n\tdefer p.parentMutex.RUnlock()\n\treturn p.parent\n}\n\n// cache Ppid in a thread-safe manner (WINDOWS ONLY)\n// see https://psutil.readthedocs.io/en/latest/#psutil.Process.ppid\nfunc (p *Process) setPpid(ppid int32) {\n\tp.parentMutex.Lock()\n\tdefer p.parentMutex.Unlock()\n\tp.parent = ppid\n}\n\nfunc getFromSnapProcess(pid int32) (int32, int32, string, error) { //nolint:unparam //FIXME\n\tsnap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid))\n\tif err != nil {\n\t\treturn 0, 0, \"\", err\n\t}\n\tdefer windows.CloseHandle(snap)\n\tvar pe32 windows.ProcessEntry32\n\tpe32.Size = uint32(unsafe.Sizeof(pe32))\n\terr = windows.Process32First(snap, &pe32)\n\tif err != nil {\n\t\treturn 0, 0, \"\", err\n\t}\n\tfor {\n\t\tif pe32.ProcessID == uint32(pid) {\n\t\t\tszexe := windows.UTF16ToString(pe32.ExeFile[:])\n\t\t\treturn int32(pe32.ParentProcessID), int32(pe32.Threads), szexe, nil\n\t\t}\n\t\tif err = windows.Process32Next(snap, &pe32); err != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn 0, 0, \"\", fmt.Errorf(\"couldn't find pid: %d\", pid)\n}\n\nfunc ProcessesWithContext(ctx context.Context) ([]*Process, error) {\n\tout := []*Process{}\n\n\tpids, err := PidsWithContext(ctx)\n\tif err != nil {\n\t\treturn out, fmt.Errorf(\"could not get Processes %w\", err)\n\t}\n\n\tfor _, pid := range pids {\n\t\tp, err := NewProcessWithContext(ctx, pid)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tout = append(out, p)\n\t}\n\n\treturn out, nil\n}\n\nfunc getRusage(pid int32) (*windows.Rusage, error) {\n\tvar CPU windows.Rusage\n\n\tc, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer windows.CloseHandle(c)\n\n\tif err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &CPU, nil\n}\n\nfunc getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {\n\tvar mem PROCESS_MEMORY_COUNTERS\n\tc, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))\n\tif err != nil {\n\t\treturn mem, err\n\t}\n\tdefer windows.CloseHandle(c)\n\tif err := getProcessMemoryInfo(c, &mem); err != nil {\n\t\treturn mem, err\n\t}\n\n\treturn mem, err\n}\n\nfunc getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {\n\tr1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))\n\tif r1 == 0 {\n\t\tif e1 != 0 {\n\t\t\terr = error(e1)\n\t\t} else {\n\t\t\terr = syscall.EINVAL\n\t\t}\n\t}\n\treturn err\n}\n\ntype SYSTEM_TIMES struct { //nolint:revive //FIXME\n\tCreateTime syscall.Filetime\n\tExitTime   syscall.Filetime\n\tKernelTime syscall.Filetime\n\tUserTime   syscall.Filetime\n}\n\nfunc getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {\n\tvar times SYSTEM_TIMES\n\n\th, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))\n\tif err != nil {\n\t\treturn times, err\n\t}\n\tdefer windows.CloseHandle(h)\n\n\terr = syscall.GetProcessTimes(\n\t\tsyscall.Handle(h),\n\t\t&times.CreateTime,\n\t\t&times.ExitTime,\n\t\t&times.KernelTime,\n\t\t&times.UserTime,\n\t)\n\n\treturn times, err\n}\n\nfunc getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32, error) {\n\tpebAddress, err := queryPebAddress(syscall.Handle(handle), true)\n\tif err != nil {\n\t\treturn rtlUserProcessParameters32{}, fmt.Errorf(\"cannot locate process PEB: %w\", err)\n\t}\n\n\tbuf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{})))\n\tif len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) {\n\t\treturn rtlUserProcessParameters32{}, errors.New(\"cannot read process PEB\")\n\t}\n\tpeb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0]))\n\tuserProcessAddress := uint64(peb.ProcessParameters)\n\tbuf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{})))\n\tif len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) {\n\t\treturn rtlUserProcessParameters32{}, errors.New(\"cannot read user process parameters\")\n\t}\n\treturn *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil\n}\n\nfunc getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64, error) {\n\tpebAddress, err := queryPebAddress(syscall.Handle(handle), false)\n\tif err != nil {\n\t\treturn rtlUserProcessParameters64{}, fmt.Errorf(\"cannot locate process PEB: %w\", err)\n\t}\n\n\tbuf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{})))\n\tif len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) {\n\t\treturn rtlUserProcessParameters64{}, errors.New(\"cannot read process PEB\")\n\t}\n\tpeb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0]))\n\tuserProcessAddress := peb.ProcessParameters\n\tbuf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{})))\n\tif len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) {\n\t\treturn rtlUserProcessParameters64{}, errors.New(\"cannot read user process parameters\")\n\t}\n\treturn *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil\n}\n\nfunc is32BitProcess(h windows.Handle) bool {\n\tconst (\n\t\tPROCESSOR_ARCHITECTURE_INTEL = 0\n\t\tPROCESSOR_ARCHITECTURE_ARM   = 5\n\t\tPROCESSOR_ARCHITECTURE_ARM64 = 12\n\t\tPROCESSOR_ARCHITECTURE_IA64  = 6\n\t\tPROCESSOR_ARCHITECTURE_AMD64 = 9\n\t)\n\n\tvar procIs32Bits bool\n\tswitch processorArchitecture {\n\tcase PROCESSOR_ARCHITECTURE_INTEL, PROCESSOR_ARCHITECTURE_ARM:\n\t\tprocIs32Bits = true\n\tcase PROCESSOR_ARCHITECTURE_ARM64, PROCESSOR_ARCHITECTURE_IA64, PROCESSOR_ARCHITECTURE_AMD64:\n\t\tvar wow64 uint\n\n\t\tret, _, _ := common.ProcNtQueryInformationProcess.Call(\n\t\t\tuintptr(h),\n\t\t\tuintptr(common.ProcessWow64Information),\n\t\t\tuintptr(unsafe.Pointer(&wow64)),\n\t\t\tuintptr(unsafe.Sizeof(wow64)),\n\t\t\tuintptr(0),\n\t\t)\n\t\tif int(ret) >= 0 {\n\t\t\tif wow64 != 0 {\n\t\t\t\tprocIs32Bits = true\n\t\t\t}\n\t\t} else {\n\t\t\t// if the OS does not support the call, we fallback into the bitness of the app\n\t\t\tif unsafe.Sizeof(wow64) == 4 {\n\t\t\t\tprocIs32Bits = true\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\t// for other unknown platforms, we rely on process platform\n\t\tif unsafe.Sizeof(processorArchitecture) == 8 {\n\t\t\tprocIs32Bits = false\n\t\t} else {\n\t\t\tprocIs32Bits = true\n\t\t}\n\t}\n\treturn procIs32Bits\n}\n\nfunc getProcessEnvironmentVariables(ctx context.Context, pid int32) ([]string, error) {\n\th, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))\n\tif errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {\n\t\treturn nil, nil\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer syscall.CloseHandle(syscall.Handle(h))\n\n\tprocIs32Bits := is32BitProcess(h)\n\n\tvar processParameterBlockAddress uint64\n\n\tif procIs32Bits {\n\t\tpeb, err := getUserProcessParams32(h)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tprocessParameterBlockAddress = uint64(peb.EnvironmentAddress)\n\t} else {\n\t\tpeb, err := getUserProcessParams64(h)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tprocessParameterBlockAddress = peb.EnvironmentAddress\n\t}\n\tenvvarScanner := bufio.NewScanner(&processReader{\n\t\tprocessHandle:  h,\n\t\tis32BitProcess: procIs32Bits,\n\t\toffset:         processParameterBlockAddress,\n\t})\n\tenvvarScanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {\n\t\tif atEOF && len(data) == 0 {\n\t\t\treturn 0, nil, nil\n\t\t}\n\t\t// Check for UTF-16 zero character\n\t\tfor i := 0; i < len(data)-1; i += 2 {\n\t\t\tif data[i] == 0 && data[i+1] == 0 {\n\t\t\t\treturn i + 2, data[0:i], nil\n\t\t\t}\n\t\t}\n\t\tif atEOF {\n\t\t\treturn len(data), data, nil\n\t\t}\n\t\t// Request more data\n\t\treturn 0, nil, nil\n\t})\n\tvar envVars []string\n\tfor envvarScanner.Scan() {\n\t\tentry := envvarScanner.Bytes()\n\t\tif len(entry) == 0 {\n\t\t\tbreak // Block is finished\n\t\t}\n\t\tenvVars = append(envVars, convertUTF16ToString(entry))\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tbreak\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t}\n\tif err := envvarScanner.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn envVars, nil\n}\n\ntype processReader struct {\n\tprocessHandle  windows.Handle\n\tis32BitProcess bool\n\toffset         uint64\n}\n\nfunc (p *processReader) Read(buf []byte) (int, error) {\n\tprocessMemory := readProcessMemory(syscall.Handle(p.processHandle), p.is32BitProcess, p.offset, uint(len(buf)))\n\tif len(processMemory) == 0 {\n\t\treturn 0, io.EOF\n\t}\n\tcopy(buf, processMemory)\n\tp.offset += uint64(len(processMemory))\n\treturn len(processMemory), nil\n}\n\nfunc getProcessCommandLine(pid int32) (string, error) {\n\th, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))\n\tif errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {\n\t\treturn \"\", nil\n\t}\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer syscall.CloseHandle(syscall.Handle(h))\n\n\tprocIs32Bits := is32BitProcess(h)\n\n\tif procIs32Bits {\n\t\tuserProcParams, err := getUserProcessParams32(h)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif userProcParams.CommandLineLength > 0 {\n\t\t\tcmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CommandLineAddress), uint(userProcParams.CommandLineLength))\n\t\t\tif len(cmdLine) != int(userProcParams.CommandLineLength) {\n\t\t\t\treturn \"\", errors.New(\"cannot read cmdline\")\n\t\t\t}\n\n\t\t\treturn convertUTF16ToString(cmdLine), nil\n\t\t}\n\t} else {\n\t\tuserProcParams, err := getUserProcessParams64(h)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif userProcParams.CommandLineLength > 0 {\n\t\t\tcmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength))\n\t\t\tif len(cmdLine) != int(userProcParams.CommandLineLength) {\n\t\t\t\treturn \"\", errors.New(\"cannot read cmdline\")\n\t\t\t}\n\n\t\t\treturn convertUTF16ToString(cmdLine), nil\n\t\t}\n\t}\n\n\t// if we reach here, we have no command line\n\treturn \"\", nil\n}\n\nfunc convertUTF16ToString(src []byte) string {\n\tsrcLen := len(src) / 2\n\n\tcodePoints := make([]uint16, srcLen)\n\n\tsrcIdx := 0\n\tfor i := 0; i < srcLen; i++ {\n\t\tcodePoints[i] = uint16(src[srcIdx]) | uint16(src[srcIdx+1])<<8\n\t\tsrcIdx += 2\n\t}\n\treturn syscall.UTF16ToString(codePoints)\n}\n"
  },
  {
    "path": "process/process_windows_32bit.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build (windows && 386) || (windows && arm)\n\npackage process\n\nimport (\n\t\"errors\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\ntype PROCESS_MEMORY_COUNTERS struct { //nolint:revive //FIXME\n\tCB                         uint32\n\tPageFaultCount             uint32\n\tPeakWorkingSetSize         uint32\n\tWorkingSetSize             uint32\n\tQuotaPeakPagedPoolUsage    uint32\n\tQuotaPagedPoolUsage        uint32\n\tQuotaPeakNonPagedPoolUsage uint32\n\tQuotaNonPagedPoolUsage     uint32\n\tPagefileUsage              uint32\n\tPeakPagefileUsage          uint32\n}\n\nfunc queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) {\n\tif is32BitProcess {\n\t\t// we are on a 32-bit process reading an external 32-bit process\n\t\tvar info processBasicInformation32\n\n\t\tret, _, _ := common.ProcNtQueryInformationProcess.Call(\n\t\t\tuintptr(procHandle),\n\t\t\tuintptr(common.ProcessBasicInformation),\n\t\t\tuintptr(unsafe.Pointer(&info)),\n\t\t\tuintptr(unsafe.Sizeof(info)),\n\t\t\tuintptr(0),\n\t\t)\n\t\tif status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {\n\t\t\treturn uint64(info.PebBaseAddress), nil\n\t\t}\n\t\treturn 0, windows.NTStatus(ret)\n\t}\n\t// we are on a 32-bit process reading an external 64-bit process\n\tif common.ProcNtWow64QueryInformationProcess64.Find() != nil {\n\t\treturn 0, errors.New(\"can't find API to query 64 bit process from 32 bit\")\n\t}\n\t// avoid panic\n\tvar info processBasicInformation64\n\n\tret, _, _ := common.ProcNtWow64QueryInformationProcess64.Call(\n\t\tuintptr(procHandle),\n\t\tuintptr(common.ProcessBasicInformation),\n\t\tuintptr(unsafe.Pointer(&info)),\n\t\tuintptr(unsafe.Sizeof(info)),\n\t\tuintptr(0),\n\t)\n\tif status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {\n\t\treturn info.PebBaseAddress, nil\n\t}\n\treturn 0, windows.NTStatus(ret)\n}\n\nfunc readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, size uint) []byte {\n\tif is32BitProcess {\n\t\tvar read uint\n\n\t\tbuffer := make([]byte, size)\n\n\t\tret, _, _ := common.ProcNtReadVirtualMemory.Call(\n\t\t\tuintptr(h),\n\t\t\tuintptr(address),\n\t\t\tuintptr(unsafe.Pointer(&buffer[0])),\n\t\t\tuintptr(size),\n\t\t\tuintptr(unsafe.Pointer(&read)),\n\t\t)\n\t\tif int(ret) >= 0 && read > 0 {\n\t\t\treturn buffer[:read]\n\t\t}\n\t\t// reading a 64-bit process from a 32-bit one\n\t} else if common.ProcNtWow64ReadVirtualMemory64.Find() == nil { // avoid panic\n\t\tvar read uint64\n\n\t\tbuffer := make([]byte, size)\n\n\t\tret, _, _ := common.ProcNtWow64ReadVirtualMemory64.Call(\n\t\t\tuintptr(h),\n\t\t\tuintptr(address&0xFFFFFFFF), // the call expects a 64-bit value\n\t\t\tuintptr(address>>32),\n\t\t\tuintptr(unsafe.Pointer(&buffer[0])),\n\t\t\tuintptr(size), // the call expects a 64-bit value\n\t\t\tuintptr(0),    // but size is 32-bit so pass zero as the high dword\n\t\t\tuintptr(unsafe.Pointer(&read)),\n\t\t)\n\t\tif int(ret) >= 0 && read > 0 {\n\t\t\treturn buffer[:uint(read)]\n\t\t}\n\t}\n\n\t// if we reach here, an error happened\n\treturn nil\n}\n"
  },
  {
    "path": "process/process_windows_64bit.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build (windows && amd64) || (windows && arm64)\n\npackage process\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\ntype PROCESS_MEMORY_COUNTERS struct { //nolint:revive //FIXME\n\tCB                         uint32\n\tPageFaultCount             uint32\n\tPeakWorkingSetSize         uint64\n\tWorkingSetSize             uint64\n\tQuotaPeakPagedPoolUsage    uint64\n\tQuotaPagedPoolUsage        uint64\n\tQuotaPeakNonPagedPoolUsage uint64\n\tQuotaNonPagedPoolUsage     uint64\n\tPagefileUsage              uint64\n\tPeakPagefileUsage          uint64\n}\n\nfunc queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) {\n\tif is32BitProcess {\n\t\t// we are on a 64-bit process reading an external 32-bit process\n\t\tvar wow64 uint\n\n\t\tret, _, _ := common.ProcNtQueryInformationProcess.Call(\n\t\t\tuintptr(procHandle),\n\t\t\tuintptr(common.ProcessWow64Information),\n\t\t\tuintptr(unsafe.Pointer(&wow64)),\n\t\t\tuintptr(unsafe.Sizeof(wow64)),\n\t\t\tuintptr(0),\n\t\t)\n\t\tif status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {\n\t\t\treturn uint64(wow64), nil\n\t\t}\n\t\treturn 0, windows.NTStatus(ret)\n\t}\n\t// we are on a 64-bit process reading an external 64-bit process\n\tvar info processBasicInformation64\n\n\tret, _, _ := common.ProcNtQueryInformationProcess.Call(\n\t\tuintptr(procHandle),\n\t\tuintptr(common.ProcessBasicInformation),\n\t\tuintptr(unsafe.Pointer(&info)),\n\t\tuintptr(unsafe.Sizeof(info)),\n\t\tuintptr(0),\n\t)\n\tif status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {\n\t\treturn info.PebBaseAddress, nil\n\t}\n\treturn 0, windows.NTStatus(ret)\n}\n\nfunc readProcessMemory(procHandle syscall.Handle, _ bool, address uint64, size uint) []byte {\n\tvar read uint\n\n\tbuffer := make([]byte, size)\n\n\tret, _, _ := common.ProcNtReadVirtualMemory.Call(\n\t\tuintptr(procHandle),\n\t\tuintptr(address),\n\t\tuintptr(unsafe.Pointer(&buffer[0])),\n\t\tuintptr(size),\n\t\tuintptr(unsafe.Pointer(&read)),\n\t)\n\tif int(ret) >= 0 && read > 0 {\n\t\treturn buffer[:read]\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "process/testdata/linux/1/comm",
    "content": "ksoftirqd/0\n"
  },
  {
    "path": "process/testdata/linux/1/smaps",
    "content": "ffffb5ecc000-ffffb5ece000 r--p 00000000 00:00 0        [vvar]\nRss:                   0 kB\nKernelPageSize:        4 kB\nSize:                  1 kB\nShared_Clean:          3 kB\nShared_Dirty:          4 kB\nPrivate_Clean:         5 kB\nPrivate_Dirty:         6 kB\nReferenced:            7 kB\nAnonymous:             8 kB\nSwap:                  9 kB\nffffb5eca000-ffffb5ecc000 rw-p 00000000 00:00 0\nRss:                   0 kB\nSize:                  1 kB\nPss:                   2 kB\nShared_Clean:          3 kB\nShared_Dirty:          4 kB\nPrivate_Dirty:         6 kB\nLazyFree:              0 kB\nReferenced:            7 kB\nAnonymous:             8 kB\nSwap:                  9 kB\nffffb5ece000-ffffb5ecf000 r-xp 00000000 00:00 0        [vdso]\nRss:                   0 kB\nSize:                  1 kB\nPss:                   2 kB\nShared_Clean:          3 kB\nShared_Dirty:          4 kB\nPrivate_Clean:         5 kB\nPrivate_Hugetlb:       0 kB\nReferenced:            7 kB\nAnonymous:             8 kB\nSwap:                  9 kB\nffffb5ecf000-ffffb5ed1000 r--p 0002a000 00:3d 2238525  /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1\nRss:                   0 kB\nSize:                  1 kB\nPss:                   2 kB\nShared_Clean:          3 kB\nShared_Dirty:          4 kB\nPrivate_Clean:         5 kB\nPrivate_Dirty:         6 kB\nReferenced:            7 kB\nTHPeligible:           0\nSwap:                  9 kB\n"
  },
  {
    "path": "process/testdata/linux/1/status",
    "content": "Name:\tksoftirqd/0\nUmask:\t0000\nState:\tS (sleeping)\nTgid:\t10\nNgid:\t0\nPid:\t10\nPPid:\t2\nTracerPid:\t0\nUid:\t0\t0\t0\t0\nGid:\t0\t0\t0\t0\nFDSize:\t64\nGroups:\t \nNStgid:\t10\nNSpid:\t10\nNSpgid:\t0\nNSsid:\t0\nThreads:\t1\nSigQ:\t0/27700\nSigPnd:\t0000000000000000\nShdPnd:\t0000000000000000\nSigBlk:\t0000000000000000\nSigIgn:\tffffffffffffffff\nSigCgt:\t0000000000000000\nCapInh:\t0000000000000000\nCapPrm:\t0000003fffffffff\nCapEff:\t0000003fffffffff\nCapBnd:\t0000003fffffffff\nCapAmb:\t0000000000000000\nNoNewPrivs:\t0\nSeccomp:\t0\nSpeculation_Store_Bypass:\tvulnerable\nCpus_allowed:\t1\nCpus_allowed_list:\t0\nMems_allowed:\t00000000,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\nMems_allowed_list:\t0\nvoluntary_ctxt_switches:\t76887\nnonvoluntary_ctxt_switches:\t1771\n"
  },
  {
    "path": "process/testdata/linux/1060/comm",
    "content": "server\n"
  },
  {
    "path": "process/testdata/linux/1060/status",
    "content": "Name:\tserver\nUmask:\t0022\nState:\tS (sleeping)\nTgid:\t2549\nNgid:\t0\nPid:\t2549\nPPid:\t1\nTracerPid:\t0\nUid:\t107\t107\t107\t107\nGid:\t113\t113\t113\t113\nFDSize:\t64\nGroups:\t113 \nVmPeak:\t  664744 kB\nVmSize:\t  664744 kB\nVmLck:\t       0 kB\nVmPin:\t       0 kB\nVmHWM:\t    2892 kB\nVmRSS:\t    2892 kB\nRssAnon:\t     524 kB\nRssFile:\t    2368 kB\nRssShmem:\t       0 kB\nVmData:\t    5932 kB\nVmStk:\t     132 kB\nVmExe:\t    1304 kB\nVmLib:\t    1180 kB\nVmPTE:\t      44 kB\nVmSwap:\t       0 kB\nCoreDumping:\t0\nTHP_enabled:\t1\nThreads:\t5\nSigQ:\t0/1823\nSigPnd:\t00000000000000000000000000000000\nShdPnd:\t00000000000000000000000000000000\nSigBlk:\t00000000000000000000000000000000\nSigIgn:\t00000000000000000000000000000000\nSigCgt:\tfffffffffffffffffffffffe783ffeff\nCapInh:\t0000000000000000\nCapPrm:\t0000000000000000\nCapEff:\t0000000000000000\nCapBnd:\t0000003fffffffff\nCapAmb:\t0000000000000000\nNoNewPrivs:\t0\nSpeculation_Store_Bypass:\tunknown\nCpus_allowed:\t3\nCpus_allowed_list:\t0-1\nvoluntary_ctxt_switches:\t3\nnonvoluntary_ctxt_switches:\t146"
  },
  {
    "path": "process/testdata/linux/23819/comm",
    "content": "pause\n"
  },
  {
    "path": "process/testdata/linux/23819/status",
    "content": "Name:\tpause\nUmask:\t0022\nState:\tS (sleeping)\nTgid:\t23819\nNgid:\t0\nPid:\t23819\nPPid:\t23783\nTracerPid:\t0\nUid:\t4061200383\t4061200383\t4061200383\t4061200383\nGid:\t4061200383\t4061200383\t4061200383\t4061200383\nFDSize:\t64\nGroups:\t4061200383 \nNStgid:\t23819\t1\nNSpid:\t23819\t1\nNSpgid:\t23819\t1\nNSsid:\t23819\t1\nKthread:\t0\nVmPeak:\t     972 kB\nVmSize:\t     972 kB\nVmLck:\t       0 kB\nVmPin:\t       0 kB\nVmHWM:\t       0 kB\nVmRSS:\t       0 kB\nRssAnon:\t       0 kB\nRssFile:\t       0 kB\nRssShmem:\t       0 kB\nVmData:\t     172 kB\nVmStk:\t     132 kB\nVmExe:\t     496 kB\nVmLib:\t       8 kB\nVmPTE:\t      32 kB\nVmSwap:\t       0 kB\nHugetlbPages:\t       0 kB\nCoreDumping:\t0\nTHP_enabled:\t1\nuntag_mask:\t0xffffffffffffffff\nThreads:\t1\nSigQ:\t0/3081260\nSigPnd:\t0000000000000000\nShdPnd:\t0000000000000000\nSigBlk:\t0000000000000000\nSigIgn:\t0000000000000000\nSigCgt:\t0000000000014002\nCapInh:\t0000000000000000\nCapPrm:\t0000000000000000\nCapEff:\t0000000000000000\nCapBnd:\t00000000a80425fb\nCapAmb:\t0000000000000000\nNoNewPrivs:\t1\nSeccomp:\t2\nSeccomp_filters:\t1\nSpeculation_Store_Bypass:\tthread vulnerable\nSpeculationIndirectBranch:\tconditional enabled\nCpus_allowed:\tffffffff,ffffffff,ffffffff\nCpus_allowed_list:\t0-95\nMems_allowed:\t00000000,00000003\nMems_allowed_list:\t0-1\nvoluntary_ctxt_switches:\t23\nnonvoluntary_ctxt_switches:\t8\n"
  },
  {
    "path": "process/testdata/linux/68927/comm",
    "content": "test(cmd).sh\n"
  },
  {
    "path": "process/testdata/linux/68927/stat",
    "content": "68927 (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\n"
  },
  {
    "path": "process/testdata/lx_brandz/1/stat",
    "content": "1 (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\n"
  },
  {
    "path": "process/types_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n// Copyright 2009 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// Hand Writing\n// - all pointer in ExternProc to uint64\n\n//go:build ignore\n\n/*\nInput to cgo -godefs.\n*/\n\n// +godefs map struct_in_addr [4]byte /* in_addr */\n// +godefs map struct_in6_addr [16]byte /* in6_addr */\n// +godefs map struct_ [16]byte /* in6_addr */\n\npackage process\n\n/*\n#define __DARWIN_UNIX03 0\n#define KERNEL\n#define _DARWIN_USE_64_BIT_INODE\n#include <stdint.h>\n#include <dirent.h>\n#include <fcntl.h>\n#include <signal.h>\n#include <termios.h>\n#include <unistd.h>\n#include <mach/mach.h>\n#include <mach/message.h>\n#include <sys/event.h>\n#include <sys/mman.h>\n#include <sys/mount.h>\n#include <sys/param.h>\n#include <sys/ptrace.h>\n#include <sys/resource.h>\n#include <sys/select.h>\n#include <sys/signal.h>\n#include <sys/socket.h>\n#include <sys/stat.h>\n#include <sys/time.h>\n#include <sys/types.h>\n#include <sys/uio.h>\n#include <sys/un.h>\n#include <net/bpf.h>\n#include <net/if_dl.h>\n#include <net/if_var.h>\n#include <net/route.h>\n#include <netinet/in.h>\n\n#include <sys/sysctl.h>\n#include <sys/ucred.h>\n#include <sys/proc.h>\n#include <sys/proc_info.h>\n#include <sys/time.h>\n#include <sys/_types/_timeval.h>\n#include <sys/appleapiopts.h>\n#include <sys/cdefs.h>\n#include <sys/param.h>\n#include <bsm/audit.h>\n#include <sys/queue.h>\n\nenum {\n\tsizeofPtr = sizeof(void*),\n};\n\nunion sockaddr_all {\n\tstruct sockaddr s1;\t// this one gets used for fields\n\tstruct sockaddr_in s2;\t// these pad it out\n\tstruct sockaddr_in6 s3;\n\tstruct sockaddr_un s4;\n\tstruct sockaddr_dl s5;\n};\n\nstruct sockaddr_any {\n\tstruct sockaddr addr;\n\tchar pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];\n};\n\nstruct ucred_queue {\n        struct ucred *tqe_next;\n        struct ucred **tqe_prev;\n        TRACEBUF\n};\n\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tsizeofPtr      = C.sizeofPtr\n\tsizeofShort    = C.sizeof_short\n\tsizeofInt      = C.sizeof_int\n\tsizeofLong     = C.sizeof_long\n\tsizeofLongLong = C.sizeof_longlong\n)\n\n// Basic types\n\ntype (\n\t_C_short     C.short\n\t_C_int       C.int\n\t_C_long      C.long\n\t_C_long_long C.longlong\n)\n\n// Time\n\ntype Timespec C.struct_timespec\n\ntype Timeval C.struct_timeval\n\n// Processes\n\ntype Rusage C.struct_rusage\n\ntype Rlimit C.struct_rlimit\n\ntype UGid_t C.gid_t\n\ntype KinfoProc C.struct_kinfo_proc\n\ntype Eproc C.struct_eproc\n\ntype Proc C.struct_proc\n\ntype Session C.struct_session\n\ntype ucred C.struct_ucred\n\ntype Uucred C.struct__ucred\n\ntype Upcred C.struct__pcred\n\ntype Vmspace C.struct_vmspace\n\ntype Sigacts C.struct_sigacts\n\ntype ExternProc C.struct_extern_proc\n\ntype Itimerval C.struct_itimerval\n\ntype Vnode C.struct_vnode\n\ntype Pgrp C.struct_pgrp\n\ntype UserStruct C.struct_user\n\ntype Au_session C.struct_au_session\n\ntype Posix_cred C.struct_posix_cred\n\ntype Label C.struct_label\n\ntype ProcTaskInfo C.struct_proc_taskinfo\n\ntype vinfoStat C.struct_vinfo_stat\n\ntype fsid C.struct_fsid\n\ntype vnodeInfo C.struct_vnode_info\n\ntype vnodeInfoPath C.struct_vnode_info_path\n\ntype vnodePathInfo C.struct_proc_vnodepathinfo\n\ntype (\n\tAuditinfoAddr C.struct_auditinfo_addr\n\tAuMask        C.struct_au_mask\n\tAuTidAddr     C.struct_au_tid_addr\n)\n\n// TAILQ(ucred)\ntype UcredQueue C.struct_ucred_queue\n"
  },
  {
    "path": "process/types_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n// We still need editing by hands.\n// go tool cgo -godefs types_freebsd.go | sed 's/\\*int64/int64/' | sed 's/\\*byte/int64/'  > process_freebsd_amd64.go\n\n/*\nInput to cgo -godefs.\n*/\n\n// +godefs map struct_pargs int64 /* pargs */\n// +godefs map struct_proc int64 /* proc */\n// +godefs map struct_user int64 /* user */\n// +godefs map struct_vnode int64 /* vnode */\n// +godefs map struct_filedesc int64 /* filedesc */\n// +godefs map struct_vmspace int64 /* vmspace */\n// +godefs map struct_pcb int64 /* pcb */\n// +godefs map struct_thread int64 /* thread */\n// +godefs map struct_pwddesc int64 /* pwddesc, not accurate */\n// +godefs map struct___sigset [16]byte /* sigset */\n\npackage process\n\n/*\n#include <sys/types.h>\n#include <sys/user.h>\n\nenum {\n\tsizeofPtr = sizeof(void*),\n};\n\n\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tCTLKern          = 1  // \"high kernel\": proc, limits\n\tKernProc         = 14 // struct: process entries\n\tKernProcPID      = 1  // by process id\n\tKernProcProc     = 8  // only return procs\n\tKernProcPathname = 12 // path to executable\n\tKernProcArgs     = 7  // get/set arguments/proctitle\n\tKernProcCwd      = 42 /* process current working directory */\n)\n\nconst (\n\tsizeofPtr      = C.sizeofPtr\n\tsizeofShort    = C.sizeof_short\n\tsizeofInt      = C.sizeof_int\n\tsizeofLong     = C.sizeof_long\n\tsizeofLongLong = C.sizeof_longlong\n)\n\nconst (\n\tsizeOfKinfoVmentry = C.sizeof_struct_kinfo_vmentry\n\tsizeOfKinfoProc    = C.sizeof_struct_kinfo_proc\n\tsizeOfKinfoFile    = C.sizeof_struct_kinfo_file\n)\n\n// from sys/proc.h\nconst (\n\tSIDL   = 1 /* Process being created by fork. */\n\tSRUN   = 2 /* Currently runnable. */\n\tSSLEEP = 3 /* Sleeping on an address. */\n\tSSTOP  = 4 /* Process debugging or suspension. */\n\tSZOMB  = 5 /* Awaiting collection by parent. */\n\tSWAIT  = 6 /* Waiting for interrupt. */\n\tSLOCK  = 7 /* Blocked on a lock. */\n)\n\n// Basic types\n\ntype (\n\t_C_short     C.short\n\t_C_int       C.int\n\t_C_long      C.long\n\t_C_long_long C.longlong\n)\n\n// Time\n\ntype Timespec C.struct_timespec\n\ntype Timeval C.struct_timeval\n\n// Processes\n\ntype Rusage C.struct_rusage\n\ntype Rlimit C.struct_rlimit\n\ntype KinfoProc C.struct_kinfo_proc\n\ntype Priority C.struct_priority\n\ntype KinfoVmentry C.struct_kinfo_vmentry\n\ntype kinfoFile C.struct_kinfo_file\n\ntype capRights C.struct_cap_rights\n"
  },
  {
    "path": "process/types_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build ignore\n\n// We still need editing by hands.\n// go tool cgo -godefs types_openbsd.go | sed 's/\\*int64/int64/' | sed 's/\\*byte/int64/'  > process_openbsd_amd64.go\n\n/*\nInput to cgo -godefs.\n*/\n\n// +godefs map struct_pargs int64 /* pargs */\n// +godefs map struct_proc int64 /* proc */\n// +godefs map struct_user int64 /* user */\n// +godefs map struct_vnode int64 /* vnode */\n// +godefs map struct_vnode int64 /* vnode */\n// +godefs map struct_filedesc int64 /* filedesc */\n// +godefs map struct_vmspace int64 /* vmspace */\n// +godefs map struct_pcb int64 /* pcb */\n// +godefs map struct_thread int64 /* thread */\n// +godefs map struct___sigset [16]byte /* sigset */\n\npackage process\n\n/*\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#include <sys/user.h>\n\nenum {\n\tsizeofPtr = sizeof(void*),\n};\n\n\n*/\nimport \"C\"\n\n// Machine characteristics; for internal use.\n\nconst (\n\tCTLKern          = 1  // \"high kernel\": proc, limits\n\tKernProc         = 66 // struct: process entries\n\tKernProcAll      = 0\n\tKernProcPID      = 1  // by process id\n\tKernProcProc     = 8  // only return procs\n\tKernProcPathname = 12 // path to executable\n\tKernProcArgs     = 55 // get/set arguments/proctitle\n\tKernProcCwd      = 78 // get current working directory\n\tKernProcArgv     = 1\n\tKernProcEnv      = 3\n)\n\nconst (\n\tArgMax = 256 * 1024 // sys/syslimits.h:#define  ARG_MAX\n)\n\nconst (\n\tsizeofPtr      = C.sizeofPtr\n\tsizeofShort    = C.sizeof_short\n\tsizeofInt      = C.sizeof_int\n\tsizeofLong     = C.sizeof_long\n\tsizeofLongLong = C.sizeof_longlong\n)\n\nconst (\n\tsizeOfKinfoVmentry = C.sizeof_struct_kinfo_vmentry\n\tsizeOfKinfoProc    = C.sizeof_struct_kinfo_proc\n)\n\n// from sys/proc.h\nconst (\n\tSIDL    = 1 /* Process being created by fork. */\n\tSRUN    = 2 /* Currently runnable. */\n\tSSLEEP  = 3 /* Sleeping on an address. */\n\tSSTOP   = 4 /* Process debugging or suspension. */\n\tSZOMB   = 5 /* Awaiting collection by parent. */\n\tSDEAD   = 6 /* Thread is almost gone */\n\tSONPROC = 7 /* Thread is currently on a CPU. */\n)\n\n// Basic types\n\ntype (\n\t_C_short     C.short\n\t_C_int       C.int\n\t_C_long      C.long\n\t_C_long_long C.longlong\n)\n\n// Time\n\ntype Timespec C.struct_timespec\n\ntype Timeval C.struct_timeval\n\n// Processes\n\ntype Rusage C.struct_rusage\n\ntype Rlimit C.struct_rlimit\n\ntype KinfoProc C.struct_kinfo_proc\n\ntype Priority C.struct_priority\n\ntype KinfoVmentry C.struct_kinfo_vmentry\n"
  },
  {
    "path": "sensors/ex_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage sensors\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// ExTemperature represents Linux dependent temperature sensor data\ntype ExTemperature struct {\n\tSensorKey string  `json:\"key\"`\n\tMin       float64 `json:\"min\"`     // Temperature min value.\n\tLowest    float64 `json:\"lowest\"`  // Historical minimum temperature\n\tHighest   float64 `json:\"highest\"` // Historical maximum temperature\n}\n\ntype ExLinux struct{}\n\nfunc NewExLinux() *ExLinux {\n\treturn &ExLinux{}\n}\n\nfunc (*ExLinux) TemperatureWithContext(ctx context.Context) ([]ExTemperature, error) {\n\tvar warns Warnings\n\n\tfiles, err := getTemperatureFiles(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get temperature files, %w\", err)\n\t}\n\n\ttemperatures := make([]ExTemperature, 0, len(files))\n\tfor _, file := range files {\n\t\tvar raw []byte\n\n\t\t// Get the base directory location\n\t\tdirectory := filepath.Dir(file)\n\n\t\t// Get the base filename prefix like temp1\n\t\tbasename := strings.Split(filepath.Base(file), \"_\")[0]\n\n\t\t// Get the base path like <dir>/temp1\n\t\tbasepath := filepath.Join(directory, basename)\n\n\t\t// Get the label of the temperature you are reading\n\t\tlabel := \"\"\n\n\t\tif raw, _ = os.ReadFile(basepath + \"_label\"); len(raw) != 0 {\n\t\t\t// Format the label from \"Core 0\" to \"core_0\"\n\t\t\tlabel = strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(raw))), \" \"), \"_\")\n\t\t}\n\n\t\t// Get the name of the temperature you are reading\n\t\tif raw, err = os.ReadFile(filepath.Join(directory, \"name\")); err != nil {\n\t\t\twarns.Add(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tname := strings.TrimSpace(string(raw))\n\n\t\tif label != \"\" {\n\t\t\tname = name + \"_\" + label\n\t\t}\n\n\t\t// Add discovered temperature sensor to the list\n\t\ttemperatures = append(temperatures, ExTemperature{\n\t\t\tSensorKey: name,\n\t\t\tMin:       optionalValueReadFromFile(basepath+\"_min\") / hostTemperatureScale,\n\t\t\tLowest:    optionalValueReadFromFile(basepath+\"_lowest\") / hostTemperatureScale,\n\t\t\tHighest:   optionalValueReadFromFile(basepath+\"_highest\") / hostTemperatureScale,\n\t\t})\n\t}\n\n\treturn temperatures, warns.Reference()\n}\n"
  },
  {
    "path": "sensors/sensors.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npackage sensors\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\ntype Warnings = common.Warnings\n\nvar invoke common.Invoker = common.Invoke{}\n\ntype TemperatureStat struct {\n\tSensorKey   string  `json:\"sensorKey\"`\n\tTemperature float64 `json:\"temperature\"`\n\tHigh        float64 `json:\"sensorHigh\"`\n\tCritical    float64 `json:\"sensorCritical\"`\n}\n\nfunc (t TemperatureStat) String() string {\n\ts, _ := json.Marshal(t)\n\treturn string(s)\n}\n\nfunc SensorsTemperatures() ([]TemperatureStat, error) {\n\treturn TemperaturesWithContext(context.Background())\n}\n"
  },
  {
    "path": "sensors/sensors_aix.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build aix\n\npackage sensors\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst (\n\thostTemperatureScale = 1000.0 // Not part of the linked file, but kept just in case it becomes relevant\n)\n\nfunc TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {\n\treturn []TemperatureStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "sensors/sensors_darwin.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin && !arm64\n\npackage sensors\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"unsafe\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {\n\tsmc, err := common.NewSMC()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer smc.Close()\n\n\ttemperatures := make([]TemperatureStat, 0, len(temperatureKeys))\n\tfor _, key := range temperatureKeys {\n\t\ttemperatures = append(temperatures, TemperatureStat{\n\t\t\tSensorKey:   key,\n\t\t\tTemperature: getTemperature(smc, key),\n\t\t})\n\t}\n\n\treturn temperatures, nil\n}\n\nvar temperatureKeys = []string{\n\t\"TA0P\", // AMBIENT_AIR_0\n\t\"TA1P\", // AMBIENT_AIR_1\n\t\"TC0D\", // CPU_0_DIODE\n\t\"TC0H\", // CPU_0_HEATSINK\n\t\"TC0P\", // CPU_0_PROXIMITY\n\t\"TB0T\", // ENCLOSURE_BASE_0\n\t\"TB1T\", // ENCLOSURE_BASE_1\n\t\"TB2T\", // ENCLOSURE_BASE_2\n\t\"TB3T\", // ENCLOSURE_BASE_3\n\t\"TG0D\", // GPU_0_DIODE\n\t\"TG0H\", // GPU_0_HEATSINK\n\t\"TG0P\", // GPU_0_PROXIMITY\n\t\"TH0P\", // HARD_DRIVE_BAY\n\t\"TM0S\", // MEMORY_SLOT_0\n\t\"TM0P\", // MEMORY_SLOTS_PROXIMITY\n\t\"TN0H\", // NORTHBRIDGE\n\t\"TN0D\", // NORTHBRIDGE_DIODE\n\t\"TN0P\", // NORTHBRIDGE_PROXIMITY\n\t\"TI0P\", // THUNDERBOLT_0\n\t\"TI1P\", // THUNDERBOLT_1\n\t\"TW0P\", // WIRELESS_MODULE\n}\n\ntype smcReturn struct {\n\tdata     [32]uint8\n\tdataType uint32\n\tdataSize uint32\n\tkSMC     uint8\n}\n\ntype smcPLimitData struct {\n\tversion   uint16\n\tlength    uint16\n\tcpuPLimit uint32\n\tgpuPLimit uint32\n\tmemPLimit uint32\n}\n\ntype smcKeyInfoData struct {\n\tdataSize       uint32\n\tdataType       uint32\n\tdataAttributes uint8\n}\n\ntype smcVersion struct {\n\tmajor    byte\n\tminor    byte\n\tbuild    byte\n\treserved byte\n\trelease  uint16\n}\n\ntype smcParamStruct struct {\n\tkey        uint32\n\tvers       smcVersion\n\tplimitData smcPLimitData\n\tkeyInfo    smcKeyInfoData\n\tresult     uint8\n\tstatus     uint8\n\tdata8      uint8\n\tdata32     uint32\n\tbytes      [32]byte\n}\n\nconst (\n\tsmcKeySize   = 4\n\tdataTypeSp78 = \"sp78\"\n)\n\nfunc getTemperature(smc *common.SMC, key string) float64 {\n\tresult, err := readSMC(smc, key)\n\tif err != nil {\n\t\treturn 0.0\n\t}\n\n\tif result.dataSize == 2 && result.dataType == toUint32(dataTypeSp78) {\n\t\treturn 0.0\n\t}\n\n\treturn float64(result.data[0])\n}\n\nfunc readSMC(smc *common.SMC, key string) (*smcReturn, error) {\n\tinput := new(smcParamStruct)\n\tresultSmc := new(smcReturn)\n\n\tinput.key = toUint32(key)\n\tinput.data8 = common.KSMCGetKeyInfo\n\n\tresult, err := callSMC(smc, input)\n\tresultSmc.kSMC = result.result\n\n\tif err != nil || result.result != common.KSMCSuccess {\n\t\treturn resultSmc, errors.New(\"ERROR: IOConnectCallStructMethod failed\")\n\t}\n\n\tresultSmc.dataSize = uint32(result.keyInfo.dataSize)\n\tresultSmc.dataType = uint32(result.keyInfo.dataType)\n\n\tinput.keyInfo.dataSize = result.keyInfo.dataSize\n\tinput.data8 = common.KSMCReadKey\n\n\tresult, err = callSMC(smc, input)\n\tresultSmc.kSMC = result.result\n\n\tif err != nil || result.result != common.KSMCSuccess {\n\t\treturn resultSmc, err\n\t}\n\n\tresultSmc.data = result.bytes\n\treturn resultSmc, nil\n}\n\nfunc callSMC(smc *common.SMC, input *smcParamStruct) (*smcParamStruct, error) {\n\toutput := new(smcParamStruct)\n\tinputCnt := unsafe.Sizeof(*input)\n\toutputCnt := unsafe.Sizeof(*output)\n\n\tresult := smc.CallStruct(common.KSMCHandleYPCEvent,\n\t\tuintptr(unsafe.Pointer(input)), inputCnt, uintptr(unsafe.Pointer(output)), &outputCnt)\n\n\tif result != 0 {\n\t\treturn output, errors.New(\"ERROR: IOConnectCallStructMethod failed\")\n\t}\n\n\treturn output, nil\n}\n\nfunc toUint32(key string) uint32 {\n\tif len(key) != smcKeySize {\n\t\treturn 0\n\t}\n\n\tvar ans uint32\n\tvar shift uint32 = 24\n\n\tfor i := 0; i < smcKeySize; i++ {\n\t\tans += uint32(key[i]) << shift\n\t\tshift -= 8\n\t}\n\n\treturn ans\n}\n"
  },
  {
    "path": "sensors/sensors_darwin_arm64.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build darwin && arm64\n\npackage sensors\n\nimport (\n\t\"context\"\n\t\"unsafe\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nconst (\n\tkHIDPageAppleVendor                  = 0xff00\n\tkHIDPageAppleVendorTemperatureSensor = 5\n)\n\nfunc ReadTemperaturesArm() []TemperatureStat {\n\ttemperatures, _ := TemperaturesWithContext(context.Background())\n\treturn temperatures\n}\n\nfunc TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {\n\tiokit, err := common.NewIOKitLib()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer iokit.Close()\n\n\tcf, err := common.NewCoreFoundationLib()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer cf.Close()\n\n\tta := &temperatureArm{\n\t\tiokit: iokit,\n\t\tcf:    cf,\n\t}\n\n\tsensors := ta.matching(kHIDPageAppleVendor, kHIDPageAppleVendorTemperatureSensor)\n\tdefer cf.CFRelease(uintptr(sensors))\n\n\t// Create HID system client\n\tsystem := iokit.IOHIDEventSystemClientCreate(common.KCFAllocatorDefault)\n\tdefer cf.CFRelease(uintptr(system))\n\n\treturn ta.getSensors(system, sensors), nil\n}\n\ntype temperatureArm struct {\n\tiokit *common.IOKitLib\n\tcf    *common.CoreFoundationLib\n}\n\nfunc (ta *temperatureArm) getSensors(system, sensors unsafe.Pointer) []TemperatureStat {\n\tta.iokit.IOHIDEventSystemClientSetMatching(uintptr(system), uintptr(sensors))\n\tmatchingsrvs := ta.iokit.IOHIDEventSystemClientCopyServices(uintptr(system))\n\n\tif matchingsrvs == nil {\n\t\treturn nil\n\t}\n\tdefer ta.cf.CFRelease(uintptr(matchingsrvs))\n\n\tstr := ta.cf.CFStringCreateWithCString(common.KCFAllocatorDefault, \"Product\", common.KCFStringEncodingUTF8)\n\tdefer ta.cf.CFRelease(uintptr(str))\n\n\tcount := ta.cf.CFArrayGetCount(uintptr(matchingsrvs))\n\tstats := make([]TemperatureStat, 0, count)\n\n\tnameSet := make(map[string]struct{})\n\tfor i := count - 1; i >= 0; i-- {\n\t\tsc := ta.cf.CFArrayGetValueAtIndex(uintptr(matchingsrvs), i)\n\t\tevent := ta.iokit.IOHIDServiceClientCopyEvent(uintptr(sc), common.KIOHIDEventTypeTemperature, 0, 0)\n\t\tif event == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\ttemp := ta.iokit.IOHIDEventGetFloatValue(uintptr(event), ioHIDEventFieldBase(common.KIOHIDEventTypeTemperature))\n\t\tta.cf.CFRelease(uintptr(event))\n\n\t\tnameRef := ta.iokit.IOHIDServiceClientCopyProperty(uintptr(sc), uintptr(str))\n\t\tif nameRef != nil {\n\t\t\tbuf := common.NewCStr(common.GetCFStringBufLengthForUTF8(ta.cf.CFStringGetLength(uintptr(nameRef))))\n\t\t\tta.cf.CFStringGetCString(uintptr(nameRef), buf, buf.Length(), common.KCFStringEncodingUTF8)\n\n\t\t\tname := buf.GoString()\n\t\t\tif _, ok := nameSet[name]; ok {\n\t\t\t\tta.cf.CFRelease(uintptr(nameRef))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tstats = append(stats, TemperatureStat{\n\t\t\t\tSensorKey:   name,\n\t\t\t\tTemperature: temp,\n\t\t\t})\n\t\t\tnameSet[name] = struct{}{}\n\t\t\tta.cf.CFRelease(uintptr(nameRef))\n\t\t}\n\t}\n\n\treturn stats\n}\n\nfunc (ta *temperatureArm) matching(page, usage int32) unsafe.Pointer {\n\tpageNum := ta.cf.CFNumberCreate(common.KCFAllocatorDefault, common.KCFNumberIntType, uintptr(unsafe.Pointer(&page)))\n\tdefer ta.cf.CFRelease(uintptr(pageNum))\n\n\tusageNum := ta.cf.CFNumberCreate(common.KCFAllocatorDefault, common.KCFNumberIntType, uintptr(unsafe.Pointer(&usage)))\n\tdefer ta.cf.CFRelease(uintptr(usageNum))\n\n\tk1 := ta.cf.CFStringCreateWithCString(common.KCFAllocatorDefault, \"PrimaryUsagePage\", common.KCFStringEncodingUTF8)\n\tk2 := ta.cf.CFStringCreateWithCString(common.KCFAllocatorDefault, \"PrimaryUsage\", common.KCFStringEncodingUTF8)\n\n\tdefer ta.cf.CFRelease(uintptr(k1))\n\tdefer ta.cf.CFRelease(uintptr(k2))\n\n\tkeys := []unsafe.Pointer{k1, k2}\n\tvalues := []unsafe.Pointer{pageNum, usageNum}\n\n\tkCFTypeDictionaryKeyCallBacks, _ := ta.cf.Dlsym(\"kCFTypeDictionaryKeyCallBacks\")\n\tkCFTypeDictionaryValueCallBacks, _ := ta.cf.Dlsym(\"kCFTypeDictionaryValueCallBacks\")\n\n\treturn ta.cf.CFDictionaryCreate(common.KCFAllocatorDefault, &keys[0], &values[0], 2,\n\t\tkCFTypeDictionaryKeyCallBacks,\n\t\tkCFTypeDictionaryValueCallBacks)\n}\n\nfunc ioHIDEventFieldBase(i int32) int32 {\n\treturn i << 16\n}\n"
  },
  {
    "path": "sensors/sensors_fallback.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows && !aix\n\npackage sensors\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {\n\treturn []TemperatureStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "sensors/sensors_freebsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build freebsd\n\npackage sensors\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {\n\treturn []TemperatureStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "sensors/sensors_linux.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build linux\n\npackage sensors\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\n// from utmp.h\nconst (\n\thostTemperatureScale = 1000.0\n)\n\nfunc TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {\n\tvar warns Warnings\n\n\tfiles, err := getTemperatureFiles(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get temperature files, %w\", err)\n\t}\n\n\tif len(files) == 0 { // handle distributions without hwmon, like raspbian #391, parse legacy thermal_zone files\n\t\tfiles, err = filepath.Glob(common.HostSysWithContext(ctx, \"/class/thermal/thermal_zone*/\"))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttemperatures := make([]TemperatureStat, 0, len(files))\n\n\t\tfor _, file := range files {\n\t\t\t// Get the name of the temperature you are reading\n\t\t\tname, err := os.ReadFile(filepath.Join(file, \"type\"))\n\t\t\tif err != nil {\n\t\t\t\twarns.Add(err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Get the temperature reading\n\t\t\tcurrent, err := os.ReadFile(filepath.Join(file, \"temp\"))\n\t\t\tif err != nil {\n\t\t\t\twarns.Add(err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttemperature, err := strconv.ParseInt(strings.TrimSpace(string(current)), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\twarns.Add(err)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttemperatures = append(temperatures, TemperatureStat{\n\t\t\t\tSensorKey:   strings.TrimSpace(string(name)),\n\t\t\t\tTemperature: float64(temperature) / 1000.0,\n\t\t\t})\n\t\t}\n\t\treturn temperatures, warns.Reference()\n\t}\n\n\ttemperatures := make([]TemperatureStat, 0, len(files))\n\n\t// example directory\n\t// device/           temp1_crit_alarm  temp2_crit_alarm  temp3_crit_alarm  temp4_crit_alarm  temp5_crit_alarm  temp6_crit_alarm  temp7_crit_alarm\n\t// name              temp1_input       temp2_input       temp3_input       temp4_input       temp5_input       temp6_input       temp7_input\n\t// power/            temp1_label       temp2_label       temp3_label       temp4_label       temp5_label       temp6_label       temp7_label\n\t// subsystem/        temp1_max         temp2_max         temp3_max         temp4_max         temp5_max         temp6_max         temp7_max\n\t// temp1_crit        temp2_crit        temp3_crit        temp4_crit        temp5_crit        temp6_crit        temp7_crit        uevent\n\tfor _, file := range files {\n\t\tvar raw []byte\n\n\t\tvar temperature float64\n\n\t\t// Get the base directory location\n\t\tdirectory := filepath.Dir(file)\n\n\t\t// Get the base filename prefix like temp1\n\t\tbasename := strings.Split(filepath.Base(file), \"_\")[0]\n\n\t\t// Get the base path like <dir>/temp1\n\t\tbasepath := filepath.Join(directory, basename)\n\n\t\t// Get the label of the temperature you are reading\n\t\tlabel := \"\"\n\n\t\tif raw, _ = os.ReadFile(basepath + \"_label\"); len(raw) != 0 {\n\t\t\t// Format the label from \"Core 0\" to \"core_0\"\n\t\t\tlabel = strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(raw))), \" \"), \"_\")\n\t\t}\n\n\t\t// Get the name of the temperature you are reading\n\t\tif raw, err = os.ReadFile(filepath.Join(directory, \"name\")); err != nil {\n\t\t\twarns.Add(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tname := strings.TrimSpace(string(raw))\n\n\t\tif label != \"\" {\n\t\t\tname = name + \"_\" + label\n\t\t}\n\n\t\t// Get the temperature reading\n\t\tif raw, err = os.ReadFile(file); err != nil {\n\t\t\twarns.Add(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif temperature, err = strconv.ParseFloat(strings.TrimSpace(string(raw)), 64); err != nil {\n\t\t\twarns.Add(err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Add discovered temperature sensor to the list\n\t\ttemperatures = append(temperatures, TemperatureStat{\n\t\t\tSensorKey:   name,\n\t\t\tTemperature: temperature / hostTemperatureScale,\n\t\t\tHigh:        optionalValueReadFromFile(basepath+\"_max\") / hostTemperatureScale,\n\t\t\tCritical:    optionalValueReadFromFile(basepath+\"_crit\") / hostTemperatureScale,\n\t\t})\n\t}\n\n\treturn temperatures, warns.Reference()\n}\n\nfunc getTemperatureFiles(ctx context.Context) ([]string, error) {\n\tvar files []string\n\tvar err error\n\n\t// Only the temp*_input file provides current temperature\n\t// value in millidegree Celsius as reported by the temperature to the device:\n\t// https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface\n\tif files, err = filepath.Glob(common.HostSysWithContext(ctx, \"/class/hwmon/hwmon*/temp*_input\")); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(files) == 0 {\n\t\t// CentOS has an intermediate /device directory:\n\t\t// https://github.com/giampaolo/psutil/issues/971\n\t\tif files, err = filepath.Glob(common.HostSysWithContext(ctx, \"/class/hwmon/hwmon*/device/temp*_input\")); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn files, nil\n}\n\nfunc optionalValueReadFromFile(filename string) float64 {\n\tvar raw []byte\n\n\tvar err error\n\n\tvar value float64\n\n\t// Check if file exists\n\tif _, err := os.Stat(filename); os.IsNotExist(err) {\n\t\treturn 0\n\t}\n\n\tif raw, err = os.ReadFile(filename); err != nil {\n\t\treturn 0\n\t}\n\n\tif value, err = strconv.ParseFloat(strings.TrimSpace(string(raw)), 64); err != nil {\n\t\treturn 0\n\t}\n\n\treturn value\n}\n"
  },
  {
    "path": "sensors/sensors_netbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build netbsd\n\npackage sensors\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {\n\treturn []TemperatureStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "sensors/sensors_openbsd.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build openbsd\n\npackage sensors\n\nimport (\n\t\"context\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {\n\treturn []TemperatureStat{}, common.ErrNotImplementedError\n}\n"
  },
  {
    "path": "sensors/sensors_solaris.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build solaris\n\npackage sensors\n\nimport (\n\t\"context\"\n\t\"encoding/csv\"\n\t\"errors\"\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {\n\tvar ret []TemperatureStat\n\n\tout, err := invoke.CommandWithContext(ctx, \"ipmitool\", \"-c\", \"sdr\", \"list\")\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\tr := csv.NewReader(strings.NewReader(string(out)))\n\t// Output may contain errors, e.g. \"bmc_send_cmd: Permission denied\", don't expect a consistent number of records\n\tr.FieldsPerRecord = -1\n\tfor {\n\t\trecord, err := r.Read()\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\t// CPU1 Temp,40,degrees C,ok\n\t\tif len(record) < 3 || record[1] == \"\" || record[2] != \"degrees C\" {\n\t\t\tcontinue\n\t\t}\n\t\tv, err := strconv.ParseFloat(record[1], 64)\n\t\tif err != nil {\n\t\t\treturn ret, err\n\t\t}\n\t\tts := TemperatureStat{\n\t\t\tSensorKey:   strings.TrimSuffix(record[0], \" Temp\"),\n\t\t\tTemperature: v,\n\t\t}\n\t\tret = append(ret, ts)\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "sensors/sensors_test.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npackage sensors\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\nfunc TestTemperatureStat_String(t *testing.T) {\n\tv := TemperatureStat{\n\t\tSensorKey:   \"CPU\",\n\t\tTemperature: 1.1,\n\t\tHigh:        30.1,\n\t\tCritical:    0.1,\n\t}\n\ts := `{\"sensorKey\":\"CPU\",\"temperature\":1.1,\"sensorHigh\":30.1,\"sensorCritical\":0.1}`\n\tassert.Equalf(t, s, v.String(), \"TemperatureStat string is invalid, %v\", v.String())\n}\n\nfunc TestTemperatures(t *testing.T) {\n\tif os.Getenv(\"CI\") != \"\" {\n\t\tt.Skip(\"Skip CI\")\n\t}\n\tv, err := SensorsTemperatures()\n\tif errors.Is(err, common.ErrNotImplementedError) {\n\t\tt.Skip(\"not implemented\")\n\t}\n\trequire.NoError(t, err)\n\tassert.NotEmptyf(t, v, \"Could not get temperature %v\", v)\n\tt.Log(v)\n}\n"
  },
  {
    "path": "sensors/sensors_windows.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage sensors\n\nimport (\n\t\"context\"\n\n\t\"github.com/yusufpapurcu/wmi\"\n\n\t\"github.com/shirou/gopsutil/v4/internal/common\"\n)\n\ntype msAcpi_ThermalZoneTemperature struct { //nolint:revive //FIXME\n\tActive             bool\n\tCriticalTripPoint  uint32\n\tCurrentTemperature uint32\n\tInstanceName       string\n}\n\nfunc TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {\n\tvar ret []TemperatureStat\n\tvar dst []msAcpi_ThermalZoneTemperature\n\tq := wmi.CreateQuery(&dst, \"\")\n\tif err := common.WMIQueryWithContext(ctx, q, &dst, nil, \"root/wmi\"); err != nil {\n\t\treturn ret, err\n\t}\n\n\tfor _, v := range dst {\n\t\tts := TemperatureStat{\n\t\t\tSensorKey:   v.InstanceName,\n\t\t\tTemperature: kelvinToCelsius(v.CurrentTemperature),\n\t\t}\n\t\tret = append(ret, ts)\n\t}\n\n\treturn ret, nil\n}\n\nfunc kelvinToCelsius(temp uint32) float64 {\n\t// wmi return temperature Kelvin * 10, so need to divide the result by 10,\n\t// and then minus 273.15 to get °Celsius.\n\treturn (float64(temp*10) - 27315) / 100\n}\n"
  },
  {
    "path": "windows_memo.rst",
    "content": "Windows memo\n=====================\n\nSize\n----------\n\nDWORD\n  32-bit unsigned integer\nDWORDLONG\n  64-bit unsigned integer\nDWORD_PTR\n  unsigned long type for pointer precision\nDWORD32\n  32-bit unsigned integer\nDWORD64\n  64-bit unsigned integer\nHALF_PTR\n  _WIN64 = int, else short\nINT\n  32-bit signed integer\nINT_PTR\n  _WIN64 = __int64 else int\nLONG\n  32-bit signed integer\nLONGLONG\n  64-bit signed integer\nLONG_PTR\n  _WIN64 = __int64 else long\nSHORT\n  16-bit integer\nSIZE_T\n  maximum number of bytes to which a pointer can point. typedef ULONG_PTR SIZE_T;\nSSIZE_T\n  signed version of SIZE_T. typedef LONG_PTR SSIZE_T;\nWORD\n  16-bit unsigned integer"
  },
  {
    "path": "winservices/manager.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage winservices\n\nimport (\n\t\"golang.org/x/sys/windows/svc/mgr\"\n)\n\ntype scmanager struct {\n\tmgr *mgr.Mgr\n}\n\nfunc openSCManager() (*scmanager, error) {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &scmanager{m}, nil\n}\n\nfunc (sc *scmanager) close() error {\n\treturn sc.mgr.Disconnect()\n}\n\nfunc getService(serviceName string) (*mgr.Service, error) {\n\tm, err := openSCManager()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer m.close()\n\treturn m.mgr.OpenService(serviceName)\n}\n"
  },
  {
    "path": "winservices/winservices.go",
    "content": "// SPDX-License-Identifier: BSD-3-Clause\n//go:build windows\n\npackage winservices\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\t\"golang.org/x/sys/windows/svc\"\n\t\"golang.org/x/sys/windows/svc/mgr\"\n)\n\n// Service represent a windows service.\ntype Service struct {\n\tName   string\n\tConfig mgr.Config\n\tStatus ServiceStatus\n\tsrv    *mgr.Service\n}\n\n// ServiceStatus combines State and Accepted commands to fully describe running service.\ntype ServiceStatus struct {\n\tState         svc.State\n\tAccepts       svc.Accepted\n\tPid           uint32\n\tWin32ExitCode uint32\n}\n\n// NewService create and return a windows Service\nfunc NewService(name string) (*Service, error) {\n\t// call windows service function need to OpenService handler,\n\t// so first call func OpenService to get the specified service handler.\n\tservice, err := getService(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Service{\n\t\tName: name,\n\t\tsrv:  service,\n\t}, nil\n}\n\n// GetServiceDetail get a windows service by name\nfunc (s *Service) GetServiceDetail() error {\n\treturn s.GetServiceDetailWithContext(context.Background())\n}\n\n// GetServiceDetailWithContext get a windows service by name\nfunc (s *Service) GetServiceDetailWithContext(ctx context.Context) error {\n\tconfig, err := s.QueryServiceConfigWithContext(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts.Config = config\n\n\tstatus, err := s.QueryStatusWithContext(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts.Status = status\n\n\treturn nil\n}\n\n// QueryServiceConfig return the specified service config\nfunc (s *Service) QueryServiceConfig() (mgr.Config, error) {\n\treturn s.QueryServiceConfigWithContext(context.Background())\n}\n\n// QueryServiceConfigWithContext call QueryServiceConfig() and QueryServiceConfig2()\n// implement windows https://msdn.microsoft.com/en-us/library/windows/desktop/ms684932(v=vs.85).aspx\nfunc (s *Service) QueryServiceConfigWithContext(_ context.Context) (mgr.Config, error) {\n\treturn s.srv.Config()\n}\n\n// QueryStatus return the specified name service currentState and ControlsAccepted\nfunc (s *Service) QueryStatus() (ServiceStatus, error) {\n\treturn s.QueryStatusWithContext(context.Background())\n}\n\n// QueryStatusWithContext return the specified name service currentState and ControlsAccepted\nfunc (s *Service) QueryStatusWithContext(_ context.Context) (ServiceStatus, error) {\n\tvar p *windows.SERVICE_STATUS_PROCESS\n\tvar bytesNeeded uint32\n\tvar buf []byte\n\n\tif err := windows.QueryServiceStatusEx(s.srv.Handle, windows.SC_STATUS_PROCESS_INFO, nil, 0, &bytesNeeded); !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {\n\t\treturn ServiceStatus{}, err\n\t}\n\n\tbuf = make([]byte, bytesNeeded)\n\tp = (*windows.SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))\n\tif err := windows.QueryServiceStatusEx(s.srv.Handle, windows.SC_STATUS_PROCESS_INFO, &buf[0], uint32(len(buf)), &bytesNeeded); err != nil {\n\t\treturn ServiceStatus{}, err\n\t}\n\n\treturn ServiceStatus{\n\t\tState:         svc.State(p.CurrentState),\n\t\tAccepts:       svc.Accepted(p.ControlsAccepted),\n\t\tPid:           p.ProcessId,\n\t\tWin32ExitCode: p.Win32ExitCode,\n\t}, nil\n}\n\n// ListServices return all windows service\n// reference to golang.org/x/sys/windows/svc/mgr#ListServices()\nfunc ListServices() ([]Service, error) {\n\tm, err := openSCManager()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer m.close()\n\n\tnames, err := m.mgr.ListServices()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tservices := make([]Service, 0)\n\tfor _, name := range names {\n\t\tservices = append(services, Service{Name: name})\n\t}\n\n\treturn services, nil\n}\n"
  }
]