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_gen_poll.c
32  * @brief Contains functions which add ability to scan directories for data points.
33  *
34  * Contains functions that search through a directory and create dpg's for any
35  * important data values found which can then be polled for data collection.
36  */
37 
38 #include <unistd.h>
39 #include <stdio.h>
40 #include <dirent.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 
47 #include "datatop_interface.h"
48 #include "datatop_fileops.h"
49 #include "datatop_str.h"
50 #include "datatop_gen_poll.h"
51 
52 #define DTOP_GEN_SIZE 8192
53 #define DTOP_GEN_LINE (DTOP_GEN_SIZE>>2)
54 
55 /**
56  * @brief Searches a file to find the number of data values it contains.
57  *
58  * @param dpg The struct which contains the file to search.
59  * @return Number of datapoints found in the file.
60  */
get_number_of_values(struct dtop_data_point_gatherer * dpg)61 static int get_number_of_values(struct dtop_data_point_gatherer *dpg)
62 {
63 	char *data;
64 	int read;
65 	char line[DTOP_GEN_LINE];
66 	int line_len;
67 	int i, num;
68 
69 	read = dt_read_file(dpg->file, &data, DTOP_GEN_SIZE);
70 	line_len = dt_read_line(line, DTOP_GEN_LINE, data, DTOP_GEN_SIZE, 0);
71 
72 	if (read == 0) {
73 		return 0;
74 	}
75 
76 	if (line_len < 1) {
77 		dt_free(&data);
78 		return 0;
79 	}
80 
81 	num = 1;
82 	for (i = 0; i < line_len; i++) {
83 		if ((line[i] == ' ' || line[i] == ','
84 		    || line[i] == '	') &&line[i+1] != 0)
85 			num++;
86 	}
87 
88 	dt_free(&data);
89 	return num;
90 }
91 
92 /**
93  * @brief Stores the data collected from a dpg that was constructed during dtop_search.
94  *
95  * @param dpg Struct that polled data is added to.
96  * @return DTOP_POLL_IO_ERR - Poll of dpg unsuccessful.
97  * @return DTOP_POLL_OK - Poll of dpg successful.
98  */
dtop_gen_poll(struct dtop_data_point_gatherer * dpg)99 int dtop_gen_poll(struct dtop_data_point_gatherer *dpg)
100 {
101 	char *data;
102 	int read;
103 	char line[DTOP_GEN_LINE];
104 	int line_len;
105 	struct dt_procdict dict;
106 	int i;
107 
108 	read = dt_read_file(dpg->file, &data, DTOP_GEN_SIZE);
109 	line_len = dt_read_line(line, DTOP_GEN_LINE, data, DTOP_GEN_SIZE, 0);
110 
111 	if (read == 0 || data == 0)
112 		return DTOP_POLL_IO_ERR;
113 
114 	dt_single_line_parse(line, line_len, &dict);
115 
116 	for (i = 0; i < dpg->data_points_len; i++) {
117 		if (dict.val[i][0] == '-')
118 			dpg->data_points[i].type = DTOP_LONG;
119 		dtop_store_dp(&(dpg->data_points[i]), dict.val[i]);
120 	}
121 
122 	dt_free(&data);
123 	return DTOP_POLL_OK;
124 }
125 
126 /**
127  * @brief Frees dynamically allocated dpg's.
128  *
129  * Frees the memory of dpg variables and the dpg for all dynamically allocated
130  * dpgs.
131  *
132  * @param dpg Dpg to deconstruct and deallocate memory for.
133  */
dtop_gen_dpg_deconstructor(struct dtop_data_point_gatherer * dpset)134 static void dtop_gen_dpg_deconstructor(struct dtop_data_point_gatherer *dpset)
135 {
136 	int i;
137 	for (i = 0; i < dpset->data_points_len; i++)
138 		free(dpset->data_points[i].name);
139 	free(dpset->data_points);
140 	free(dpset->file);
141 	free(dpset->prefix);
142 	free(dpset);
143 }
144 
145 /**
146  * @brief Creates a dpg and all necessary dp's corresponding to it.
147  *
148  * Dynamically allocates memory for dpg and dp structs which are then
149  * created and added to a linked_list of dpgs through the dtop_register
150  * function.
151  *
152  * @param dir Directory which file is located in, assigned to the dpg prefix.
153  * @param name Name of file that dpg represents, assigned to a dp name.
154  */
dpg_construction(char * dir,char * name)155 static void dpg_construction(char *dir, char *name)
156 {
157 	int num, i;
158 	int both_len = strlen(dir) + strlen(name) + 1;
159 	char *both = malloc(both_len);
160 	char *maindir;
161 	struct dtop_data_point_gatherer *dpg = malloc
162 	       (sizeof(struct dtop_data_point_gatherer));
163 	strlcpy(both, dir, both_len);
164 	strlcat(both, name, both_len);
165 	maindir = malloc(strlen(dir) + 1);
166 	strlcpy(maindir, dir, strlen(dir) + 1);
167 
168 	dpg->prefix = maindir;
169 	dpg->file = both;
170 	dpg->poll = dtop_gen_poll;
171 	dpg->deconstruct = dtop_gen_dpg_deconstructor;
172 	num = get_number_of_values(dpg);
173 
174 	if (num != 0) {
175 		struct dtop_data_point *dp = malloc
176 		       (num * sizeof(struct dtop_data_point));
177 		for (i = 0; i < num; i++) {
178 			if (num == 1) {
179 				dp[i].name = malloc(strlen(name) + 1);
180 				strlcpy(dp[i].name, name, strlen(name) + 1);
181 			} else {
182 				char *add = malloc(7 * sizeof(char));
183 				char *newname;
184 				int nn_len, dpn_len;
185 				snprintf(add, 7 * sizeof(char), "[%d]:", i);
186 				nn_len = strlen(name) + strlen(add) + 1;
187 				newname = malloc(nn_len);
188 				strlcpy(newname, name, nn_len);
189 				strlcat(newname, add, nn_len);
190 				dpn_len = strlen(newname) + 1;
191 				dp[i].name = malloc(dpn_len);
192 				strlcpy(dp[i].name, newname, dpn_len);
193 				free(add);
194 				free(newname);
195 			}
196 			dp[i].prefix = NULL;
197 			dp[i].type = DTOP_ULONG;
198 			dp[i].skip = DO_NOT_SKIP;
199 			dp[i].initial_data_populated = NOT_POPULATED;
200 		}
201 
202 		dpg->data_points = dp;
203 		dpg->data_points_len = num;
204 
205 		dtop_register(dpg);
206 	} else {
207 		free(dpg->prefix);
208 		free(dpg->file);
209 		free(dpg);
210 	}
211 }
212 
213 /**
214  * @brief Scans a directory for all important datapoints to be collected.
215  *
216  * Recursively scans a directory and locates all files which data will be
217  * collected from.
218  *
219  * @param dir Directory to search.
220  */
dtop_search(char * dir)221 static int dtop_search(char *dir)
222 {
223 	DIR *dp;
224 	struct dirent *entry;
225 	struct stat s;
226 	char cwd[1024];
227 
228 	if (!getcwd(cwd, sizeof(cwd))) {
229 		fprintf(stderr, "Failed to get current working dir\n");
230 		return -1;
231 	}
232 
233 	dp = opendir(dir);
234 	if (dp == NULL) {
235 		fprintf(stderr, "err=%d: %s\n", errno, strerror(errno));
236 		fprintf(stderr, "Cannot open directory: %s\n", dir);
237 		return DIR_FAILURE;
238 	}
239 
240 	chdir(dir);
241 
242 	while ((entry = readdir(dp))) {
243 		if (stat(entry->d_name, &s)) {
244 			printf("stat err=%d: %s\n", errno, strerror(errno));
245 			return DIR_FAILURE;
246 		}
247 
248 		if (strcmp(".", entry->d_name) != 0 &&
249 		   strcmp("..", entry->d_name) != 0 &&
250 		   S_ISREG(s.st_mode)) {
251 
252 			dpg_construction(dir, entry->d_name);
253 
254 		} else if (strcmp(".", entry->d_name) != 0 &&
255 			strcmp("..", entry->d_name) != 0 &&
256 			S_ISDIR(s.st_mode)) {
257 			int nd_len = strlen(dir) + strlen(entry->d_name) + 2;
258 			char *newdir = malloc(nd_len);
259 			strlcpy(newdir, dir, nd_len);
260 			strlcat(newdir, entry->d_name, nd_len);
261 			strlcat(newdir, "/", nd_len);
262 			dtop_search(newdir);
263 			free(newdir);
264 		}
265 	}
266 
267 	closedir(dp);
268 	chdir(cwd);
269 	return DIR_SUCCESS;
270 }
271 
272 /**
273  * @brief Calls dtop_search for any specified directory.
274  *
275  * @param dir Directory to search.
276  */
dtop_gen_init(char * dir)277 void dtop_gen_init(char *dir)
278 {
279 	dtop_search(dir);
280 }
281