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_helpers.c
32  * @brief Contains functions which output data.
33  *
34  * Contains functions which are used for printing data to output streams.
35  * Handles all formatting for data output. Also contains functions which
36  * are responsible for data gathering and collection.
37  */
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdint.h>
42 #include <time.h>
43 #include <sys/time.h>
44 #include <string.h>
45 #include <errno.h>
46 #include "datatop_interface.h"
47 #include "datatop_linked_list.h"
48 #include "datatop_fileops.h"
49 
50 /**
51  * @brief Prints the name and prefix of a datapoint.
52  *
53  * @param dp Dp whose name and prefix is printed.
54  * @param prefix Directory where dp is contained.
55  * @param fw File to print the information to.
56  * @return FILE_ERROR - Writing to file was unsuccessful.
57  * @return FILE_SUCCESS - Writing to file was successful.
58  */
dtop_format_dp_names(struct dtop_data_point * dp,const char * prefix,FILE * fw)59 static int dtop_format_dp_names(struct dtop_data_point *dp, const char
60 						*prefix, FILE *fw)
61 {
62 	if (dp->prefix) {
63 		if (fprintf(fw, "\"%s:%s:%s\",", prefix, dp->prefix,
64 							dp->name) < 0)
65 			return FILE_ERROR;
66 	} else {
67 		if (fprintf(fw, "\"%s::%s\",", prefix, dp->name) < 0)
68 			return FILE_ERROR;
69 	}
70 	return FILE_SUCCESS;
71 }
72 
73 /**
74  * @brief Prints the value of a datapoint.
75  *
76  * Checks the type of the value and will print it accordingly.
77  *
78  * @param dp Pointer to the data_point struct which holds the value that will
79  *           be printed.
80  * @param fw File to print the information to.
81  * @return FILE_ERROR - Writing to file was unsuccessful.
82  * @return FILE_SUCCESS - Writing to file was successful.
83  */
dtop_format_dp_values(struct dtop_data_point * dp,FILE * fw)84 static int dtop_format_dp_values(struct dtop_data_point *dp, FILE *fw)
85 {
86 	switch (dp->type) {
87 	case DTOP_ULONG:
88 		if (fprintf(fw, "%"PRIu64, dp->data.d_ulong) < 0)
89 			return FILE_ERROR;
90 	break;
91 	case DTOP_LONG:
92 		if (fprintf(fw, "%"PRId64, dp->data.d_long) < 0)
93 			return FILE_ERROR;
94 	break;
95 	case DTOP_UINT:
96 		if (fprintf(fw, "%d", dp->data.d_uint) < 0)
97 			return FILE_ERROR;
98 	break;
99 	case DTOP_INT:
100 		if (fprintf(fw, "%u", dp->data.d_uint) < 0)
101 			return FILE_ERROR;
102 	break;
103 	case DTOP_UCHAR:
104 		if (fprintf(fw, "%c,", dp->data.d_uchar) < 0)
105 			return FILE_ERROR;
106 		if (fprintf(fw, "(0x%02X)", dp->data.d_uchar) < 0)
107 			return FILE_ERROR;
108 	break;
109 	case DTOP_CHAR:
110 		if (fprintf(fw, "%c,", dp->data.d_char) < 0)
111 			return FILE_ERROR;
112 		if (fprintf(fw, "(%d)", dp->data.d_char) < 0)
113 			return FILE_ERROR;
114 	break;
115 	case DTOP_STR:
116 		if (fprintf(fw, "\"%s\"", dp->data.d_str) < 0)
117 			return FILE_ERROR;
118 	break;
119 	default:
120 		if (fprintf(fw, "UNKNOWN_TYPE") < 0)
121 			return FILE_ERROR;
122 	break;
123 	}
124 	return FILE_SUCCESS;
125 }
126 
127 /**
128  * @brief Prints the name and prefix of a dp, formatted appropriately.
129  *
130  * @param dpset data_point_gatherer used to access dp directory.
131  * @param dp data_point used to get datapoint prefix if available.
132  */
dtop_format_text_for_snapshot(struct dtop_data_point_gatherer * dpset,struct dtop_data_point dp)133 static void dtop_format_text_for_snapshot
134 	(struct dtop_data_point_gatherer *dpset, struct dtop_data_point dp)
135 {
136 	printf("%s:", dpset->prefix);
137 	if (dp.prefix)
138 		printf("%s:", dp.prefix);
139 
140 	printf("%s::", dp.name);
141 }
142 
143 /**
144  * @brief Prints a datapoint value to a specified csv file.
145  *
146  * @param dp Datapoint that holds the value to be printed.
147  * @param fw File to print to.
148  * @return FILE_ERROR - Writing to file was unsuccessful.
149  * @return FILE_SUCCESS - Writing to file was successful.
150  */
dtop_print_dp_csv(struct dtop_data_point * dp,FILE * fw)151 static int dtop_print_dp_csv(struct dtop_data_point *dp, FILE *fw)
152 {
153 	if (dtop_format_dp_values(dp, fw) == FILE_ERROR)
154 		return FILE_ERROR;
155 	if (fprintf(fw, ",") < 0)
156 		return FILE_ERROR;
157 	return FILE_SUCCESS;
158 }
159 
160 /**
161  * @brief Prints a datapoint value to the terminal.
162  *
163  * @param dp Holds the value to be printed print.
164  * @param prefix Used to print prefix of the data_point.
165  */
dtop_print_dp(struct dtop_data_point * dp,const char * prefix)166 static void dtop_print_dp(struct dtop_data_point *dp, const char *prefix)
167 {
168 	dtop_format_dp_names(dp, prefix, stdout);
169 	printf(" ");
170 	dtop_format_dp_values(dp, stdout);
171 	printf("\n");
172 }
173 
174 /**
175  * @brief Finds delta(value) of a datapoint.
176  *
177  * Function accounts for different types that values may be.
178  *
179  * @param dpset Pointer to a data_point used as another parameter for printing.
180  * @param dp Datapoint which contains the value to find the difference of.
181  */
dtop_handle_dp_type_for_snapshot(struct dtop_data_point_gatherer * dpset,struct dtop_data_point dp)182 static void dtop_handle_dp_type_for_snapshot(
183 	struct dtop_data_point_gatherer *dpset, struct dtop_data_point dp)
184 {
185 	int64_t int64;
186 
187 	switch (dp.type) {
188 	case DTOP_ULONG:
189 	default:
190 		/* This is less than ideal. Replace with 128-bit ops later */
191 		int64 = (int64_t)dp.data.d_ulong
192 			- (int64_t)dp.initial_data.d_ulong;
193 		if (int64 != 0) {
194 			dtop_format_text_for_snapshot(dpset, dp);
195 			printf("%"PRId64"\n", int64);
196 		}
197 	break;
198 
199 	case DTOP_LONG:
200 		/* This is less than ideal. Replace with 128-bit ops later */
201 		int64 = (int64_t)dp.data.d_long
202 			- (int64_t)dp.initial_data.d_long;
203 		if (int64 != 0) {
204 			dtop_format_text_for_snapshot(dpset, dp);
205 			printf("%"PRId64"\n", int64);
206 		}
207 	break;
208 
209 	case DTOP_UINT:
210 		int64 = (int64_t)dp.data.d_uint
211 			- (int64_t)dp.initial_data.d_uint;
212 		if (int64 != 0) {
213 			dtop_format_text_for_snapshot(dpset, dp);
214 			printf("%"PRId64"\n", int64);
215 		}
216 	break;
217 
218 	case DTOP_INT:
219 		int64 = (int64_t)dp.data.d_int
220 			- (int64_t)dp.initial_data.d_int;
221 		if (int64 != 0) {
222 			dtop_format_text_for_snapshot(dpset, dp);
223 			printf("%"PRId64"\n", int64);
224 		}
225 	break;
226 	}
227 }
228 
229 /**
230  * @brief Calls the dtop_print_dp_csv function for each data_point a dpg has access to.
231  *
232  * @param dpg A data_point_gatherer struct that is iterated through for each datapoint.
233  * @param fw File to print datapoint values to.
234  * @return FILE_ERROR - Writing to file was unsuccessful.
235  * @return FILE_SUCCESS - Writing to file was successful.
236  */
dtop_print_dpg_csv(struct dtop_data_point_gatherer * dpg,FILE * fw)237 static int dtop_print_dpg_csv(struct dtop_data_point_gatherer *dpg, FILE *fw)
238 {
239 	int i;
240 
241 	for (i = 0; i < dpg->data_points_len; i++)
242 		if (dtop_print_dp_csv(&(dpg->data_points[i]), fw) == FILE_ERROR)
243 			return FILE_ERROR;
244 	return FILE_SUCCESS;
245 }
246 
247 /**
248  * @brief Calls the dtop_format_dp_names function for each data_point a dpg has access to.
249  *
250  * @param dpg A data_point_gatherer struct that is iterated through for each datapoint.
251  * @param fw File to printg datapoint names and prefixes to.
252  * @return FILE_ERROR - Writing to file was unsuccessful.
253  * @return FILE_SUCCESS - Writing to file was successful.
254  */
dtop_print_dpg_names_csv(struct dtop_data_point_gatherer * dpg,FILE * fw)255 int dtop_print_dpg_names_csv(struct dtop_data_point_gatherer *dpg, FILE *fw)
256 {
257 	int i;
258 
259 	for (i = 0; i < dpg->data_points_len; i++)
260 		if (dtop_format_dp_names(&(dpg->data_points[i]),
261 		dpg->prefix, fw) == FILE_ERROR)
262 			return FILE_ERROR;
263 
264 	return FILE_SUCCESS;
265 }
266 
267 /**
268  * @brief Prints all dp values to a specified file.
269  *
270  * This function is responsible for the printing of all data_point values
271  * to a specified file. It will iterate through the linked list which contains
272  * all of the dpgs and will print each dp value, being sure to flush the buffer.
273  *
274  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
275  * @param fw File that data prints to.
276  * @return FILE_ERROR - Writing to file was unsuccessful.
277  * @return FILE_SUCCESS - Writing to file was successful.
278  */
dtop_write_pollingdata_csv(struct dtop_linked_list * dpg_list,FILE * fw)279 int dtop_write_pollingdata_csv(struct dtop_linked_list *dpg_list, FILE *fw)
280 {
281 	struct dtop_linked_list *curr_ptr = dpg_list;
282 	struct dtop_data_point_gatherer *dpset;
283 
284 	while (curr_ptr) {
285 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
286 		if (dtop_print_dpg_csv(dpset, fw) == FILE_ERROR)
287 			return FILE_ERROR;
288 		curr_ptr = curr_ptr->next_ptr;
289 		fflush(fw);
290 	}
291 
292 	if (fprintf(fw, "\n") < 0)
293 		return FILE_ERROR;
294 
295 	return FILE_SUCCESS;
296 }
297 
298 /**
299  * @brief Calls the dtop_print_dp function for each data_point a dpg has access to.
300  *
301  * @param dpg A data_point_gatherer struct that is iterated through for each datapoint.
302  */
dtop_print_dpg(struct dtop_data_point_gatherer * dpg)303 void dtop_print_dpg(struct dtop_data_point_gatherer *dpg)
304 {
305 	int i;
306 	for (i = 0; i < dpg->data_points_len; i++)
307 		dtop_print_dp(&(dpg->data_points[i]), dpg->prefix);
308 }
309 
310 /**
311  * @brief Stores the values for the datapoints and populates the initial value.
312  *
313  * @param dp A datapoint whose value will be stored.
314  * @param str Str used for sscanf function call to find value of dp.
315  */
dtop_store_dp(struct dtop_data_point * dp,const char * str)316 void dtop_store_dp(struct dtop_data_point *dp, const char *str)
317 {
318 	switch (dp->type) {
319 	case DTOP_ULONG:
320 		sscanf(str, "%"PRIu64, &(dp->data.d_ulong));
321 		if (dp->initial_data_populated == NOT_POPULATED) {
322 			dp->initial_data.d_ulong = dp->data.d_ulong;
323 			dp->initial_data_populated = POPULATED;
324 		}
325 	break;
326 	case DTOP_LONG:
327 		sscanf(str, "%"PRId64, &(dp->data.d_long));
328 		if (dp->initial_data_populated == NOT_POPULATED) {
329 			dp->initial_data.d_long = dp->data.d_long;
330 			dp->initial_data_populated = POPULATED;
331 		}
332 	break;
333 	case DTOP_UINT:
334 		sscanf(str, "%u",  &(dp->data.d_uint));
335 		if (dp->initial_data_populated == NOT_POPULATED) {
336 			dp->initial_data.d_uint = dp->data.d_uint;
337 			dp->initial_data_populated = POPULATED;
338 		}
339 	break;
340 	case DTOP_INT:
341 		sscanf(str, "%d",  &(dp->data.d_int));
342 		if (dp->initial_data_populated == NOT_POPULATED) {
343 			dp->initial_data.d_int = dp->data.d_int;
344 			dp->initial_data_populated = POPULATED;
345 		}
346 	break;
347 	case DTOP_UCHAR:
348 		sscanf(str, "%c",  &(dp->data.d_uchar));
349 		if (dp->initial_data_populated == NOT_POPULATED) {
350 			dp->initial_data.d_uchar = dp->data.d_uchar;
351 			dp->initial_data_populated = POPULATED;
352 		}
353 	break;
354 	case DTOP_CHAR:
355 		sscanf(str, "%c",  &(dp->data.d_char));
356 		if (dp->initial_data_populated == NOT_POPULATED) {
357 			dp->initial_data.d_char = dp->data.d_char;
358 			dp->initial_data_populated = POPULATED;
359 		}
360 	break;
361 	case DTOP_STR:
362 		sscanf(str, "%s",  dp->data.d_str);
363 		if (dp->initial_data_populated == NOT_POPULATED) {
364 			memcpy(dp->initial_data.d_str, dp->data.d_str,
365 			       DTOP_DP_MAX_STR_LEN);
366 			dp->initial_data_populated = POPULATED;
367 		}
368 	break;
369 	default:
370 	break;
371 	}
372 }
373 
374 /**
375  * @brief Responsible for calculating and printing current time to file.
376  *
377  * Prints the time since 1970, in Seconds and Milliseconds.
378  *
379  * @param fw File that time is printed to.
380  * @return FILE_ERROR - Writing to file was unsuccessful.
381  * @return FILE_SUCCESS - Writing to file was successful.
382  */
dtop_print_time_at_poll(FILE * fw)383 int dtop_print_time_at_poll(FILE *fw)
384 {
385 	struct timeval tv;
386 	gettimeofday(&tv, NULL);
387 
388 	if (fprintf(fw, "%10ld", tv.tv_sec) < 0)
389 		return FILE_ERROR;
390 
391 	if (fprintf(fw, ".%06ld,", tv.tv_usec) < 0)
392 		return FILE_ERROR;
393 
394 	return FILE_SUCCESS;
395 }
396 
397 /**
398  * @brief Polls all dp values and updates each value.
399  *
400  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
401  */
dtop_poll(struct dtop_linked_list * dpg_list)402 void dtop_poll(struct dtop_linked_list *dpg_list)
403 {
404 	struct dtop_linked_list *curr_ptr = dpg_list;
405 	struct dtop_data_point_gatherer *dpset;
406 
407 	while (curr_ptr) {
408 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
409 		dpset->poll(dpset);
410 		curr_ptr = curr_ptr->next_ptr;
411 	}
412 }
413 
414 /**
415  * @brief Prints the delta(value) of all data_points to terminal.
416  *
417  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
418  */
dtop_print_snapshot_diff(struct dtop_linked_list * dpg_list)419 void dtop_print_snapshot_diff(struct dtop_linked_list *dpg_list)
420 {
421 	int i;
422 
423 	struct dtop_linked_list *curr_ptr = dpg_list;
424 	struct dtop_data_point_gatherer *dpset;
425 	printf("\n");
426 	printf("Change In Datapoint Values\n");
427 	printf("---------------------------\n");
428 	while (curr_ptr) {
429 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
430 		for (i = 0; i < dpset->data_points_len; i++)
431 			dtop_handle_dp_type_for_snapshot(dpset,
432 					  dpset->data_points[i]);
433 		curr_ptr = curr_ptr->next_ptr;
434 	}
435 	printf("\n");
436 }
437 
438 /**
439  * @brief Resets the initial values of all data_points.
440  *
441  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
442  */
dtop_reset_dp_initial_values(struct dtop_linked_list * dpg_list)443 void dtop_reset_dp_initial_values(struct dtop_linked_list *dpg_list)
444 {
445 	int i;
446 
447 	struct dtop_linked_list *curr_ptr = dpg_list;
448 	struct dtop_data_point_gatherer *dpset;
449 
450 	while (curr_ptr) {
451 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
452 		for (i = 0; i < dpset->data_points_len; i++)
453 			dpset->data_points[i].initial_data_populated
454 							= NOT_POPULATED;
455 		curr_ptr = curr_ptr->next_ptr;
456 	}
457 }
458 
459 /**
460  * @brief Calls deconstructor method for all dpgs dynamically created.
461  *
462  * Checks to see if each dpg created has a deconstructor method. If not null,
463  * function calls the appropiate deconstructor method to deallocate memory.
464  *
465  * @param dpg_list Pointer to first node of linked list which contains all dpgs.
466  */
deconstruct_dpgs(struct dtop_linked_list * dpg_list)467 void deconstruct_dpgs(struct dtop_linked_list *dpg_list)
468 {
469 	struct dtop_linked_list *curr_ptr = dpg_list;
470 	struct dtop_data_point_gatherer *dpset;
471 
472 	while (curr_ptr) {
473 		dpset = (struct dtop_data_point_gatherer *) curr_ptr->data;
474 		if (dpset->deconstruct)
475 			dpset->deconstruct(dpset);
476 		curr_ptr = curr_ptr->next_ptr;
477 	}
478 }
479