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 */
dt_dev_parse(char * line1,int len1,int index,struct dt_procdict * dict)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 */
dtop_dev_poll(struct dtop_data_point_gatherer * dpg)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 */
dtop_dev_dpg_deconstructor(struct dtop_data_point_gatherer * dpset)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 */
construct_dev_file_dpg(struct dtop_dev_vars * storage,int dp_count,struct dtop_data_point * data_points)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 */
dtop_dev_search(char * name,struct dtop_dev_vars * storage)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 */
dtop_dev_init(void)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