]> git.itanic.dy.fi Git - rrdd/blob - rrdtool.c
rrdtool_draw_image: Avoid corrupting image files
[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         char cmd[] = RRDTOOL_CMD;
36 //      char cmd[] = "echo";
37         char *args[512], argstr[ARGSTR_LEN];
38         int idx = 0, argcnt = 0, i,j;
39         char timestamp[256];
40         char tmp[256];
41         char tmpfile[256];
42         time_t t = time(0);
43
44         pr_info("Drawing image %s\n", image->image_filename);
45
46         tmpfile[0] = 0;
47         strncat(tmpfile, image->image_filename, sizeof(tmp) - strlen(tmp) - 1);
48         strncat(tmpfile, ".tmp", sizeof(tmp) - strlen(tmp) - 1);
49
50         strftime(tmp, 256, "%d.%m.%Y %T (%Z) ", localtime(&t));
51         for (i = 0, j = 0; j < 256;) {
52                 if (tmp[i] == ':') {
53                         timestamp[j++] = '\\';
54                 }
55                 timestamp[j++] = tmp[i++];
56                 if (!tmp[i])
57                         break;
58         }
59         timestamp[j] = 0;
60
61
62         add_arg(args, argcnt, argstr, idx, " ");
63         add_arg(args, argcnt, argstr, idx, "graph");
64         add_arg(args, argcnt, argstr, idx, "%s", tmpfile);
65
66         add_arg(args, argcnt, argstr, idx, "--start");
67         add_arg(args, argcnt, argstr, idx, "%s", image->timestart);
68         add_arg(args, argcnt, argstr, idx, "--end");
69         add_arg(args, argcnt, argstr, idx, "%s", image->timeend);
70         add_arg(args, argcnt, argstr, idx, "--width");
71         add_arg(args, argcnt, argstr, idx, "%d", image->width);
72         add_arg(args, argcnt, argstr, idx, "--height");
73         add_arg(args, argcnt, argstr, idx, "%d", image->height);
74         add_arg(args, argcnt, argstr, idx, "--imgformat");
75         add_arg(args, argcnt, argstr, idx, "%s", image->imageformat);
76
77         for (i = 0; image->options[i]; i++) {
78                 add_arg(args, argcnt, argstr, idx, "%s", image->options[i]);
79         }
80
81         for (i = 0; image->text[i]; i++) {
82                 args[argcnt++] = image->text[i];
83         }
84
85         add_arg(args, argcnt, argstr, idx, "COMMENT:Last update %s\\c", timestamp);
86
87         args[argcnt] = 0;
88
89         run(cmd, args);
90
91         rename(tmpfile, image->image_filename);
92
93         return 0;
94 }
95
96 int rrdtool_draw_images(struct rrd_image **image)
97 {
98         int i;
99         for (i = 0; image[i]; i++)
100                 rrdtool_draw_image(image[i]);
101
102         return 0;
103 }
104
105 static int sanitize_rrd_update_data(char *data)
106 {
107         char clean_data[RRD_DATA_MAX_LEN];
108         int entries = 0;
109         int minus;
110         char *src, *end, *cln;
111
112         data[RRD_DATA_MAX_LEN - 1] = 0;
113         src = data;
114         cln = clean_data;
115
116         while (src < data + RRD_DATA_MAX_LEN && *src) {
117                 minus = 0;
118                 if (*src == '-') {
119                         src++;
120                         minus = 1;
121                 }
122
123                 end = skip_numbers(src);
124
125                 if (*end == '.') {
126                         end++;
127                         end = skip_numbers(end);
128                 }
129
130                 if (*end == ':' || !*end) {
131                         if (minus) {
132                                 *cln = '-';
133                                 cln++;
134                         }
135                         for (; src <= end; src++, cln++)
136                                 *cln = *src;
137
138                         goto next;
139                 }
140
141                 while (*end != ':' && *end)
142                         end++;
143                 *cln = 'U';
144                 cln++;
145                 *cln = ':';
146                 cln++;
147         next:
148                 end++;
149                 src = end;
150                 entries++;
151         }
152
153         strncpy(data, clean_data, RRD_DATA_MAX_LEN);
154         return entries;
155 }
156
157 int rrdtool_update_data(struct rrd_database *rrd)
158 {
159         char data[RRD_DATA_MAX_LEN + 2];
160         char cmd[] = RRDTOOL_CMD;
161 //      char cmd[] = "echo";
162         char *cmdline[] = {
163                 "",
164                 "update",
165                 rrd->filename,
166                 data,
167                 0
168         };
169         int l;
170
171         rrd->last_update = time(0);
172         if (do_fork())
173                 return 0;
174
175         l = sprintf(data, "N:");
176
177         if (rrd->parse) {
178                 rrd->parse(data + l, rrd->parser_data);
179                 sanitize_rrd_update_data(data + l);
180                 run(cmd, cmdline);
181         }
182
183         if (rrd->images)
184                 rrdtool_draw_images(rrd->images);
185
186         while (harvest_zombies(0));
187         exit(0);
188 }
189
190 static int database_exists(struct rrd_database *db)
191 {
192         struct stat s;
193
194         /* If the filename exists, stat will return zero */
195         if (db->filename)
196                 return !stat(db->filename, &s);
197
198         return 1;
199 }
200
201 static int create_database(struct rrd_database *db)
202 {
203         char cmd[] = RRDTOOL_CMD;
204 //      char cmd[] = "echo";
205         char *args[512], argstr[ARGSTR_LEN];
206         int idx = 0, argcnt = 0;
207         int child, i;
208
209         if (!db->sources || !db->archives) {
210                 printf("Cannot create db \"%s\", insufficient source data\n",
211                         db->filename);
212                 return -1;
213         }
214
215         add_arg(args, argcnt, argstr, idx, " ");
216         add_arg(args, argcnt, argstr, idx, "create");
217         add_arg(args, argcnt, argstr, idx, "%s", db->filename);
218         add_arg(args, argcnt, argstr, idx, "--step");
219         add_arg(args, argcnt, argstr, idx, "%d", db->interval);
220
221         for (i = 0; db->sources[i].type; i++) {
222                 add_arg(args, argcnt, argstr, idx, "DS:%s:%s:%d:%f:%f",
223                         db->sources[i].name,
224                         db->sources[i].type,
225                         db->sources[i].heartbeat,
226                         db->sources[i].min,
227                         db->sources[i].max);
228         }
229
230         for (i = 0; db->archives[i].type; i++) {
231                 add_arg(args, argcnt, argstr, idx, "RRA:%s:%f:%d:%d",
232                         db->archives[i].type,
233                         db->archives[i].xff,
234                         db->archives[i].steps,
235                         db->archives[i].rows);
236         }
237
238         child = run(cmd, args);
239
240         harvest_zombies(child);
241
242         return 0;
243 }
244
245 int rrdtool_check_databases(struct rrd_database *dbs[])
246 {
247         struct rrd_database *db;
248         int i;
249
250         for (i = 0, db = dbs[i]; db; i++, db = dbs[i]) {
251                 if (database_exists(db)) {
252                         printf("database %s found\n", db->filename);
253                         continue;
254                 }
255                 printf("Database %s missing, creating\n", db->filename);
256                 create_database(db);
257         }
258         printf("All done\n");
259
260         return 0;
261 }