...

Source file src/github.com/shirou/gopsutil/internal/common/common.go

Documentation: github.com/shirou/gopsutil/internal/common

     1  package common
     2  
     3  //
     4  // gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
     5  // This covers these architectures.
     6  //  - linux (amd64, arm)
     7  //  - freebsd (amd64)
     8  //  - windows (amd64)
     9  import (
    10  	"bufio"
    11  	"bytes"
    12  	"context"
    13  	"errors"
    14  	"fmt"
    15  	"io/ioutil"
    16  	"net/url"
    17  	"os"
    18  	"os/exec"
    19  	"path"
    20  	"path/filepath"
    21  	"reflect"
    22  	"runtime"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  )
    27  
    28  var (
    29  	Timeout    = 3 * time.Second
    30  	ErrTimeout = errors.New("command timed out")
    31  )
    32  
    33  type Invoker interface {
    34  	Command(string, ...string) ([]byte, error)
    35  	CommandWithContext(context.Context, string, ...string) ([]byte, error)
    36  }
    37  
    38  type Invoke struct{}
    39  
    40  func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
    41  	ctx, cancel := context.WithTimeout(context.Background(), Timeout)
    42  	defer cancel()
    43  	return i.CommandWithContext(ctx, name, arg...)
    44  }
    45  
    46  func (i Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
    47  	cmd := exec.CommandContext(ctx, name, arg...)
    48  
    49  	var buf bytes.Buffer
    50  	cmd.Stdout = &buf
    51  	cmd.Stderr = &buf
    52  
    53  	if err := cmd.Start(); err != nil {
    54  		return buf.Bytes(), err
    55  	}
    56  
    57  	if err := cmd.Wait(); err != nil {
    58  		return buf.Bytes(), err
    59  	}
    60  
    61  	return buf.Bytes(), nil
    62  }
    63  
    64  type FakeInvoke struct {
    65  	Suffix string // Suffix species expected file name suffix such as "fail"
    66  	Error  error  // If Error specfied, return the error.
    67  }
    68  
    69  // Command in FakeInvoke returns from expected file if exists.
    70  func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
    71  	if i.Error != nil {
    72  		return []byte{}, i.Error
    73  	}
    74  
    75  	arch := runtime.GOOS
    76  
    77  	commandName := filepath.Base(name)
    78  
    79  	fname := strings.Join(append([]string{commandName}, arg...), "")
    80  	fname = url.QueryEscape(fname)
    81  	fpath := path.Join("testdata", arch, fname)
    82  	if i.Suffix != "" {
    83  		fpath += "_" + i.Suffix
    84  	}
    85  	if PathExists(fpath) {
    86  		return ioutil.ReadFile(fpath)
    87  	}
    88  	return []byte{}, fmt.Errorf("could not find testdata: %s", fpath)
    89  }
    90  
    91  func (i FakeInvoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
    92  	return i.Command(name, arg...)
    93  }
    94  
    95  var ErrNotImplementedError = errors.New("not implemented yet")
    96  
    97  // ReadFile reads contents from a file.
    98  func ReadFile(filename string) (string, error) {
    99  	content, err := ioutil.ReadFile(filename)
   100  
   101  	if err != nil {
   102  		return "", err
   103  	}
   104  
   105  	return string(content), nil
   106  }
   107  
   108  // ReadLines reads contents from a file and splits them by new lines.
   109  // A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
   110  func ReadLines(filename string) ([]string, error) {
   111  	return ReadLinesOffsetN(filename, 0, -1)
   112  }
   113  
   114  // ReadLinesOffsetN reads contents from file and splits them by new line.
   115  // The offset tells at which line number to start.
   116  // The count determines the number of lines to read (starting from offset):
   117  //   n >= 0: at most n lines
   118  //   n < 0: whole file
   119  func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
   120  	f, err := os.Open(filename)
   121  	if err != nil {
   122  		return []string{""}, err
   123  	}
   124  	defer f.Close()
   125  
   126  	var ret []string
   127  
   128  	r := bufio.NewReader(f)
   129  	for i := 0; i < n+int(offset) || n < 0; i++ {
   130  		line, err := r.ReadString('\n')
   131  		if err != nil {
   132  			break
   133  		}
   134  		if i < int(offset) {
   135  			continue
   136  		}
   137  		ret = append(ret, strings.Trim(line, "\n"))
   138  	}
   139  
   140  	return ret, nil
   141  }
   142  
   143  func IntToString(orig []int8) string {
   144  	ret := make([]byte, len(orig))
   145  	size := -1
   146  	for i, o := range orig {
   147  		if o == 0 {
   148  			size = i
   149  			break
   150  		}
   151  		ret[i] = byte(o)
   152  	}
   153  	if size == -1 {
   154  		size = len(orig)
   155  	}
   156  
   157  	return string(ret[0:size])
   158  }
   159  
   160  func UintToString(orig []uint8) string {
   161  	ret := make([]byte, len(orig))
   162  	size := -1
   163  	for i, o := range orig {
   164  		if o == 0 {
   165  			size = i
   166  			break
   167  		}
   168  		ret[i] = o
   169  	}
   170  	if size == -1 {
   171  		size = len(orig)
   172  	}
   173  
   174  	return string(ret[0:size])
   175  }
   176  
   177  func ByteToString(orig []byte) string {
   178  	n := -1
   179  	l := -1
   180  	for i, b := range orig {
   181  		// skip left side null
   182  		if l == -1 && b == 0 {
   183  			continue
   184  		}
   185  		if l == -1 {
   186  			l = i
   187  		}
   188  
   189  		if b == 0 {
   190  			break
   191  		}
   192  		n = i + 1
   193  	}
   194  	if n == -1 {
   195  		return string(orig)
   196  	}
   197  	return string(orig[l:n])
   198  }
   199  
   200  // ReadInts reads contents from single line file and returns them as []int32.
   201  func ReadInts(filename string) ([]int64, error) {
   202  	f, err := os.Open(filename)
   203  	if err != nil {
   204  		return []int64{}, err
   205  	}
   206  	defer f.Close()
   207  
   208  	var ret []int64
   209  
   210  	r := bufio.NewReader(f)
   211  
   212  	// The int files that this is concerned with should only be one liners.
   213  	line, err := r.ReadString('\n')
   214  	if err != nil {
   215  		return []int64{}, err
   216  	}
   217  
   218  	i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32)
   219  	if err != nil {
   220  		return []int64{}, err
   221  	}
   222  	ret = append(ret, i)
   223  
   224  	return ret, nil
   225  }
   226  
   227  // HexToUint32 parses Hex to uint32 without error.
   228  func HexToUint32(hex string) uint32 {
   229  	vv, _ := strconv.ParseUint(hex, 16, 32)
   230  	return uint32(vv)
   231  }
   232  
   233  // mustParseInt32 parses to int32 without error.
   234  func mustParseInt32(val string) int32 {
   235  	vv, _ := strconv.ParseInt(val, 10, 32)
   236  	return int32(vv)
   237  }
   238  
   239  // mustParseUint64 parses to uint64 without error.
   240  func mustParseUint64(val string) uint64 {
   241  	vv, _ := strconv.ParseInt(val, 10, 64)
   242  	return uint64(vv)
   243  }
   244  
   245  // mustParseFloat64 parses to Float64 without error.
   246  func mustParseFloat64(val string) float64 {
   247  	vv, _ := strconv.ParseFloat(val, 64)
   248  	return vv
   249  }
   250  
   251  // StringsHas checks the target string slice contains src or not.
   252  func StringsHas(target []string, src string) bool {
   253  	for _, t := range target {
   254  		if strings.TrimSpace(t) == src {
   255  			return true
   256  		}
   257  	}
   258  	return false
   259  }
   260  
   261  // StringsContains checks the src in any string of the target string slice.
   262  func StringsContains(target []string, src string) bool {
   263  	for _, t := range target {
   264  		if strings.Contains(t, src) {
   265  			return true
   266  		}
   267  	}
   268  	return false
   269  }
   270  
   271  // IntContains checks the src in any int of the target int slice.
   272  func IntContains(target []int, src int) bool {
   273  	for _, t := range target {
   274  		if src == t {
   275  			return true
   276  		}
   277  	}
   278  	return false
   279  }
   280  
   281  // get struct attributes.
   282  // This method is used only for debugging platform dependent code.
   283  func attributes(m interface{}) map[string]reflect.Type {
   284  	typ := reflect.TypeOf(m)
   285  	if typ.Kind() == reflect.Ptr {
   286  		typ = typ.Elem()
   287  	}
   288  
   289  	attrs := make(map[string]reflect.Type)
   290  	if typ.Kind() != reflect.Struct {
   291  		return nil
   292  	}
   293  
   294  	for i := 0; i < typ.NumField(); i++ {
   295  		p := typ.Field(i)
   296  		if !p.Anonymous {
   297  			attrs[p.Name] = p.Type
   298  		}
   299  	}
   300  
   301  	return attrs
   302  }
   303  
   304  func PathExists(filename string) bool {
   305  	if _, err := os.Stat(filename); err == nil {
   306  		return true
   307  	}
   308  	return false
   309  }
   310  
   311  // GetEnv retrieves the environment variable key. If it does not exist it returns the default.
   312  func GetEnv(key string, dfault string, combineWith ...string) string {
   313  	value := os.Getenv(key)
   314  	if value == "" {
   315  		value = dfault
   316  	}
   317  
   318  	switch len(combineWith) {
   319  	case 0:
   320  		return value
   321  	case 1:
   322  		return filepath.Join(value, combineWith[0])
   323  	default:
   324  		all := make([]string, len(combineWith)+1)
   325  		all[0] = value
   326  		copy(all[1:], combineWith)
   327  		return filepath.Join(all...)
   328  	}
   329  }
   330  
   331  func HostProc(combineWith ...string) string {
   332  	return GetEnv("HOST_PROC", "/proc", combineWith...)
   333  }
   334  
   335  func HostSys(combineWith ...string) string {
   336  	return GetEnv("HOST_SYS", "/sys", combineWith...)
   337  }
   338  
   339  func HostEtc(combineWith ...string) string {
   340  	return GetEnv("HOST_ETC", "/etc", combineWith...)
   341  }
   342  
   343  func HostVar(combineWith ...string) string {
   344  	return GetEnv("HOST_VAR", "/var", combineWith...)
   345  }
   346  
   347  func HostRun(combineWith ...string) string {
   348  	return GetEnv("HOST_RUN", "/run", combineWith...)
   349  }
   350  
   351  func HostDev(combineWith ...string) string {
   352  	return GetEnv("HOST_DEV", "/dev", combineWith...)
   353  }
   354  
   355  // MockEnv set environment variable and return revert function.
   356  // MockEnv should be used testing only.
   357  func MockEnv(key string, value string) func() {
   358  	original := os.Getenv(key)
   359  	os.Setenv(key, value)
   360  	return func() {
   361  		os.Setenv(key, original)
   362  	}
   363  }
   364  
   365  // getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running
   366  // sysctl commands (see DoSysctrl).
   367  func getSysctrlEnv(env []string) []string {
   368  	foundLC := false
   369  	for i, line := range env {
   370  		if strings.HasPrefix(line, "LC_ALL") {
   371  			env[i] = "LC_ALL=C"
   372  			foundLC = true
   373  		}
   374  	}
   375  	if !foundLC {
   376  		env = append(env, "LC_ALL=C")
   377  	}
   378  	return env
   379  }
   380  

View as plain text