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