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_meminfo_file_poll.c
32 * @brief Adds ability for data collection from /proc/meminfo
33 *
34 * File contains methods for searching and polling data from
35 * "/proc/meminfo"
36 */
37
38 #include <stdio.h>
39 #include <stdint.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <inttypes.h>
43 #include "datatop_interface.h"
44 #include "datatop_fileops.h"
45 #include "datatop_str.h"
46
47 #define DTOP_MEM_SIZE 8192
48 #define DTOP_MEM_LINE (DTOP_MEM_SIZE>>2)
49
50 /**
51 * @struct dtop_meminfo_vars
52 * @brief Struct used to hold necessary variables for /proc/meminfo dpg
53 *
54 * @var dtop_meminfo_vars::line
55 * Array of strings where necessary dp names and values are held.
56 * @var dtop_meminfo_vars::line_count
57 * Number of lines the file is that the dpg represents.
58 */
59 struct dtop_meminfo_vars {
60 char **line;
61 int line_count;
62 };
63
64 /**
65 * @brief Parses lines with data in "/proc/meminfo"
66 *
67 * @param line1 Line to parse to find datapoint names and values.
68 * @param len1 Length of line1.
69 * @param l Index in the dictionary the key/value pair is added to.
70 * @param dict Dictionary the keys and values are added to.
71 */
dt_meminfo_parse(char * line1,int len1,int l,struct dt_procdict * dict)72 int dt_meminfo_parse(char *line1, int len1,
73 int l, struct dt_procdict *dict)
74 {
75 int i, k, n;
76 if (len1 < 1)
77 return 0;
78
79 if (line1 == 0 || dict == 0)
80 return 0;
81
82 k = l;
83 dict->key[k] = &line1[0];
84 for (i = 0; i < len1 && k < DTOP_DICT_SIZE; i++) {
85 if (line1[i] == ' ' || line1[i] == ' ') {
86 line1[i] = 0;
87 n = i+1;
88 while (line1[n] == ' ' || line1[n] == ' ')
89 n++;
90 dict->val[k] = &line1[n];
91 while (line1[n] != ' ')
92 n++;
93 line1[n] = 0;
94 break;
95 }
96 }
97 k++;
98 dict->max = k;
99 return k;
100 }
101
102 /**
103 * @brief Stores the data collected from a "/proc/meminfo"
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_meminfo_poll(struct dtop_data_point_gatherer * dpg)109 int dtop_meminfo_poll(struct dtop_data_point_gatherer *dpg)
110 {
111 char *data;
112 int *line_len = malloc(sizeof(int) *
113 ((struct dtop_meminfo_vars *)
114 (dpg->priv))->line_count);
115 int read;
116 struct dt_procdict dict;
117 int i, j, n, sum;
118
119 read = dt_read_file(dpg->file, &data, DTOP_MEM_SIZE);
120 if (read == 0 || data == 0)
121 return DTOP_POLL_IO_ERR;
122
123 sum = 0;
124 /* Assigns each line read from the file, a length */
125 for (n = 0; n < ((struct dtop_meminfo_vars *)
126 (dpg->priv))->line_count; n++) {
127 line_len[n] = dt_read_line(((struct dtop_meminfo_vars *)
128 (dpg->priv))->line[n],
129 DTOP_MEM_LINE, data,
130 DTOP_MEM_SIZE, sum);
131 if (n <= (((struct dtop_meminfo_vars *)
132 (dpg->priv))->line_count - 1)) {
133 sum += (line_len[n] + 1);
134 }
135
136 }
137
138 /* Stores dp names and values in dictionary */
139 for (i = 0; i < dpg->data_points_len; i++)
140 dt_meminfo_parse(((struct dtop_meminfo_vars *)
141 (dpg->priv))->line[i], line_len[i], i, &dict);
142
143 /* Assigns the dp value to the dp struct */
144 for (j = 0; j < dpg->data_points_len; j++) {
145 i = dt_find_dict_idx(dpg->data_points[j].name, &dict);
146 if (i >= 0 && i < dict.max) {
147 sscanf(dict.val[i], "%" PRIu64,
148 &(dpg->data_points[i].data.d_ulong));
149 dpg->data_points[i].data.d_ulong *= 1024;
150 if (dpg->data_points[i].
151 initial_data_populated == NOT_POPULATED) {
152 dpg->data_points[i].initial_data.d_ulong
153 = dpg->data_points[i].data.d_ulong;
154 dpg->data_points[i].initial_data_populated
155 = POPULATED;
156 }
157 }
158 }
159
160 dt_free(&data);
161 free(line_len);
162 return DTOP_POLL_OK;
163 }
164
165 /**
166 * @brief Frees dynamically allocated "/proc/meminfo" dpg.
167 *
168 * Frees the memory of the dpg along with it's data_points
169 * and other malloc'd memory no longer needed.
170 *
171 * @param dpg Dpg to deconstruct and deallocate memory for.
172 */
dtop_meminfo_dpg_deconstructor(struct dtop_data_point_gatherer * dpset)173 static void dtop_meminfo_dpg_deconstructor
174 (struct dtop_data_point_gatherer *dpset)
175 {
176 int i;
177 free(dpset->data_points);
178 for (i = 0; i < ((struct dtop_meminfo_vars *)
179 (dpset->priv))->line_count; i++)
180 free(((struct dtop_meminfo_vars *)(dpset->priv))->line[i]);
181 free(((struct dtop_meminfo_vars *)(dpset->priv))->line);
182 free(((struct dtop_meminfo_vars *)(dpset->priv)));
183 free(dpset);
184 }
185
186 /**
187 * @brief Creates a dpg for "/proc/meminfo" 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_meminfo_vars struct that holds relevant dpg variables.
194 */
construct_meminfo_file_dpg(struct dtop_data_point * data_points,struct dtop_meminfo_vars * storage)195 static void construct_meminfo_file_dpg(struct dtop_data_point
196 *data_points, struct dtop_meminfo_vars *storage)
197 {
198 struct dtop_data_point_gatherer *dpg = malloc
199 (sizeof(struct dtop_data_point_gatherer));
200 dpg->prefix = "/proc/meminfo";
201 dpg->file = "/proc/meminfo";
202 dpg->poll = dtop_meminfo_poll;
203 dpg->data_points = data_points;
204 dpg->priv = (struct dtop_meminfo_vars *)storage;
205 dpg->data_points_len = storage->line_count;
206 dpg->deconstruct = dtop_meminfo_dpg_deconstructor;
207
208 dtop_register(dpg);
209 }
210
211 /**
212 * @brief Scans "/proc/meminfo in order to autodetect dps.
213 *
214 * Searches through "/proc/meminfo" file for all available data
215 * points to create as dp structs.
216 *
217 * @param storage dtop_meminfo_vars struct where relevant variables are stored.
218 */
dtop_meminfo_search(struct dtop_meminfo_vars * storage)219 int dtop_meminfo_search(struct dtop_meminfo_vars *storage)
220 {
221 int i, k, n, sum;
222 char *data;
223 int *line_len = malloc(sizeof(int) * storage->line_count);
224 int read;
225 struct dt_procdict dict;
226 struct dtop_data_point *data_points;
227
228 storage->line = malloc(storage->line_count * sizeof(*storage->line));
229
230 for (i = 0; i < storage->line_count; i++)
231 storage->line[i] = malloc(sizeof(char) * DTOP_MEM_LINE);
232
233 read = dt_read_file("/proc/meminfo", &data, DTOP_MEM_SIZE);
234 if (read == 0 || data == 0)
235 return DTOP_POLL_IO_ERR;
236
237 sum = 0;
238 /* Assigns each line read from the file, a length */
239 for (n = 0; n < storage->line_count; n++) {
240 line_len[n] = dt_read_line(storage->line[n],
241 DTOP_MEM_LINE, data,
242 DTOP_MEM_SIZE, sum);
243 if (n < (storage->line_count - 1))
244 sum += (line_len[n] + 1);
245 }
246
247 /* Stores dp names in dictionary */
248 for (i = 0; i < (storage->line_count); i++)
249 dt_parse_proc_same_line_key_and_val(storage->line[i],
250 line_len[i], i, &dict);
251
252 data_points = malloc
253 (storage->line_count * sizeof(struct dtop_data_point));
254
255 k = 0;
256 /* Creates a dtop_data_point struct for each dp found in the file */
257 for (i = 0; i < dict.max; i++) {
258 data_points[i].name = dict.key[i];
259 data_points[i].prefix = NULL;
260 data_points[i].type = DTOP_ULONG;
261 k++;
262 }
263
264 /* Calls dpg constructor, dpg will point to the dp struct */
265 construct_meminfo_file_dpg(data_points, storage);
266
267 free(line_len);
268 dt_free(&data);
269
270 return DTOP_POLL_OK;
271 }
272
273 /**
274 * @brief Calls dtop_search for "/proc/meminfo" file.
275 */
dtop_meminfo_init(void)276 void dtop_meminfo_init(void)
277 {
278 struct dtop_meminfo_vars *storage = malloc
279 (sizeof(struct dtop_meminfo_vars));
280 storage->line_count = dtop_get_file_line_amount("/proc/meminfo");
281 dtop_meminfo_search(storage);
282 }
283