| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- // +build freebsd openbsd
- package mem
- import (
- "context"
- "fmt"
- "os/exec"
- "strconv"
- "strings"
- )
- const swapCommand = "swapctl"
- // swapctl column indexes
- const (
- nameCol = 0
- totalKiBCol = 1
- usedKiBCol = 2
- )
- func SwapDevices() ([]*SwapDevice, error) {
- return SwapDevicesWithContext(context.Background())
- }
- func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
- swapCommandPath, err := exec.LookPath(swapCommand)
- if err != nil {
- return nil, fmt.Errorf("could not find command %q: %w", swapCommand, err)
- }
- output, err := invoke.CommandWithContext(ctx, swapCommandPath, "-lk")
- if err != nil {
- return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err)
- }
- return parseSwapctlOutput(string(output))
- }
- func parseSwapctlOutput(output string) ([]*SwapDevice, error) {
- lines := strings.Split(output, "\n")
- if len(lines) == 0 {
- return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output)
- }
- // Check header headerFields are as expected.
- header := lines[0]
- header = strings.ToLower(header)
- header = strings.ReplaceAll(header, ":", "")
- headerFields := strings.Fields(header)
- if len(headerFields) < usedKiBCol {
- return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, header)
- }
- if headerFields[nameCol] != "device" {
- return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "device")
- }
- if headerFields[totalKiBCol] != "1kb-blocks" && headerFields[totalKiBCol] != "1k-blocks" {
- return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalKiBCol], "1kb-blocks")
- }
- if headerFields[usedKiBCol] != "used" {
- return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[usedKiBCol], "used")
- }
- var swapDevices []*SwapDevice
- for _, line := range lines[1:] {
- if line == "" {
- continue // the terminal line is typically empty
- }
- fields := strings.Fields(line)
- if len(fields) < usedKiBCol {
- return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand)
- }
- totalKiB, err := strconv.ParseUint(fields[totalKiBCol], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err)
- }
- usedKiB, err := strconv.ParseUint(fields[usedKiBCol], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err)
- }
- swapDevices = append(swapDevices, &SwapDevice{
- Name: fields[nameCol],
- UsedBytes: usedKiB * 1024,
- FreeBytes: (totalKiB - usedKiB) * 1024,
- })
- }
- return swapDevices, nil
- }
|