...

Source file src/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/utils.go

Documentation: github.com/opencontainers/runc/libcontainer/cgroups/fscommon

     1  package fscommon
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"path"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/opencontainers/runc/libcontainer/cgroups"
    12  )
    13  
    14  var (
    15  	// Deprecated: use cgroups.OpenFile instead.
    16  	OpenFile = cgroups.OpenFile
    17  	// Deprecated: use cgroups.ReadFile instead.
    18  	ReadFile = cgroups.ReadFile
    19  	// Deprecated: use cgroups.WriteFile instead.
    20  	WriteFile = cgroups.WriteFile
    21  )
    22  
    23  // ParseError records a parse error details, including the file path.
    24  type ParseError struct {
    25  	Path string
    26  	File string
    27  	Err  error
    28  }
    29  
    30  func (e *ParseError) Error() string {
    31  	return "unable to parse " + path.Join(e.Path, e.File) + ": " + e.Err.Error()
    32  }
    33  
    34  func (e *ParseError) Unwrap() error { return e.Err }
    35  
    36  // ParseUint converts a string to an uint64 integer.
    37  // Negative values are returned at zero as, due to kernel bugs,
    38  // some of the memory cgroup stats can be negative.
    39  func ParseUint(s string, base, bitSize int) (uint64, error) {
    40  	value, err := strconv.ParseUint(s, base, bitSize)
    41  	if err != nil {
    42  		intValue, intErr := strconv.ParseInt(s, base, bitSize)
    43  		// 1. Handle negative values greater than MinInt64 (and)
    44  		// 2. Handle negative values lesser than MinInt64
    45  		if intErr == nil && intValue < 0 {
    46  			return 0, nil
    47  		} else if errors.Is(intErr, strconv.ErrRange) && intValue < 0 {
    48  			return 0, nil
    49  		}
    50  
    51  		return value, err
    52  	}
    53  
    54  	return value, nil
    55  }
    56  
    57  // ParseKeyValue parses a space-separated "name value" kind of cgroup
    58  // parameter and returns its key as a string, and its value as uint64
    59  // (ParseUint is used to convert the value). For example,
    60  // "io_service_bytes 1234" will be returned as "io_service_bytes", 1234.
    61  func ParseKeyValue(t string) (string, uint64, error) {
    62  	parts := strings.SplitN(t, " ", 3)
    63  	if len(parts) != 2 {
    64  		return "", 0, fmt.Errorf("line %q is not in key value format", t)
    65  	}
    66  
    67  	value, err := ParseUint(parts[1], 10, 64)
    68  	if err != nil {
    69  		return "", 0, err
    70  	}
    71  
    72  	return parts[0], value, nil
    73  }
    74  
    75  // GetValueByKey reads a key-value pairs from the specified cgroup file,
    76  // and returns a value of the specified key. ParseUint is used for value
    77  // conversion.
    78  func GetValueByKey(path, file, key string) (uint64, error) {
    79  	content, err := cgroups.ReadFile(path, file)
    80  	if err != nil {
    81  		return 0, err
    82  	}
    83  
    84  	lines := strings.Split(content, "\n")
    85  	for _, line := range lines {
    86  		arr := strings.Split(line, " ")
    87  		if len(arr) == 2 && arr[0] == key {
    88  			val, err := ParseUint(arr[1], 10, 64)
    89  			if err != nil {
    90  				err = &ParseError{Path: path, File: file, Err: err}
    91  			}
    92  			return val, err
    93  		}
    94  	}
    95  
    96  	return 0, nil
    97  }
    98  
    99  // GetCgroupParamUint reads a single uint64 value from the specified cgroup file.
   100  // If the value read is "max", the math.MaxUint64 is returned.
   101  func GetCgroupParamUint(path, file string) (uint64, error) {
   102  	contents, err := GetCgroupParamString(path, file)
   103  	if err != nil {
   104  		return 0, err
   105  	}
   106  	contents = strings.TrimSpace(contents)
   107  	if contents == "max" {
   108  		return math.MaxUint64, nil
   109  	}
   110  
   111  	res, err := ParseUint(contents, 10, 64)
   112  	if err != nil {
   113  		return res, &ParseError{Path: path, File: file, Err: err}
   114  	}
   115  	return res, nil
   116  }
   117  
   118  // GetCgroupParamInt reads a single int64 value from specified cgroup file.
   119  // If the value read is "max", the math.MaxInt64 is returned.
   120  func GetCgroupParamInt(path, file string) (int64, error) {
   121  	contents, err := cgroups.ReadFile(path, file)
   122  	if err != nil {
   123  		return 0, err
   124  	}
   125  	contents = strings.TrimSpace(contents)
   126  	if contents == "max" {
   127  		return math.MaxInt64, nil
   128  	}
   129  
   130  	res, err := strconv.ParseInt(contents, 10, 64)
   131  	if err != nil {
   132  		return res, &ParseError{Path: path, File: file, Err: err}
   133  	}
   134  	return res, nil
   135  }
   136  
   137  // GetCgroupParamString reads a string from the specified cgroup file.
   138  func GetCgroupParamString(path, file string) (string, error) {
   139  	contents, err := cgroups.ReadFile(path, file)
   140  	if err != nil {
   141  		return "", err
   142  	}
   143  
   144  	return strings.TrimSpace(contents), nil
   145  }
   146  

View as plain text