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