Home | History | Annotate | Download | only in src
      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_stat_poll.c
     32  * @brief Adds ability for data collection from /proc/stat
     33  *
     34  * File contains methods for searching and polling data from
     35  * "/proc/stat"
     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_STAT_SIZE 16384
     46 #define DTOP_STAT_LINE (DTOP_STAT_SIZE>>2)
     47 
     48 /**
     49 * @struct dtop_stat_vars
     50 * @brief Struct used to hold necessary variables for /proc/stat dpg
     51 *
     52 * @var dtop_stat_vars::line
     53 * Array of strings where necessary dp names and values are held.
     54 * @var dtop_stat_vars::line_count
     55 * Number of lines the file is that the dpg represents.
     56 */
     57 struct dtop_stat_vars {
     58 	char **line;
     59 	int line_count;
     60 };
     61 
     62 /**
     63  * @brief Parses lines with data in "/proc/stat"
     64  *
     65  * @param line1 Line to parse to find datapoint names and values.
     66  * @param len1 Length of line1.
     67  * @param n_index Index in the dictionary the key (name) is added to.
     68  * @param v_index Index in the dictionary the value is added to.
     69  * @param dict Dictionary the keys and values are added to.
     70  */
     71 static int dt_stat_parse(char *line1, int len1,
     72 			int n_index, int v_index, struct dt_procdict *dict)
     73 {
     74 	int i, k, j, start = 0;
     75 	if (len1 < 1)
     76 		return 0;
     77 
     78 	if (line1 == 0 || dict == 0)
     79 		return 0;
     80 
     81 	dict->key[n_index] = &line1[0];
     82 	for (i = 0; i < len1; i++) {
     83 		if (line1[i] == ' ') {
     84 			line1[i] = 0;
     85 			start = (i+1);
     86 			break;
     87 		}
     88 	}
     89 
     90 	k = v_index;
     91 	for (i = start; i < len1 && k < DTOP_DICT_SIZE; i++) {
     92 		if (line1[i] != ' ') {
     93 			dict->val[k] = &line1[i];
     94 			for (j = i; j < len1; j++) {
     95 				if (line1[j] == ' ') {
     96 					line1[j] = 0;
     97 					break;
     98 				}
     99 			}
    100 			i = j;
    101 			k++;
    102 		}
    103 	}
    104 
    105 	dict->max = k;
    106 	return k;
    107 }
    108 
    109 /**
    110  * @brief Stores the data collected from "/proc/stat"
    111  *
    112  * @param dpg Struct that polled data is added to.
    113  * @return DTOP_POLL_IO_ERR - Poll of dpg unsuccessful.
    114  * @return DTOP_POLL_OK - Poll of dpg successful.
    115  */
    116 int dtop_stat_poll(struct dtop_data_point_gatherer *dpg)
    117 {
    118 	char *data;
    119 	int *line_len = malloc(sizeof(int) *
    120 			((struct dtop_stat_vars *)
    121 			(dpg->priv))->line_count);
    122 	int read;
    123 	struct dt_procdict dict;
    124 	int i, n, sum;
    125 	int dp_count = 0;
    126 
    127 	read = dt_read_file(dpg->file, &data, DTOP_STAT_SIZE);
    128 	if (read == 0 || data == 0)
    129 		return DTOP_POLL_IO_ERR;
    130 
    131 	sum = 0;
    132 	/* Assigns each line read from the file, a length */
    133 	for (n = 0; n < ((struct dtop_stat_vars *)
    134 				(dpg->priv))->line_count; n++) {
    135 		line_len[n] = dt_read_line(((struct dtop_stat_vars *)
    136 					(dpg->priv))->line[n],
    137 					   DTOP_STAT_LINE, data,
    138 					   DTOP_STAT_SIZE, sum);
    139 		if (n <= (((struct dtop_stat_vars *)
    140 			(dpg->priv))->line_count - 1)) {
    141 			sum += (line_len[n] + 1);
    142 		}
    143 
    144 	}
    145 
    146 	/* Stores dp names and values in dictionary */
    147 	for (i = 0; i < ((struct dtop_stat_vars *)(dpg->priv))->line_count; i++)
    148 		dp_count = dt_stat_parse(((struct dtop_stat_vars *)
    149 			(dpg->priv))->line[i], line_len[i], i, dp_count, &dict);
    150 
    151 	/* Assigns the dp value to the dp struct */
    152 	for (n = 0; n < dp_count; n++) {
    153 		dtop_store_dp(&(dpg->data_points[n]),
    154 				dict.val[n]);
    155 	}
    156 
    157 	dt_free(&data);
    158 	free(line_len);
    159 	return DTOP_POLL_OK;
    160 }
    161 
    162 /**
    163  * @brief Frees dynamically allocated "/proc/stat" dpg.
    164  *
    165  * Frees the memory of the dpg along with it's data_points
    166  * and other malloc'd memory no longer needed.
    167  *
    168  * @param dpg Dpg to deconstruct and deallocate memory for.
    169  */
    170 static void dtop_stat_dpg_deconstructor
    171 			(struct dtop_data_point_gatherer *dpset)
    172 {
    173 	int i;
    174 	for (i = 0; i < dpset->data_points_len; i++)
    175 		free(dpset->data_points[i].name);
    176 	free(dpset->data_points);
    177 	for (i = 0; i < ((struct dtop_stat_vars *)
    178 				(dpset->priv))->line_count; i++)
    179 		free(((struct dtop_stat_vars *)(dpset->priv))->line[i]);
    180 	free(((struct dtop_stat_vars *)(dpset->priv))->line);
    181 	free(((struct dtop_stat_vars *)(dpset->priv)));
    182 
    183 	free(dpset);
    184 }
    185 
    186 /**
    187  * @brief Creates a dpg for "/proc/stat" 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_stat_vars struct that holds relevant dpg variables.
    194  * @param dp_count Number of data_points in data_points array
    195  */
    196 static void construct_stat_file_dpg(struct dtop_data_point
    197 		*data_points, struct dtop_stat_vars *storage, int dp_count)
    198 {
    199 	struct dtop_data_point_gatherer *dpg = malloc
    200 		(sizeof(struct dtop_data_point_gatherer));
    201 	dpg->prefix = "/proc/stat";
    202 	dpg->file = "/proc/stat";
    203 	dpg->poll = dtop_stat_poll;
    204 	dpg->data_points = data_points;
    205 	dpg->priv = (struct dtop_stat_vars *)storage;
    206 	dpg->data_points_len = dp_count;
    207 	dpg->deconstruct = dtop_stat_dpg_deconstructor;
    208 
    209 	dtop_register(dpg);
    210 }
    211 
    212 /**
    213  * @brief Scans "/proc/stat" in order to autodetect dps.
    214  *
    215  * Searches through "/proc/stat" file for all available data
    216  * points to create as dp structs.
    217  *
    218  * @param storage dtop_stat_vars struct where relevant variables are stored.
    219  */
    220 int dtop_stat_search(struct dtop_stat_vars *storage)
    221 {
    222 	int i, n, sum;
    223 	char *data;
    224 	int *line_len = malloc(sizeof(int) * storage->line_count);
    225 	int read;
    226 	struct dt_procdict dict;
    227 	int dp_count = 0;
    228 	int end;
    229 	int *dp_per_line;
    230 	struct dtop_data_point *data_points;
    231 	int count = 0;
    232 
    233 	storage->line = malloc(storage->line_count * sizeof(*storage->line));
    234 
    235 	for (i = 0; i < storage->line_count; i++)
    236 		storage->line[i] = malloc(sizeof(char) * DTOP_STAT_LINE);
    237 
    238 	read = dt_read_file("/proc/stat", &data, DTOP_STAT_SIZE);
    239 	if (read == 0 || data == 0)
    240 		return DTOP_POLL_IO_ERR;
    241 
    242 	sum = 0;
    243 	/* Assigns each line read from the file, a length */
    244 	for (n = 0; n < storage->line_count; n++) {
    245 		line_len[n] = dt_read_line(storage->line[n],
    246 					   DTOP_STAT_LINE, data,
    247 					   DTOP_STAT_SIZE, sum);
    248 		if (n < (storage->line_count - 1))
    249 			sum += (line_len[n] + 1);
    250 	}
    251 
    252 	dp_per_line = malloc(sizeof(int) * (storage->line_count));
    253 	/* Stores dp names in dictionary */
    254 
    255 	for (i = 0; i < (storage->line_count); i++) {
    256 		end = dp_count;
    257 		dp_count = dt_stat_parse(storage->line[i],
    258 				line_len[i], i, dp_count, &dict);
    259 		dp_per_line[i] = (dp_count - end);
    260 	}
    261 
    262 	data_points = malloc(dp_count * sizeof(struct dtop_data_point));
    263 
    264 	for (i = 0; i < (storage->line_count); i++) {
    265 		for (n = 0; n < dp_per_line[i]; n++) {
    266 			if (dp_per_line[i] == 1) {
    267 				int dk_len = strlen(dict.key[i]) + 1;
    268 				int dp_len;
    269 				char *newname = malloc(dk_len);
    270 				strlcpy(newname, dict.key[i], dk_len);
    271 				dp_len = strlen(newname) + 1;
    272 				data_points[count].name = malloc(dp_len);
    273 				strlcpy(data_points[count].name, newname,
    274 					dp_len);
    275 				free(newname);
    276 			} else {
    277 				char *add = malloc(15 * sizeof(char));
    278 				char *newname;
    279 				int nn_len, dpn_len;
    280 				snprintf(add, 15 * sizeof(char), "[%d]:", n);
    281 				nn_len = strlen(dict.key[i]) + strlen(add) + 1;
    282 				newname = malloc(nn_len);
    283 				strlcpy(newname, dict.key[i], nn_len);
    284 				strlcat(newname, add, nn_len);
    285 				dpn_len = strlen(newname) + 1;
    286 				data_points[count].name = malloc(dpn_len);
    287 				strlcpy(data_points[count].name, newname,
    288 					dpn_len);
    289 				free(newname);
    290 				free(add);
    291 			}
    292 			data_points[count].prefix = NULL;
    293 			data_points[count].type = DTOP_ULONG;
    294 			data_points[count].initial_data_populated
    295 						= NOT_POPULATED;
    296 			data_points[count].skip = DO_NOT_SKIP;
    297 			count++;
    298 		}
    299 	}
    300 
    301 	/* Calls dpg constructor, dpg will point to the dp struct */
    302 	construct_stat_file_dpg(data_points, storage, dp_count);
    303 	free(dp_per_line);
    304 	free(line_len);
    305 	dt_free(&data);
    306 
    307 	return DTOP_POLL_OK;
    308 }
    309 
    310 /**
    311  * @brief Calls dtop_search for "/proc/stat" file.
    312  */
    313 void dtop_stat_init(void)
    314 {
    315 	struct dtop_stat_vars *storage = malloc
    316 			(sizeof(struct dtop_stat_vars));
    317 	storage->line_count = dtop_get_file_line_amount("/proc/stat");
    318 	dtop_stat_search(storage);
    319 }
    320