1 /************************************************************************ 2 Copyright (c) 2015, The Linux Foundation. All rights reserved. 3 4 Redistribution and use in source and binary forms, with or without 5 modification, are permitted provided that the following conditions are 6 met: 7 * Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 * Redistributions in binary form must reproduce the above 10 copyright notice, this list of conditions and the following 11 disclaimer in the documentation and/or other materials provided 12 with the distribution. 13 * Neither the name of The Linux Foundation nor the names of its 14 contributors may be used to endorse or promote products derived 15 from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 ************************************************************************/ 29 30 /** 31 * @file datatop_meminfo_file_poll.c 32 * @brief Adds ability for data collection from /proc/meminfo 33 * 34 * File contains methods for searching and polling data from 35 * "/proc/meminfo" 36 */ 37 38 #include <stdio.h> 39 #include <stdint.h> 40 #include <string.h> 41 #include <stdlib.h> 42 #include <inttypes.h> 43 #include "datatop_interface.h" 44 #include "datatop_fileops.h" 45 #include "datatop_str.h" 46 47 #define DTOP_MEM_SIZE 8192 48 #define DTOP_MEM_LINE (DTOP_MEM_SIZE>>2) 49 50 /** 51 * @struct dtop_meminfo_vars 52 * @brief Struct used to hold necessary variables for /proc/meminfo dpg 53 * 54 * @var dtop_meminfo_vars::line 55 * Array of strings where necessary dp names and values are held. 56 * @var dtop_meminfo_vars::line_count 57 * Number of lines the file is that the dpg represents. 58 */ 59 struct dtop_meminfo_vars { 60 char **line; 61 int line_count; 62 }; 63 64 /** 65 * @brief Parses lines with data in "/proc/meminfo" 66 * 67 * @param line1 Line to parse to find datapoint names and values. 68 * @param len1 Length of line1. 69 * @param l Index in the dictionary the key/value pair is added to. 70 * @param dict Dictionary the keys and values are added to. 71 */ 72 int dt_meminfo_parse(char *line1, int len1, 73 int l, struct dt_procdict *dict) 74 { 75 int i, k, n; 76 if (len1 < 1) 77 return 0; 78 79 if (line1 == 0 || dict == 0) 80 return 0; 81 82 k = l; 83 dict->key[k] = &line1[0]; 84 for (i = 0; i < len1 && k < DTOP_DICT_SIZE; i++) { 85 if (line1[i] == ' ' || line1[i] == ' ') { 86 line1[i] = 0; 87 n = i+1; 88 while (line1[n] == ' ' || line1[n] == ' ') 89 n++; 90 dict->val[k] = &line1[n]; 91 while (line1[n] != ' ') 92 n++; 93 line1[n] = 0; 94 break; 95 } 96 } 97 k++; 98 dict->max = k; 99 return k; 100 } 101 102 /** 103 * @brief Stores the data collected from a "/proc/meminfo" 104 * 105 * @param dpg Struct that polled data is added to. 106 * @return DTOP_POLL_IO_ERR - Poll of dpg unsuccessful. 107 * @return DTOP_POLL_OK - Poll of dpg successful. 108 */ 109 int dtop_meminfo_poll(struct dtop_data_point_gatherer *dpg) 110 { 111 char *data; 112 int *line_len = malloc(sizeof(int) * 113 ((struct dtop_meminfo_vars *) 114 (dpg->priv))->line_count); 115 int read; 116 struct dt_procdict dict; 117 int i, j, n, sum; 118 119 read = dt_read_file(dpg->file, &data, DTOP_MEM_SIZE); 120 if (read == 0 || data == 0) 121 return DTOP_POLL_IO_ERR; 122 123 sum = 0; 124 /* Assigns each line read from the file, a length */ 125 for (n = 0; n < ((struct dtop_meminfo_vars *) 126 (dpg->priv))->line_count; n++) { 127 line_len[n] = dt_read_line(((struct dtop_meminfo_vars *) 128 (dpg->priv))->line[n], 129 DTOP_MEM_LINE, data, 130 DTOP_MEM_SIZE, sum); 131 if (n <= (((struct dtop_meminfo_vars *) 132 (dpg->priv))->line_count - 1)) { 133 sum += (line_len[n] + 1); 134 } 135 136 } 137 138 /* Stores dp names and values in dictionary */ 139 for (i = 0; i < dpg->data_points_len; i++) 140 dt_meminfo_parse(((struct dtop_meminfo_vars *) 141 (dpg->priv))->line[i], line_len[i], i, &dict); 142 143 /* Assigns the dp value to the dp struct */ 144 for (j = 0; j < dpg->data_points_len; j++) { 145 i = dt_find_dict_idx(dpg->data_points[j].name, &dict); 146 if (i >= 0 && i < dict.max) { 147 sscanf(dict.val[i], "%" PRIu64, 148 &(dpg->data_points[i].data.d_ulong)); 149 dpg->data_points[i].data.d_ulong *= 1024; 150 if (dpg->data_points[i]. 151 initial_data_populated == NOT_POPULATED) { 152 dpg->data_points[i].initial_data.d_ulong 153 = dpg->data_points[i].data.d_ulong; 154 dpg->data_points[i].initial_data_populated 155 = POPULATED; 156 } 157 } 158 } 159 160 dt_free(&data); 161 free(line_len); 162 return DTOP_POLL_OK; 163 } 164 165 /** 166 * @brief Frees dynamically allocated "/proc/meminfo" dpg. 167 * 168 * Frees the memory of the dpg along with it's data_points 169 * and other malloc'd memory no longer needed. 170 * 171 * @param dpg Dpg to deconstruct and deallocate memory for. 172 */ 173 static void dtop_meminfo_dpg_deconstructor 174 (struct dtop_data_point_gatherer *dpset) 175 { 176 int i; 177 free(dpset->data_points); 178 for (i = 0; i < ((struct dtop_meminfo_vars *) 179 (dpset->priv))->line_count; i++) 180 free(((struct dtop_meminfo_vars *)(dpset->priv))->line[i]); 181 free(((struct dtop_meminfo_vars *)(dpset->priv))->line); 182 free(((struct dtop_meminfo_vars *)(dpset->priv))); 183 free(dpset); 184 } 185 186 /** 187 * @brief Creates a dpg for "/proc/meminfo" file 188 * 189 * Dynamically allocates memory for dpg which is then added to a linked list 190 * via the dtop_register(dpg) function call. 191 * 192 * @param data_points dtop_data_point struct that dpg points to. 193 * @param storage dtop_meminfo_vars struct that holds relevant dpg variables. 194 */ 195 static void construct_meminfo_file_dpg(struct dtop_data_point 196 *data_points, struct dtop_meminfo_vars *storage) 197 { 198 struct dtop_data_point_gatherer *dpg = malloc 199 (sizeof(struct dtop_data_point_gatherer)); 200 dpg->prefix = "/proc/meminfo"; 201 dpg->file = "/proc/meminfo"; 202 dpg->poll = dtop_meminfo_poll; 203 dpg->data_points = data_points; 204 dpg->priv = (struct dtop_meminfo_vars *)storage; 205 dpg->data_points_len = storage->line_count; 206 dpg->deconstruct = dtop_meminfo_dpg_deconstructor; 207 208 dtop_register(dpg); 209 } 210 211 /** 212 * @brief Scans "/proc/meminfo in order to autodetect dps. 213 * 214 * Searches through "/proc/meminfo" file for all available data 215 * points to create as dp structs. 216 * 217 * @param storage dtop_meminfo_vars struct where relevant variables are stored. 218 */ 219 int dtop_meminfo_search(struct dtop_meminfo_vars *storage) 220 { 221 int i, k, n, sum; 222 char *data; 223 int *line_len = malloc(sizeof(int) * storage->line_count); 224 int read; 225 struct dt_procdict dict; 226 struct dtop_data_point *data_points; 227 228 storage->line = malloc(storage->line_count * sizeof(*storage->line)); 229 230 for (i = 0; i < storage->line_count; i++) 231 storage->line[i] = malloc(sizeof(char) * DTOP_MEM_LINE); 232 233 read = dt_read_file("/proc/meminfo", &data, DTOP_MEM_SIZE); 234 if (read == 0 || data == 0) 235 return DTOP_POLL_IO_ERR; 236 237 sum = 0; 238 /* Assigns each line read from the file, a length */ 239 for (n = 0; n < storage->line_count; n++) { 240 line_len[n] = dt_read_line(storage->line[n], 241 DTOP_MEM_LINE, data, 242 DTOP_MEM_SIZE, sum); 243 if (n < (storage->line_count - 1)) 244 sum += (line_len[n] + 1); 245 } 246 247 /* Stores dp names in dictionary */ 248 for (i = 0; i < (storage->line_count); i++) 249 dt_parse_proc_same_line_key_and_val(storage->line[i], 250 line_len[i], i, &dict); 251 252 data_points = malloc 253 (storage->line_count * sizeof(struct dtop_data_point)); 254 255 k = 0; 256 /* Creates a dtop_data_point struct for each dp found in the file */ 257 for (i = 0; i < dict.max; i++) { 258 data_points[i].name = dict.key[i]; 259 data_points[i].prefix = NULL; 260 data_points[i].type = DTOP_ULONG; 261 k++; 262 } 263 264 /* Calls dpg constructor, dpg will point to the dp struct */ 265 construct_meminfo_file_dpg(data_points, storage); 266 267 free(line_len); 268 dt_free(&data); 269 270 return DTOP_POLL_OK; 271 } 272 273 /** 274 * @brief Calls dtop_search for "/proc/meminfo" file. 275 */ 276 void dtop_meminfo_init(void) 277 { 278 struct dtop_meminfo_vars *storage = malloc 279 (sizeof(struct dtop_meminfo_vars)); 280 storage->line_count = dtop_get_file_line_amount("/proc/meminfo"); 281 dtop_meminfo_search(storage); 282 } 283