github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/client/fingerprint/storage_unix.go (about)

     1  //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
     2  // +build darwin dragonfly freebsd linux netbsd openbsd solaris
     3  
     4  package fingerprint
     5  
     6  import (
     7  	"fmt"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  // diskFree inspects the filesystem for path and returns the volume name and
    16  // the total and free bytes available on the file system.
    17  func (f *StorageFingerprint) diskFree(path string) (volume string, total, free uint64, err error) {
    18  	absPath, err := filepath.Abs(path)
    19  	if err != nil {
    20  		return "", 0, 0, fmt.Errorf("failed to determine absolute path for %s", path)
    21  	}
    22  
    23  	// Use -k to standardize the output values between darwin and linux
    24  	var dfArgs string
    25  	if runtime.GOOS == "linux" {
    26  		// df on linux needs the -P option to prevent linebreaks on long filesystem paths
    27  		dfArgs = "-kP"
    28  	} else {
    29  		dfArgs = "-k"
    30  	}
    31  
    32  	mountOutput, err := exec.Command("df", dfArgs, absPath).Output()
    33  	if err != nil {
    34  		return "", 0, 0, fmt.Errorf("failed to determine mount point for %s", absPath)
    35  	}
    36  	// Output looks something like:
    37  	//	Filesystem 1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on
    38  	//	/dev/disk1   487385240 423722532  63406708    87% 105994631 15851677   87%   /
    39  	//	[0] volume [1] capacity [2] SKIP  [3] free
    40  	lines := strings.Split(string(mountOutput), "\n")
    41  	if len(lines) < 2 {
    42  		return "", 0, 0, fmt.Errorf("failed to parse `df` output; expected at least 2 lines")
    43  	}
    44  	fields := strings.Fields(lines[1])
    45  	if len(fields) < 4 {
    46  		return "", 0, 0, fmt.Errorf("failed to parse `df` output; expected at least 4 columns")
    47  	}
    48  	volume = fields[0]
    49  
    50  	total, err = strconv.ParseUint(fields[1], 10, 64)
    51  	if err != nil {
    52  		return "", 0, 0, fmt.Errorf("failed to parse storage.bytestotal size in kilobytes")
    53  	}
    54  	// convert to bytes
    55  	total *= 1024
    56  
    57  	free, err = strconv.ParseUint(fields[3], 10, 64)
    58  	if err != nil {
    59  		return "", 0, 0, fmt.Errorf("failed to parse storage.bytesfree size in kilobytes")
    60  	}
    61  	// convert to bytes
    62  	free *= 1024
    63  
    64  	return volume, total, free, nil
    65  }