util.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package cpu
  2. import (
  3. "bufio"
  4. "io/ioutil"
  5. "os"
  6. "strconv"
  7. "strings"
  8. "github.com/pkg/errors"
  9. )
  10. func readFile(path string) (string, error) {
  11. contents, err := ioutil.ReadFile(path)
  12. if err != nil {
  13. return "", errors.Wrapf(err, "os/stat: read file(%s) failed!", path)
  14. }
  15. return strings.TrimSpace(string(contents)), nil
  16. }
  17. func parseUint(s string) (uint64, error) {
  18. v, err := strconv.ParseUint(s, 10, 64)
  19. if err != nil {
  20. intValue, intErr := strconv.ParseInt(s, 10, 64)
  21. // 1. Handle negative values greater than MinInt64 (and)
  22. // 2. Handle negative values lesser than MinInt64
  23. if intErr == nil && intValue < 0 {
  24. return 0, nil
  25. } else if intErr != nil &&
  26. intErr.(*strconv.NumError).Err == strconv.ErrRange &&
  27. intValue < 0 {
  28. return 0, nil
  29. }
  30. return 0, errors.Wrapf(err, "os/stat: parseUint(%s) failed!", s)
  31. }
  32. return v, nil
  33. }
  34. // ParseUintList parses and validates the specified string as the value
  35. // found in some cgroup file (e.g. cpuset.cpus, cpuset.mems), which could be
  36. // one of the formats below. Note that duplicates are actually allowed in the
  37. // input string. It returns a map[int]bool with available elements from val
  38. // set to true.
  39. // Supported formats:
  40. // 7
  41. // 1-6
  42. // 0,3-4,7,8-10
  43. // 0-0,0,1-7
  44. // 03,1-3 <- this is gonna get parsed as [1,2,3]
  45. // 3,2,1
  46. // 0-2,3,1
  47. func ParseUintList(val string) (map[int]bool, error) {
  48. if val == "" {
  49. return map[int]bool{}, nil
  50. }
  51. availableInts := make(map[int]bool)
  52. split := strings.Split(val, ",")
  53. errInvalidFormat := errors.Errorf("os/stat: invalid format: %s", val)
  54. for _, r := range split {
  55. if !strings.Contains(r, "-") {
  56. v, err := strconv.Atoi(r)
  57. if err != nil {
  58. return nil, errInvalidFormat
  59. }
  60. availableInts[v] = true
  61. } else {
  62. split := strings.SplitN(r, "-", 2)
  63. min, err := strconv.Atoi(split[0])
  64. if err != nil {
  65. return nil, errInvalidFormat
  66. }
  67. max, err := strconv.Atoi(split[1])
  68. if err != nil {
  69. return nil, errInvalidFormat
  70. }
  71. if max < min {
  72. return nil, errInvalidFormat
  73. }
  74. for i := min; i <= max; i++ {
  75. availableInts[i] = true
  76. }
  77. }
  78. }
  79. return availableInts, nil
  80. }
  81. // ReadLines reads contents from a file and splits them by new lines.
  82. // A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
  83. func readLines(filename string) ([]string, error) {
  84. return readLinesOffsetN(filename, 0, -1)
  85. }
  86. // ReadLinesOffsetN reads contents from file and splits them by new line.
  87. // The offset tells at which line number to start.
  88. // The count determines the number of lines to read (starting from offset):
  89. // n >= 0: at most n lines
  90. // n < 0: whole file
  91. func readLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
  92. f, err := os.Open(filename)
  93. if err != nil {
  94. return []string{""}, err
  95. }
  96. defer f.Close()
  97. var ret []string
  98. r := bufio.NewReader(f)
  99. for i := 0; i < n+int(offset) || n < 0; i++ {
  100. line, err := r.ReadString('\n')
  101. if err != nil {
  102. break
  103. }
  104. if i < int(offset) {
  105. continue
  106. }
  107. ret = append(ret, strings.Trim(line, "\n"))
  108. }
  109. return ret, nil
  110. }