2024-02-17 03:48:29 +00:00
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2016-04-01 21:34:39 +09:00
|
|
|
package common
|
|
|
|
|
2014-04-22 10:31:14 +09:00
|
|
|
//
|
2015-01-01 21:29:25 +09:00
|
|
|
// gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
|
2014-04-22 10:31:14 +09:00
|
|
|
// This covers these architectures.
|
2014-06-12 17:18:45 +09:00
|
|
|
// - linux (amd64, arm)
|
|
|
|
// - freebsd (amd64)
|
|
|
|
// - windows (amd64)
|
2023-02-12 09:24:52 +00:00
|
|
|
|
2014-04-18 16:34:47 +09:00
|
|
|
import (
|
|
|
|
"bufio"
|
2016-05-20 17:59:41 +09:00
|
|
|
"bytes"
|
2017-04-27 14:11:25 -07:00
|
|
|
"context"
|
2014-08-15 19:18:30 +02:00
|
|
|
"errors"
|
2017-03-15 23:01:06 +09:00
|
|
|
"fmt"
|
2021-12-18 20:06:03 +08:00
|
|
|
"io"
|
2024-07-21 16:18:16 +09:00
|
|
|
"math"
|
2015-09-16 11:58:02 +09:00
|
|
|
"net/url"
|
2014-04-18 16:34:47 +09:00
|
|
|
"os"
|
2015-09-16 11:58:02 +09:00
|
|
|
"os/exec"
|
|
|
|
"path"
|
2015-10-18 20:40:01 -07:00
|
|
|
"path/filepath"
|
2014-05-16 11:33:35 +09:00
|
|
|
"reflect"
|
2015-09-16 11:58:02 +09:00
|
|
|
"runtime"
|
2014-04-26 15:44:22 +09:00
|
|
|
"strconv"
|
2014-04-18 16:34:47 +09:00
|
|
|
"strings"
|
2016-05-20 17:59:41 +09:00
|
|
|
"time"
|
2023-04-14 22:05:58 -07:00
|
|
|
|
2024-02-17 03:48:29 +00:00
|
|
|
"github.com/shirou/gopsutil/v4/common"
|
2016-05-20 17:59:41 +09:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
Timeout = 3 * time.Second
|
2017-04-27 14:21:34 -07:00
|
|
|
ErrTimeout = errors.New("command timed out")
|
2014-04-18 16:34:47 +09:00
|
|
|
)
|
|
|
|
|
2015-09-16 11:58:02 +09:00
|
|
|
type Invoker interface {
|
|
|
|
Command(string, ...string) ([]byte, error)
|
2018-03-31 21:35:53 +09:00
|
|
|
CommandWithContext(context.Context, string, ...string) ([]byte, error)
|
2015-09-16 11:58:02 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
type Invoke struct{}
|
|
|
|
|
|
|
|
func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
|
2018-03-31 21:35:53 +09:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), Timeout)
|
2017-04-27 14:11:25 -07:00
|
|
|
defer cancel()
|
2018-03-31 21:35:53 +09:00
|
|
|
return i.CommandWithContext(ctx, name, arg...)
|
|
|
|
}
|
2017-04-27 14:11:25 -07:00
|
|
|
|
2018-03-31 21:35:53 +09:00
|
|
|
func (i Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
|
|
|
|
cmd := exec.CommandContext(ctx, name, arg...)
|
2017-04-27 14:11:25 -07:00
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
cmd.Stdout = &buf
|
|
|
|
cmd.Stderr = &buf
|
|
|
|
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
return buf.Bytes(), err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
|
|
return buf.Bytes(), err
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf.Bytes(), nil
|
2015-09-16 11:58:02 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
type FakeInvoke struct {
|
2017-03-15 23:01:06 +09:00
|
|
|
Suffix string // Suffix species expected file name suffix such as "fail"
|
2022-01-30 22:48:09 +02:00
|
|
|
Error error // If Error specified, return the error.
|
2015-09-16 11:58:02 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
// Command in FakeInvoke returns from expected file if exists.
|
|
|
|
func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
|
|
|
|
if i.Error != nil {
|
|
|
|
return []byte{}, i.Error
|
|
|
|
}
|
|
|
|
|
|
|
|
arch := runtime.GOOS
|
|
|
|
|
2017-03-15 23:01:06 +09:00
|
|
|
commandName := filepath.Base(name)
|
|
|
|
|
|
|
|
fname := strings.Join(append([]string{commandName}, arg...), "")
|
2015-09-16 11:58:02 +09:00
|
|
|
fname = url.QueryEscape(fname)
|
2017-03-15 23:01:06 +09:00
|
|
|
fpath := path.Join("testdata", arch, fname)
|
2015-09-16 11:58:02 +09:00
|
|
|
if i.Suffix != "" {
|
|
|
|
fpath += "_" + i.Suffix
|
|
|
|
}
|
|
|
|
if PathExists(fpath) {
|
2023-09-08 17:05:14 +00:00
|
|
|
return os.ReadFile(fpath)
|
2015-09-16 11:58:02 +09:00
|
|
|
}
|
2017-03-15 23:01:06 +09:00
|
|
|
return []byte{}, fmt.Errorf("could not find testdata: %s", fpath)
|
2015-09-16 11:58:02 +09:00
|
|
|
}
|
|
|
|
|
2018-03-31 21:35:53 +09:00
|
|
|
func (i FakeInvoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
|
|
|
|
return i.Command(name, arg...)
|
|
|
|
}
|
|
|
|
|
2016-04-01 21:34:39 +09:00
|
|
|
var ErrNotImplementedError = errors.New("not implemented yet")
|
2014-08-07 17:11:24 +09:00
|
|
|
|
2021-11-06 09:53:56 +00:00
|
|
|
// ReadFile reads contents from a file
|
2020-06-20 12:55:26 +00:00
|
|
|
func ReadFile(filename string) (string, error) {
|
2023-09-08 17:05:14 +00:00
|
|
|
content, err := os.ReadFile(filename)
|
2020-06-20 12:55:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(content), nil
|
|
|
|
}
|
|
|
|
|
2015-09-13 13:05:09 +09:00
|
|
|
// ReadLines reads contents from a file and splits them by new lines.
|
2014-11-27 10:25:14 +09:00
|
|
|
// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
|
|
|
|
func ReadLines(filename string) ([]string, error) {
|
|
|
|
return ReadLinesOffsetN(filename, 0, -1)
|
2014-11-02 01:13:40 +01:00
|
|
|
}
|
|
|
|
|
2023-08-25 13:35:07 -07:00
|
|
|
// ReadLine reads a file and returns the first occurrence of a line that is prefixed with prefix.
|
|
|
|
func ReadLine(filename string, prefix string) (string, error) {
|
|
|
|
f, err := os.Open(filename)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
r := bufio.NewReader(f)
|
|
|
|
for {
|
|
|
|
line, err := r.ReadString('\n')
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
2023-08-25 14:39:29 -07:00
|
|
|
return "", err
|
2023-08-25 13:35:07 -07:00
|
|
|
}
|
|
|
|
if strings.HasPrefix(line, prefix) {
|
|
|
|
return line, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2021-12-24 17:14:50 +08:00
|
|
|
// ReadLinesOffsetN reads contents from file and splits them by new line.
|
2014-11-02 01:13:40 +01:00
|
|
|
// The offset tells at which line number to start.
|
|
|
|
// The count determines the number of lines to read (starting from offset):
|
2022-09-01 09:18:20 +02:00
|
|
|
// n >= 0: at most n lines
|
|
|
|
// n < 0: whole file
|
2014-11-27 10:25:14 +09:00
|
|
|
func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
|
2014-04-18 16:34:47 +09:00
|
|
|
f, err := os.Open(filename)
|
|
|
|
if err != nil {
|
|
|
|
return []string{""}, err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
2014-04-30 16:16:07 +09:00
|
|
|
var ret []string
|
2014-04-18 16:34:47 +09:00
|
|
|
|
|
|
|
r := bufio.NewReader(f)
|
2024-08-23 08:22:42 +00:00
|
|
|
for i := uint(0); i < uint(n)+offset || n < 0; i++ {
|
2014-11-02 01:13:40 +01:00
|
|
|
line, err := r.ReadString('\n')
|
|
|
|
if err != nil {
|
2021-12-18 20:06:03 +08:00
|
|
|
if err == io.EOF && len(line) > 0 {
|
|
|
|
ret = append(ret, strings.Trim(line, "\n"))
|
|
|
|
}
|
2014-11-02 01:13:40 +01:00
|
|
|
break
|
|
|
|
}
|
2024-08-23 08:22:42 +00:00
|
|
|
if i < offset {
|
2014-11-02 01:13:40 +01:00
|
|
|
continue
|
|
|
|
}
|
2014-04-18 16:34:47 +09:00
|
|
|
ret = append(ret, strings.Trim(line, "\n"))
|
|
|
|
}
|
|
|
|
|
2014-04-28 15:31:23 +09:00
|
|
|
return ret, nil
|
2014-04-18 16:34:47 +09:00
|
|
|
}
|
2014-04-22 17:38:47 +09:00
|
|
|
|
2014-12-28 22:30:07 +09:00
|
|
|
func IntToString(orig []int8) string {
|
|
|
|
ret := make([]byte, len(orig))
|
2015-01-22 15:16:09 +09:00
|
|
|
size := -1
|
2014-12-28 22:30:07 +09:00
|
|
|
for i, o := range orig {
|
|
|
|
if o == 0 {
|
|
|
|
size = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
ret[i] = byte(o)
|
|
|
|
}
|
2015-01-22 15:16:09 +09:00
|
|
|
if size == -1 {
|
|
|
|
size = len(orig)
|
|
|
|
}
|
2014-12-28 22:30:07 +09:00
|
|
|
|
|
|
|
return string(ret[0:size])
|
|
|
|
}
|
|
|
|
|
2016-04-10 10:07:35 +00:00
|
|
|
func UintToString(orig []uint8) string {
|
2016-05-20 17:59:41 +09:00
|
|
|
ret := make([]byte, len(orig))
|
|
|
|
size := -1
|
|
|
|
for i, o := range orig {
|
|
|
|
if o == 0 {
|
|
|
|
size = i
|
|
|
|
break
|
|
|
|
}
|
2021-11-06 09:53:56 +00:00
|
|
|
ret[i] = byte(o)
|
2016-05-20 17:59:41 +09:00
|
|
|
}
|
|
|
|
if size == -1 {
|
|
|
|
size = len(orig)
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(ret[0:size])
|
2016-04-10 10:07:35 +00:00
|
|
|
}
|
|
|
|
|
2014-11-27 10:18:15 +09:00
|
|
|
func ByteToString(orig []byte) string {
|
2014-04-22 17:38:47 +09:00
|
|
|
n := -1
|
2014-04-22 19:13:27 +09:00
|
|
|
l := -1
|
2014-04-23 10:33:55 +09:00
|
|
|
for i, b := range orig {
|
2014-04-22 19:13:27 +09:00
|
|
|
// skip left side null
|
2014-04-23 10:33:55 +09:00
|
|
|
if l == -1 && b == 0 {
|
2014-04-22 19:13:27 +09:00
|
|
|
continue
|
|
|
|
}
|
2014-04-23 10:33:55 +09:00
|
|
|
if l == -1 {
|
2014-04-22 19:13:27 +09:00
|
|
|
l = i
|
|
|
|
}
|
|
|
|
|
2014-04-22 17:38:47 +09:00
|
|
|
if b == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
n = i + 1
|
|
|
|
}
|
2014-04-22 17:39:51 +09:00
|
|
|
if n == -1 {
|
2014-04-22 17:38:47 +09:00
|
|
|
return string(orig)
|
|
|
|
}
|
2014-04-30 16:16:07 +09:00
|
|
|
return string(orig[l:n])
|
2014-04-22 17:38:47 +09:00
|
|
|
}
|
2014-04-26 15:44:22 +09:00
|
|
|
|
2015-12-08 09:32:45 +11:00
|
|
|
// ReadInts reads contents from single line file and returns them as []int32.
|
|
|
|
func ReadInts(filename string) ([]int64, error) {
|
|
|
|
f, err := os.Open(filename)
|
|
|
|
if err != nil {
|
|
|
|
return []int64{}, err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
var ret []int64
|
|
|
|
|
|
|
|
r := bufio.NewReader(f)
|
|
|
|
|
|
|
|
// The int files that this is concerned with should only be one liners.
|
|
|
|
line, err := r.ReadString('\n')
|
|
|
|
if err != nil {
|
|
|
|
return []int64{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return []int64{}, err
|
|
|
|
}
|
|
|
|
ret = append(ret, i)
|
|
|
|
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
|
2021-11-06 09:53:56 +00:00
|
|
|
// Parse Hex to uint32 without error
|
2019-05-07 07:24:17 -04:00
|
|
|
func HexToUint32(hex string) uint32 {
|
|
|
|
vv, _ := strconv.ParseUint(hex, 16, 32)
|
|
|
|
return uint32(vv)
|
|
|
|
}
|
|
|
|
|
2021-11-06 09:53:56 +00:00
|
|
|
// Parse to int32 without error
|
2014-05-18 22:43:12 +09:00
|
|
|
func mustParseInt32(val string) int32 {
|
2014-04-26 15:44:22 +09:00
|
|
|
vv, _ := strconv.ParseInt(val, 10, 32)
|
|
|
|
return int32(vv)
|
|
|
|
}
|
|
|
|
|
2021-11-06 09:53:56 +00:00
|
|
|
// Parse to uint64 without error
|
2014-05-18 22:43:12 +09:00
|
|
|
func mustParseUint64(val string) uint64 {
|
2014-04-26 15:44:22 +09:00
|
|
|
vv, _ := strconv.ParseInt(val, 10, 64)
|
|
|
|
return uint64(vv)
|
|
|
|
}
|
2014-04-29 14:59:22 +09:00
|
|
|
|
2021-11-06 09:53:56 +00:00
|
|
|
// Parse to Float64 without error
|
2014-05-18 22:43:12 +09:00
|
|
|
func mustParseFloat64(val string) float64 {
|
2014-05-16 15:33:23 +09:00
|
|
|
vv, _ := strconv.ParseFloat(val, 64)
|
|
|
|
return vv
|
|
|
|
}
|
|
|
|
|
2021-11-06 09:53:56 +00:00
|
|
|
// StringsHas checks the target string slice contains src or not
|
2015-07-21 15:25:04 +09:00
|
|
|
func StringsHas(target []string, src string) bool {
|
2014-04-29 14:59:22 +09:00
|
|
|
for _, t := range target {
|
2015-02-12 22:34:00 +09:00
|
|
|
if strings.TrimSpace(t) == src {
|
2014-04-29 14:59:22 +09:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2014-05-16 11:33:35 +09:00
|
|
|
|
2021-11-06 09:53:56 +00:00
|
|
|
// StringsContains checks the src in any string of the target string slice
|
2015-07-21 15:25:04 +09:00
|
|
|
func StringsContains(target []string, src string) bool {
|
|
|
|
for _, t := range target {
|
|
|
|
if strings.Contains(t, src) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2016-03-01 23:38:13 +09:00
|
|
|
// IntContains checks the src in any int of the target int slice.
|
|
|
|
func IntContains(target []int, src int) bool {
|
|
|
|
for _, t := range target {
|
|
|
|
if src == t {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2014-05-16 11:33:35 +09:00
|
|
|
// get struct attributes.
|
|
|
|
// This method is used only for debugging platform dependent code.
|
|
|
|
func attributes(m interface{}) map[string]reflect.Type {
|
|
|
|
typ := reflect.TypeOf(m)
|
|
|
|
if typ.Kind() == reflect.Ptr {
|
|
|
|
typ = typ.Elem()
|
|
|
|
}
|
|
|
|
|
|
|
|
attrs := make(map[string]reflect.Type)
|
|
|
|
if typ.Kind() != reflect.Struct {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
|
|
p := typ.Field(i)
|
|
|
|
if !p.Anonymous {
|
|
|
|
attrs[p.Name] = p.Type
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return attrs
|
|
|
|
}
|
2014-05-16 16:37:20 +09:00
|
|
|
|
2014-11-27 10:32:35 +09:00
|
|
|
func PathExists(filename string) bool {
|
2014-05-16 16:37:20 +09:00
|
|
|
if _, err := os.Stat(filename); err == nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2015-10-16 11:58:17 -06:00
|
|
|
|
2022-07-15 12:20:19 +00:00
|
|
|
// PathExistsWithContents returns the filename exists and it is not empty
|
|
|
|
func PathExistsWithContents(filename string) bool {
|
2022-07-19 12:43:41 +00:00
|
|
|
info, err := os.Stat(filename)
|
2022-07-15 12:20:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
2024-01-18 10:21:42 -08:00
|
|
|
return info.Size() > 4 && !info.IsDir() // at least 4 bytes
|
2022-07-15 12:20:19 +00:00
|
|
|
}
|
|
|
|
|
2023-03-25 23:14:49 -07:00
|
|
|
// GetEnvWithContext retrieves the environment variable key. If it does not exist it returns the default.
|
2023-05-26 15:53:58 -07:00
|
|
|
// The context may optionally contain a map superseding os.EnvKey.
|
2023-03-25 23:14:49 -07:00
|
|
|
func GetEnvWithContext(ctx context.Context, key string, dfault string, combineWith ...string) string {
|
|
|
|
var value string
|
2023-05-26 15:53:58 -07:00
|
|
|
if env, ok := ctx.Value(common.EnvKey).(common.EnvMap); ok {
|
|
|
|
value = env[common.EnvKeyType(key)]
|
2023-03-25 23:14:49 -07:00
|
|
|
}
|
|
|
|
if value == "" {
|
|
|
|
value = os.Getenv(key)
|
|
|
|
}
|
|
|
|
if value == "" {
|
|
|
|
value = dfault
|
|
|
|
}
|
|
|
|
|
|
|
|
return combine(value, combineWith)
|
|
|
|
}
|
|
|
|
|
2021-12-22 21:54:41 +00:00
|
|
|
// GetEnv retrieves the environment variable key. If it does not exist it returns the default.
|
2015-10-18 20:40:01 -07:00
|
|
|
func GetEnv(key string, dfault string, combineWith ...string) string {
|
2015-10-16 11:58:17 -06:00
|
|
|
value := os.Getenv(key)
|
|
|
|
if value == "" {
|
|
|
|
value = dfault
|
|
|
|
}
|
2015-10-18 20:40:01 -07:00
|
|
|
|
2023-03-25 23:14:49 -07:00
|
|
|
return combine(value, combineWith)
|
|
|
|
}
|
|
|
|
|
|
|
|
func combine(value string, combineWith []string) string {
|
2015-10-18 20:40:01 -07:00
|
|
|
switch len(combineWith) {
|
|
|
|
case 0:
|
|
|
|
return value
|
|
|
|
case 1:
|
|
|
|
return filepath.Join(value, combineWith[0])
|
|
|
|
default:
|
|
|
|
all := make([]string, len(combineWith)+1)
|
|
|
|
all[0] = value
|
|
|
|
copy(all[1:], combineWith)
|
|
|
|
return filepath.Join(all...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostProc(combineWith ...string) string {
|
|
|
|
return GetEnv("HOST_PROC", "/proc", combineWith...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostSys(combineWith ...string) string {
|
|
|
|
return GetEnv("HOST_SYS", "/sys", combineWith...)
|
2015-10-16 11:58:17 -06:00
|
|
|
}
|
2016-03-13 23:42:06 +09:00
|
|
|
|
|
|
|
func HostEtc(combineWith ...string) string {
|
|
|
|
return GetEnv("HOST_ETC", "/etc", combineWith...)
|
|
|
|
}
|
2016-05-20 17:59:41 +09:00
|
|
|
|
2017-10-16 14:53:14 -07:00
|
|
|
func HostVar(combineWith ...string) string {
|
|
|
|
return GetEnv("HOST_VAR", "/var", combineWith...)
|
|
|
|
}
|
|
|
|
|
2018-07-02 10:04:57 +02:00
|
|
|
func HostRun(combineWith ...string) string {
|
|
|
|
return GetEnv("HOST_RUN", "/run", combineWith...)
|
|
|
|
}
|
|
|
|
|
2020-01-20 20:07:09 +02:00
|
|
|
func HostDev(combineWith ...string) string {
|
|
|
|
return GetEnv("HOST_DEV", "/dev", combineWith...)
|
|
|
|
}
|
|
|
|
|
2022-12-28 23:12:58 +02:00
|
|
|
func HostRoot(combineWith ...string) string {
|
|
|
|
return GetEnv("HOST_ROOT", "/", combineWith...)
|
|
|
|
}
|
|
|
|
|
2023-03-25 23:14:49 -07:00
|
|
|
func HostProcWithContext(ctx context.Context, combineWith ...string) string {
|
|
|
|
return GetEnvWithContext(ctx, "HOST_PROC", "/proc", combineWith...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostProcMountInfoWithContext(ctx context.Context, combineWith ...string) string {
|
|
|
|
return GetEnvWithContext(ctx, "HOST_PROC_MOUNTINFO", "", combineWith...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostSysWithContext(ctx context.Context, combineWith ...string) string {
|
|
|
|
return GetEnvWithContext(ctx, "HOST_SYS", "/sys", combineWith...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostEtcWithContext(ctx context.Context, combineWith ...string) string {
|
|
|
|
return GetEnvWithContext(ctx, "HOST_ETC", "/etc", combineWith...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostVarWithContext(ctx context.Context, combineWith ...string) string {
|
|
|
|
return GetEnvWithContext(ctx, "HOST_VAR", "/var", combineWith...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostRunWithContext(ctx context.Context, combineWith ...string) string {
|
|
|
|
return GetEnvWithContext(ctx, "HOST_RUN", "/run", combineWith...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostDevWithContext(ctx context.Context, combineWith ...string) string {
|
|
|
|
return GetEnvWithContext(ctx, "HOST_DEV", "/dev", combineWith...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HostRootWithContext(ctx context.Context, combineWith ...string) string {
|
|
|
|
return GetEnvWithContext(ctx, "HOST_ROOT", "/", combineWith...)
|
|
|
|
}
|
|
|
|
|
2017-08-16 15:32:21 -07:00
|
|
|
// getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running
|
|
|
|
// sysctl commands (see DoSysctrl).
|
|
|
|
func getSysctrlEnv(env []string) []string {
|
|
|
|
foundLC := false
|
|
|
|
for i, line := range env {
|
|
|
|
if strings.HasPrefix(line, "LC_ALL") {
|
|
|
|
env[i] = "LC_ALL=C"
|
|
|
|
foundLC = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !foundLC {
|
|
|
|
env = append(env, "LC_ALL=C")
|
|
|
|
}
|
|
|
|
return env
|
|
|
|
}
|
2024-07-21 16:18:16 +09:00
|
|
|
|
|
|
|
// Round places rounds the number 'val' to 'n' decimal places
|
|
|
|
func Round(val float64, n int) float64 {
|
|
|
|
// Calculate the power of 10 to the n
|
|
|
|
pow10 := math.Pow(10, float64(n))
|
|
|
|
// Multiply the value by pow10, round it, then divide it by pow10
|
|
|
|
return math.Round(val*pow10) / pow10
|
|
|
|
}
|