]> git.itanic.dy.fi Git - rrdd/blob - built_in_parsers.c
8d7bdb15c1ca9760246e8bd83630b9b0318cac51
[rrdd] / built_in_parsers.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 #include "parser.h"
6 #include "process.h"
7 #include "string.h"
8 #include "debug.h"
9 #include "utils.h"
10 #include "built_in_parsers.h"
11
12 #define STATFILE "/proc/stat"
13
14 static int cpu_parser(char *data, const char **p)
15 {
16         char buf[1024];
17         char *str = buf;
18         FILE *file = fopen(STATFILE, "r");
19         long long user, nice, sys, idle, wait, irq, softirq;
20
21         if (file == NULL) {
22                 pr_err("Failed to open file %s\n", STATFILE);
23                 return -1;
24         }
25
26         if (!fgets(buf, sizeof(buf), file)) {
27                 pr_err("Failed to read file %s\n", STATFILE);
28                 fclose(file);
29                 return -1;
30         }
31
32         user    = dec_to_longlong(str, &str);
33         nice    = dec_to_longlong(str, &str);
34         sys     = dec_to_longlong(str, &str);
35         idle    = dec_to_longlong(str, &str);
36         wait    = dec_to_longlong(str, &str);
37         irq     = dec_to_longlong(str, &str);
38         softirq = dec_to_longlong(str, &str);
39
40         snprintf(data, RRD_DATA_MAX_LEN, "%lld:%lld:%lld:%lld:%lld:%lld:%lld",
41                 user, nice, sys, idle, wait, irq, softirq);
42
43         fclose(file);
44         return 0;
45 }
46
47 #define MEMFILE "/proc/meminfo"
48
49 static int mem_parser(char *data, const char **p)
50 {
51         char buf[1024], word[1024];
52         int free = 0, buffered = 0, cache = 0, active = 0, inactive = 0,
53                 swapfree = 0, anon = 0, slab = 0, tables = 0, other = 0,
54                 swaptotal = 0, total = 0;
55         FILE *file = fopen(MEMFILE, "r");
56
57         if (file == NULL) {
58                 pr_err("Failed to open file %s\n", MEMFILE);
59                 return -1;
60         }
61
62         while (fgets(buf, sizeof(buf), file)) {
63                 get_word(buf, 0, word, sizeof(word));
64
65                 if (!strcmp(word, "MemFree:")) {
66                         free = dec_to_int(buf, NULL);
67                 } else if (!strcmp(word, "MemTotal:")) {
68                         total = dec_to_int(buf, NULL);
69                 } else if (!strcmp(word, "Buffers:")) {
70                         buffered = dec_to_int(buf, NULL);
71                 } else if (!strcmp(word, "Cached:")) {
72                         cache = dec_to_int(buf, NULL);
73                 } else if (!strcmp(word, "Active:")) {
74                         active = dec_to_int(buf, NULL);
75                 } else if (!strcmp(word, "Inactive:")) {
76                         inactive = dec_to_int(buf, NULL);
77                 } else if (!strcmp(word, "SwapFree:")) {
78                         swapfree = dec_to_int(buf, NULL);
79                 } else if (!strcmp(word, "AnonPages:")) {
80                         anon = dec_to_int(buf, NULL);
81                 } else if (!strcmp(word, "Slab:")) {
82                         slab = dec_to_int(buf, NULL);
83                 } else if (!strcmp(word, "PageTables:")) {
84                         tables = dec_to_int(buf, NULL);
85                 } else if (!strcmp(word, "SwapTotal:")) {
86                         swaptotal = dec_to_int(buf, NULL);
87                 }
88         }
89         fclose(file);
90
91         other = total - free - buffered - cache - anon - slab - tables;
92
93         snprintf(data, RRD_DATA_MAX_LEN, "%f:%f:%f:%f:%f:%f:%f:%f:%f:%f:%f",
94                 free / 1024.0,
95                 buffered / 1024.0,
96                 cache / 1024.0,
97                 active / 1024.0,
98                 inactive / 1024.0,
99                 swapfree / 1024.0,
100                 anon / 1024.0,
101                 slab / 1024.0,
102                 tables / 1024.0,
103                 other / 1024.0,
104                 (swaptotal - swapfree) / 1024.0);
105
106         return 0;
107 }
108
109 int cpu_mem_parser(char *data, const char **p)
110 {
111         char cpu[RRD_DATA_MAX_LEN], mem[RRD_DATA_MAX_LEN];
112
113         cpu_parser(cpu, p);
114         mem_parser(mem, p);
115         snprintf(data, RRD_DATA_MAX_LEN, "%s:%s", cpu, mem);
116
117         return 0;
118 }
119
120 static int digitemp_parser(char *data, const char **p)
121 {
122         const char digitemp_cmd[] = "/usr/bin/digitemp";
123         char *const digitemp_args[] = { "", "-o2", "-a", "-q", 0 };
124         FILE *readf;
125         int pid, ret;
126         float t1 = 0, t2 = 0, t3 = 0;
127         char buf[1024];
128
129         pid = run_piped_stream(digitemp_cmd, digitemp_args, 0, &readf, 0);
130         if (pid < 0) {
131                 pr_err("Failed to parse digitemp\n");
132                 sprintf(data, "U:U");
133                 return -1;
134         }
135
136         ret = fscanf(readf, "%f %f %f", &t1, &t2, &t3);
137
138         if (ret != 3) {
139                 pr_err("Failed to parse digitemp output: %m\n");
140                 sprintf(data, "U:U");
141                 return 1;
142         }
143
144         t2 += 2.16;
145         t3 += -0.44;
146
147         /* Read whatever the process might be still printing out */
148         while (fgets(buf, 1024, readf));
149
150         harvest_zombies(pid);
151         snprintf(data, RRD_DATA_MAX_LEN, "%.2f:%.2f", t3, t2);
152         return 0;
153 }
154
155 static int digitemp_parser_mod(char *data, const char **p)
156 {
157         char buf[1024];
158         int ret;
159
160         ret = digitemp_parser(buf, p);
161         snprintf(data, RRD_DATA_MAX_LEN, "U:%s", buf);
162
163         return ret;
164 }
165
166 /* Run a command and feed the output from stdout directly to rrdtool */
167 static int script_parser(char *rrd_data, const char **parser_data)
168 {
169         FILE *readf;
170         int pid, ret;
171         void *tmp = parser_data;
172         char **cmd = tmp;
173
174         pid = run_piped_stream(cmd[0], &cmd[1], NULL, &readf, NULL);
175         ret = fread(rrd_data, 1, RRD_DATA_MAX_LEN - 1, readf);
176         if (ret < 0) {
177                 pr_err("Error on read: %m\n");
178                 goto err_read;
179         }
180
181         rrd_data[ret] = 0;
182         pr_info("Read %d bytes :%s\n", ret, rrd_data);
183
184 err_read:
185         fclose(readf);
186
187         harvest_zombies(pid);
188
189         return 0;
190 }
191
192 struct iface_stats {
193         long long rx_bytes;
194         long long rx_packets;
195         long long tx_bytes;
196         long long tx_packets;
197 };
198
199 #define PROC_NETDEV     "/proc/net/dev"
200
201 static int get_iface_stats(const char *iface, struct iface_stats *stat)
202 {
203         FILE *netdev;
204         char buf[1024];
205         char if_name[16];
206         char *str;
207         int error;
208
209         netdev = fopen(PROC_NETDEV, "r");
210
211         if (netdev == NULL) {
212                 error = errno;
213                 pr_err("Failed to open file %s: %d (%m)\n",
214                         PROC_NETDEV, error);
215                 return error;
216         }
217
218         while (fgets(buf, sizeof(buf), netdev)) {
219                 get_word(buf, &str, if_name, sizeof(if_name));
220
221                 /* Remove the ':' at the end of the if_name */
222                 if_name[strlen(if_name) - 1] = 0;
223                 if (strncmp(iface, if_name, sizeof(if_name)))
224                         continue;
225
226                 stat->rx_bytes          = dec_to_longlong(str, &str);
227                 stat->rx_packets        = dec_to_longlong(str, &str);
228                 /* errs */                dec_to_longlong(str, &str);
229                 /* drop */                dec_to_longlong(str, &str);
230                 /* fifo */                dec_to_longlong(str, &str);
231                 /* frame */               dec_to_longlong(str, &str);
232                 /* compressed */          dec_to_longlong(str, &str);
233                 /* multicast */           dec_to_longlong(str, &str);
234                 stat->tx_bytes          = dec_to_longlong(str, &str);
235                 stat->tx_packets        = dec_to_longlong(str, &str);
236
237                 pr_info("rx_b %lld rx_p %lld tx_b %lld tx_p %lld\n",
238                         stat->rx_bytes, stat->rx_packets,
239                         stat->tx_bytes, stat->tx_packets);
240
241                 return 0;
242         }
243
244         pr_err("Interface %s not found\n", iface);
245         return -ENODEV;
246 }
247
248 int netstats_parser(char *rrd_data, const char **parser_data)
249 {
250         struct iface_stats stat;
251         const char **iface_name = parser_data;
252         int max_str = RRD_DATA_MAX_LEN;
253         int ret;
254
255         if (!parser_data) {
256                 pr_err("No device names specified\n");
257                 return -1;
258         }
259
260         while(*iface_name) {
261                 pr_info("getting data for iface %s\n", *iface_name);
262                 ret = get_iface_stats(*iface_name, &stat);
263
264                 if (!ret) {
265                         ret = snprintf(rrd_data, max_str, "%lld:%lld:%lld:%lld",
266                                 stat.rx_bytes, stat.rx_packets,
267                                 stat.tx_bytes, stat.tx_packets);
268                 } else {
269                         ret = snprintf(rrd_data, max_str, "U:U:U:U");
270                 }
271
272                 max_str -= ret;
273                 rrd_data += ret;
274
275                 iface_name++;
276                 if (!*iface_name)
277                         break;
278
279                 ret = snprintf(rrd_data, max_str, ":");
280                 max_str -= ret;
281                 rrd_data += ret;
282         }
283
284         return 0;
285 }
286
287 static struct parser_info built_in_parsers[] = {
288         {
289                 .name = "cpu",
290                 .parse = cpu_parser,
291         },
292         {
293                 .name = "mem",
294                 .parse = mem_parser,
295         },
296         {
297                 .name = "cpu_mem",
298                 .parse = cpu_mem_parser,
299         },
300         {
301                 .name = "digitemp",
302                 .parse = digitemp_parser,
303         },
304         {
305                 .name = "digitemp_mod",
306                 .parse = digitemp_parser_mod,
307         },
308         {
309                 .name = "script",
310                 .parse = script_parser,
311         },
312         {
313                 .name = "netstats",
314                 .parse = netstats_parser,
315         },
316 };
317
318 int register_built_in_parsers(void)
319 {
320         int i, ret;
321
322         for (i = 0; i < ARRAY_SIZE(built_in_parsers); i++) {
323                 ret = register_parser(&built_in_parsers[i]);
324
325                 if (ret)
326                         break;
327         }
328
329         return ret;
330 }