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_dev_poll.c 32 * @brief Adds ability for data collection from /proc/net/dev 33 * 34 * File contains methods for searching and polling data from 35 * "/proc/net/dev" 36 */ 37 38 #include <stdio.h> 39 #include <string.h> 40 #include <stdlib.h> 41 #include "datatop_interface.h" 42 #include "datatop_fileops.h" 43 #include "datatop_str.h" 44 45 #define DTOP_DEV_SIZE 8192 46 #define DTOP_DEV_LINE (DTOP_DEV_SIZE>>2) 47 48 /** 49 * @struct dtop_dev_vars 50 * @brief Struct used to hold necessary variables for /proc/net/dev dpg 51 * 52 * @var dtop_dev_vars::line 53 * Array of strings where necessary dp names and values are held. 54 * @var dtop_dev_vars::line_count 55 * Number of lines the file is that the dpg represents. 56 */ 57 struct dtop_dev_vars { 58 char **line; 59 int line_count; 60 }; 61 62 /** 63 * @brief Parses lines with data in "/proc/net/dev" 64 * 65 * @param line1 Line to parse to find datapoint names and values. 66 * @param len1 Length of line1. 67 * @param index Index in the dictionary the key (name) is added to. 68 * @param dict Dictionary the keys and values are added to. 69 */ 70 static void dt_dev_parse(char *line1, int len1, 71 int index, struct dt_procdict *dict) 72 { 73 int i, start = 0; 74 int j, k, n; 75 i = 0; 76 while (line1[i] == ' ' || line1[i] == ' ') 77 i++; 78 dict->key[index] = &line1[i]; 79 for (i = 0; i < len1; i++) { 80 if (line1[i] == ':') { 81 line1[i+1] = 0; 82 start = i+2; 83 break; 84 } 85 } 86 87 k = 0; 88 for (j = start; j < len1; j++) { 89 if (line1[j] != ' ' && line1[j] != ' ') { 90 dict->val[k] = &line1[j]; 91 n = j; 92 while (line1[n] != ' ' && line1[n] != ' ') 93 n++; 94 if (n < len1) 95 line1[n] = 0; 96 j = n; 97 k++; 98 } 99 } 100 } 101 102 /** 103 * @brief Stores the data collected from "/proc/net/dev" 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_dev_poll(struct dtop_data_point_gatherer *dpg) 110 { 111 char *data; 112 int *line_len = malloc(sizeof(int) * 113 ((struct dtop_dev_vars *) 114 (dpg->priv))->line_count); 115 int read; 116 struct dt_procdict *dict = malloc(sizeof(struct dt_procdict) 117 *((struct dtop_dev_vars *) 118 (dpg->priv))->line_count-2); 119 int j, n, sum; 120 int index = 0; 121 int dp = 0; 122 123 read = dt_read_file(dpg->file, &data, DTOP_DEV_SIZE); 124 if (read == 0 || data == 0) 125 return DTOP_POLL_IO_ERR; 126 127 sum = 0; 128 /* Assigns each line read from the file, a length */ 129 for (n = 0; n < ((struct dtop_dev_vars *) 130 (dpg->priv))->line_count; n++) { 131 line_len[n] = dt_read_line(((struct dtop_dev_vars *) 132 (dpg->priv))->line[n], 133 DTOP_DEV_LINE, data, 134 DTOP_DEV_SIZE, sum); 135 if (n <= (((struct dtop_dev_vars *) 136 (dpg->priv))->line_count - 1)) { 137 sum += (line_len[n] + 1); 138 } 139 140 } 141 142 for (n = 2; n < ((struct dtop_dev_vars *) 143 (dpg->priv))->line_count; n++) { 144 dt_dev_parse(((struct dtop_dev_vars *) 145 (dpg->priv))->line[n], line_len[n], 146 index, &dict[index]); 147 index++; 148 } 149 150 151 /* Assigns the dp value to the dp struct */ 152 for (n = 2; n < ((struct dtop_dev_vars *) 153 (dpg->priv))->line_count; n++) { 154 for (j = 0; j < 16; j++) { 155 dtop_store_dp(&(dpg->data_points[dp]), 156 dict[n-2].val[j]); 157 dp++; 158 } 159 } 160 161 dt_free(&data); 162 free(line_len); 163 free(dict); 164 return DTOP_POLL_OK; 165 } 166 167 /** 168 * @brief Frees dynamically allocated "/proc/net/dev" dpg. 169 * 170 * Frees the memory of the dpg along with it's data_points 171 * and other malloc'd memory no longer needed. 172 * 173 * @param dpg Dpg to deconstruct and deallocate memory for. 174 */ 175 static void dtop_dev_dpg_deconstructor 176 (struct dtop_data_point_gatherer *dpset) 177 { 178 int i, j, dp; 179 dp = 0; 180 for (j = 0; j < ((((struct dtop_dev_vars *) 181 (dpset->priv))->line_count)-2); j++) { 182 for (i = 0; i < 16; i++) { 183 free(dpset->data_points[dp].prefix); 184 dp++; 185 } 186 } 187 free(dpset->data_points); 188 for (i = 0; i < ((struct dtop_dev_vars *) 189 (dpset->priv))->line_count; i++) 190 free(((struct dtop_dev_vars *)(dpset->priv))->line[i]); 191 free(((struct dtop_dev_vars *)(dpset->priv))->line); 192 free(((struct dtop_dev_vars *)(dpset->priv))); 193 free(dpset); 194 } 195 196 /** 197 * @brief Creates a dpg for "/proc/net/dev" file 198 * 199 * Dynamically allocates memory for dpg which is then added to a linked list 200 * via the dtop_register(dpg) function call. 201 * 202 * @param data_points dtop_data_point struct that dpg points to. 203 * @param storage dtop_dev_vars struct that holds relevant dpg variables. 204 */ 205 static void construct_dev_file_dpg(struct dtop_dev_vars *storage, 206 int dp_count, struct dtop_data_point *data_points) 207 { 208 struct dtop_data_point_gatherer *dpg = malloc 209 (sizeof(struct dtop_data_point_gatherer)); 210 211 dpg->prefix = "/proc/net/dev"; 212 dpg->file = "/proc/net/dev"; 213 dpg->poll = dtop_dev_poll; 214 dpg->data_points = data_points; 215 dpg->priv = (struct dtop_dev_vars *)storage; 216 dpg->data_points_len = dp_count; 217 dpg->deconstruct = dtop_dev_dpg_deconstructor; 218 219 dtop_register(dpg); 220 } 221 222 /** 223 * @brief Scans "/proc/net/dev in order to autodetect dps. 224 * 225 * Searches through "/proc/net/dev" file for all available data 226 * points to create as dp structs. 227 * 228 * @param name This is the file name "/proc/net/dev" passed in by dtop_dev_init 229 * @param storage dtop_dev_vars struct where relevant variables are stored. 230 */ 231 int dtop_dev_search(char *name, struct dtop_dev_vars *storage) 232 { 233 int i, n, sum; 234 char *data; 235 int *line_len = malloc(sizeof(int) * storage->line_count); 236 int read; 237 struct dt_procdict dict; 238 struct dt_procdict dev_dict; 239 struct dtop_data_point *data_points = malloc 240 (sizeof(struct dtop_data_point) * 16 * (storage->line_count-2)); 241 int dp_count = (16 * (storage->line_count - 2)); 242 int index = 0; 243 int dp = 0; 244 245 storage->line = malloc(storage->line_count * sizeof(*storage->line)); 246 247 for (i = 0; i < storage->line_count; i++) 248 storage->line[i] = malloc(sizeof(char) * DTOP_DEV_LINE); 249 250 dev_dict.val[0] = "bytes"; 251 dev_dict.val[1] = "packets"; 252 dev_dict.val[2] = "errs"; 253 dev_dict.val[3] = "drop"; 254 dev_dict.val[4] = "fifo"; 255 dev_dict.val[5] = "frame"; 256 dev_dict.val[6] = "compressed"; 257 dev_dict.val[7] = "multicast"; 258 dev_dict.val[8] = "bytes"; 259 dev_dict.val[9] = "packets"; 260 dev_dict.val[10] = "errs"; 261 dev_dict.val[11] = "drop"; 262 dev_dict.val[12] = "fifo"; 263 dev_dict.val[13] = "colls"; 264 dev_dict.val[14] = "carrier"; 265 dev_dict.val[15] = "compressed"; 266 267 read = dt_read_file(name, &data, DTOP_DEV_SIZE); 268 if (read == 0 || data == 0) 269 return DTOP_POLL_IO_ERR; 270 271 sum = 0; 272 /* Assigns each line read from the file, a length */ 273 for (n = 0; n < storage->line_count; n++) { 274 line_len[n] = dt_read_line(storage->line[n], 275 DTOP_DEV_LINE, data, 276 DTOP_DEV_SIZE, sum); 277 if (n < (storage->line_count - 1)) 278 sum += (line_len[n] + 1); 279 } 280 281 construct_dev_file_dpg(storage, dp_count, data_points); 282 283 for (n = 2; n < storage->line_count; n++) { 284 dt_dev_parse(storage->line[n], line_len[n], index, &dict); 285 index++; 286 } 287 288 for (n = 2; n < storage->line_count; n++) { 289 for (i = 0; i < 16; i++) { 290 char *pref = malloc(30 * sizeof(char)); 291 data_points[dp].skip = 0; 292 data_points[dp].initial_data_populated = NOT_POPULATED; 293 if (i < 8) 294 strlcpy(pref, "Receive:", 30 * sizeof(char)); 295 else if (i >= 8) 296 strlcpy(pref, "Transmit:", 30 * sizeof(char)); 297 strlcat(pref, dev_dict.val[i], 30 * sizeof(char)); 298 data_points[dp].prefix = pref; 299 data_points[dp].name = dict.key[n-2]; 300 data_points[dp].type = DTOP_ULONG; 301 dp++; 302 } 303 index++; 304 } 305 306 free(line_len); 307 dt_free(&data); 308 return DTOP_POLL_OK; 309 } 310 311 /** 312 * @brief Calls dtop_search for "/proc/net/dev" file. 313 */ 314 void dtop_dev_init(void) 315 { 316 struct dtop_dev_vars *storage = malloc 317 (sizeof(struct dtop_dev_vars)); 318 storage->line_count = dtop_get_file_line_amount("/proc/net/dev"); 319 dtop_dev_search("/proc/net/dev", storage); 320 } 321