]> git.itanic.dy.fi Git - rrdd/blob - rrdtool.c
Merge branch 'master' into itanic
[rrdd] / rrdtool.c
1 #include <time.h>
2
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <string.h>
7
8 #include "rrdtool.h"
9 #include "process.h"
10 #include "parser.h"
11 #include "debug.h"
12 #include "string.h"
13
14 #define MAX_ARGS        512
15 #define ARGSTR_LEN      32768
16
17 #define RRDTOOL_CMD "/usr/bin/rrdtool"
18
19 /*
20  * Add new argument to a argument list
21  *
22  * args         pointer list to arguments
23  * argcnt       argument counter
24  * argstr       array where the actual arguments are stored
25  * idx          index in the argstr where the new argument will be appended
26  */
27 #define add_arg(args, argcnt, argstr, idx, fmt, arg...) \
28         args[argcnt] = argstr + idx;                    \
29         idx += sprintf(argstr + idx, fmt, ##arg);       \
30         argcnt++;                                       \
31         argstr[++idx] = 0
32
33 int rrdtool_draw_image(struct rrd_image *image)
34 {
35         int pid;
36         char cmd[] = RRDTOOL_CMD;
37 //      char cmd[] = "echo";
38         char *args[512], argstr[ARGSTR_LEN];
39         int idx = 0, argcnt = 0, i,j;
40         char timestamp[256];
41         char tmp[256];
42         char tmpfile[256];
43         time_t t = time(0);
44
45         pid = do_fork_limited();
46         if (pid)
47                 return pid;
48
49         pr_info("Drawing image %s\n", image->image_filename);
50
51         tmpfile[0] = 0;
52         strncat(tmpfile, image->image_filename, sizeof(tmp) - strlen(tmp) - 1);
53         strncat(tmpfile, ".tmp", sizeof(tmp) - strlen(tmp) - 1);
54
55         strftime(tmp, 256, "%d.%m.%Y %T (%Z) ", localtime(&t));
56         for (i = 0, j = 0; j < 256;) {
57                 if (tmp[i] == ':') {
58                         timestamp[j++] = '\\';
59                 }
60                 timestamp[j++] = tmp[i++];
61                 if (!tmp[i])
62                         break;
63         }
64         timestamp[j] = 0;
65
66
67         add_arg(args, argcnt, argstr, idx, RRDTOOL_CMD);
68         add_arg(args, argcnt, argstr, idx, "graph");
69         add_arg(args, argcnt, argstr, idx, "%s", tmpfile);
70
71         add_arg(args, argcnt, argstr, idx, "--start");
72         add_arg(args, argcnt, argstr, idx, "%s", image->timestart);
73         add_arg(args, argcnt, argstr, idx, "--end");
74         add_arg(args, argcnt, argstr, idx, "%s", image->timeend);
75         add_arg(args, argcnt, argstr, idx, "--width");
76         add_arg(args, argcnt, argstr, idx, "%d", image->width);
77         add_arg(args, argcnt, argstr, idx, "--height");
78         add_arg(args, argcnt, argstr, idx, "%d", image->height);
79         add_arg(args, argcnt, argstr, idx, "--imgformat");
80         add_arg(args, argcnt, argstr, idx, "%s", image->imageformat);
81
82         for (i = 0; image->options[i]; i++) {
83                 add_arg(args, argcnt, argstr, idx, "%s", image->options[i]);
84         }
85
86         for (i = 0; image->text[i]; i++) {
87                 args[argcnt++] = (char *)image->text[i];
88         }
89
90         add_arg(args, argcnt, argstr, idx, "COMMENT:Last update %s\\c", timestamp);
91
92         args[argcnt] = 0;
93
94         pid = run(cmd, args);
95         harvest_zombies(pid);
96
97         rename(tmpfile, image->image_filename);
98
99         exit(0);
100 }
101
102 int rrdtool_draw_images(struct rrd_image **image)
103 {
104         int i;
105         for (i = 0; image[i]; i++)
106                 rrdtool_draw_image(image[i]);
107
108         return 0;
109 }
110
111 static int sanitize_rrd_update_data(char *data)
112 {
113         char clean_data[RRD_DATA_MAX_LEN];
114         int entries = 0;
115         int minus;
116         char *src, *end, *cln;
117
118         data[RRD_DATA_MAX_LEN - 1] = 0;
119         src = data;
120         cln = clean_data;
121
122         while (src < data + RRD_DATA_MAX_LEN && *src) {
123                 minus = 0;
124                 if (*src == '-') {
125                         src++;
126                         minus = 1;
127                 }
128
129                 end = skip_numbers(src);
130
131                 if (*end == '.') {
132                         end++;
133                         end = skip_numbers(end);
134                 }
135
136                 if (*end == ':' || !*end) {
137                         if (minus) {
138                                 *cln = '-';
139                                 cln++;
140                         }
141                         for (; src <= end; src++, cln++)
142                                 *cln = *src;
143
144                         goto next;
145                 }
146
147                 while (*end != ':' && *end)
148                         end++;
149                 *cln = 'U';
150                 cln++;
151                 *cln = ':';
152                 cln++;
153         next:
154                 end++;
155                 src = end;
156                 entries++;
157         }
158
159         strncpy(data, clean_data, RRD_DATA_MAX_LEN);
160         return entries;
161 }
162
163 int rrdtool_update_data(struct rrd_database *rrd)
164 {
165         int pid;
166         char data[RRD_DATA_MAX_LEN + 2];
167         char cmd[] = RRDTOOL_CMD;
168 //      char cmd[] = "echo";
169         char *const cmdline[] = {
170                 RRDTOOL_CMD,
171                 "update",
172                 (char *const)rrd->filename,
173                 data,
174                 0
175         };
176         int l;
177
178         rrd->last_update = time(0);
179         if (do_fork())
180                 return 0;
181
182         l = sprintf(data, "N:");
183
184         if (rrd->parse) {
185                 rrd->parse(data + l, rrd->parser_data);
186                 sanitize_rrd_update_data(data + l);
187                 pid = run(cmd, cmdline);
188                 harvest_zombies(pid);
189         }
190
191         if (rrd->images)
192                 rrdtool_draw_images(rrd->images);
193
194         while (harvest_zombies(0));
195         exit(0);
196 }
197
198 static int database_exists(struct rrd_database *db)
199 {
200         struct stat s;
201
202         /* If the filename exists, stat will return zero */
203         if (db->filename)
204                 return !stat(db->filename, &s);
205
206         return 0;
207 }
208
209 static int create_database(struct rrd_database *db)
210 {
211         char cmd[] = RRDTOOL_CMD;
212 //      char cmd[] = "echo";
213         char *args[512], argstr[ARGSTR_LEN];
214         int idx = 0, argcnt = 0;
215         int child, i;
216
217         if (!db->filename) {
218                 pr_err("Database %s missing database filename\n", db->name);
219                 return -1;
220         }
221
222         if (!db->sources || !db->archives) {
223                 pr_err("Cannot create db \"%s\", insufficient source data\n",
224                         db->filename);
225                 return -1;
226         }
227
228         add_arg(args, argcnt, argstr, idx, RRDTOOL_CMD);
229         add_arg(args, argcnt, argstr, idx, "create");
230         add_arg(args, argcnt, argstr, idx, "%s", db->filename);
231         add_arg(args, argcnt, argstr, idx, "--step");
232         add_arg(args, argcnt, argstr, idx, "%d", db->interval);
233
234         for (i = 0; db->sources[i].type; i++) {
235                 add_arg(args, argcnt, argstr, idx, "DS:%s:%s:%d:%f:%f",
236                         db->sources[i].name,
237                         db->sources[i].type,
238                         db->sources[i].heartbeat,
239                         db->sources[i].min,
240                         db->sources[i].max);
241         }
242
243         for (i = 0; db->archives[i].type; i++) {
244                 add_arg(args, argcnt, argstr, idx, "RRA:%s:%f:%d:%d",
245                         db->archives[i].type,
246                         db->archives[i].xff,
247                         db->archives[i].steps,
248                         db->archives[i].rows);
249         }
250
251         child = run(cmd, args);
252
253         harvest_zombies(child);
254
255         return 0;
256 }
257
258 int rrdtool_create_missing_databases(struct rrd_database *dbs[])
259 {
260         struct rrd_database *db;
261         int i, ret = 0;
262
263         for (i = 0, db = dbs[i]; db; i++, db = dbs[i]) {
264                 if (database_exists(db)) {
265                         pr_info("database %s found\n", db->filename);
266                         continue;
267                 }
268                 pr_info("Database %s missing, creating\n", db->filename);
269                 ret |= create_database(db);
270         }
271
272         return ret;
273 }