1// +build linux 2 3/* 4** Zabbix 5** Copyright (C) 2001-2021 Zabbix SIA 6** 7** This program is free software; you can redistribute it and/or modify 8** it under the terms of the GNU General Public License as published by 9** the Free Software Foundation; either version 2 of the License, or 10** (at your option) any later version. 11** 12** This program is distributed in the hope that it will be useful, 13** but WITHOUT ANY WARRANTY; without even the implied warranty of 14** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15** GNU General Public License for more details. 16** 17** You should have received a copy of the GNU General Public License 18** along with this program; if not, write to the Free Software 19** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20**/ 21 22package procfs 23 24import ( 25 "bytes" 26 "errors" 27 "fmt" 28 "strconv" 29 "strings" 30 "syscall" 31) 32 33const ( 34 kB = 1024 35 mB = kB * 1024 36 gB = mB * 1024 37 tB = gB * 1024 38) 39 40// GetMemory reads /proc/meminfo file and returns and returns the value in bytes for the 41// specific memory type. Returns an error if the value was not found, or if theres is an issue 42// with reading the file or parsing the value. 43func GetMemory(memType string) (mem uint64, err error) { 44 meminfo, err := ReadAll("/proc/meminfo") 45 if err != nil { 46 return mem, fmt.Errorf("cannot read meminfo file: %s", err.Error()) 47 } 48 49 var found bool 50 mem, found, err = ByteFromProcFileData(meminfo, memType) 51 if err != nil { 52 return mem, fmt.Errorf("cannot get the memory amount for %s: %s", memType, err.Error()) 53 } 54 55 if !found { 56 return mem, fmt.Errorf("cannot get the memory amount for %s", memType) 57 } 58 59 return 60} 61 62// ReadAll reads all data from a file. Returns an error if there is an issue with reading the file or 63// writing the output. 64func ReadAll(filename string) (data []byte, err error) { 65 fd, err := syscall.Open(filename, syscall.O_RDONLY, 0) 66 if err != nil { 67 return 68 } 69 defer syscall.Close(fd) 70 var buf bytes.Buffer 71 b := make([]byte, 2048) 72 for { 73 var n int 74 if n, err = syscall.Read(fd, b); err != nil { 75 if errors.Is(err, syscall.EINTR) { 76 continue 77 } 78 return 79 } 80 81 if n == 0 { 82 return buf.Bytes(), nil 83 } 84 if _, err = buf.Write(b[:n]); err != nil { 85 return 86 } 87 } 88} 89 90// ByteFromProcFileData returns the value in bytes of the provided value name from the provided 91// process file data. Returns true if the value is found, and false if it is not or if there is an 92// error. Returns an error if there is an issue with parsing values. 93func ByteFromProcFileData(data []byte, valueName string) (uint64, bool, error) { 94 for _, line := range strings.Split(string(data), "\n") { 95 i := strings.Index(line, ":") 96 if i < 0 || valueName != line[:i] { 97 continue 98 } 99 100 line = line[i+1:] 101 if len(line) < 3 { 102 continue 103 } 104 105 v, err := strconv.ParseUint(strings.TrimSpace(line[:len(line)-2]), 10, 64) 106 if err != nil { 107 return 0, false, err 108 } 109 110 switch line[len(line)-2:] { 111 case "kB": 112 v *= kB 113 case "mB": 114 v *= mB 115 case "GB": 116 v *= gB 117 case "TB": 118 v *= tB 119 default: 120 return 0, false, errors.New("cannot resolve value type") 121 } 122 return v, true, nil 123 } 124 125 return 0, false, nil 126} 127