1 /*
2 * Copyright (c) 2001-2010 Willem Dijkstra
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31 #include <sys/stat.h>
32
33 #include <string.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36
37 #include "conf.h"
38 #include "data.h"
39 #include "error.h"
40 #include "lex.h"
41 #include "net.h"
42 #include "readconf.h"
43 #include "xmalloc.h"
44
45 __BEGIN_DECLS
46 int read_mux(struct muxlist * mul, struct lex *);
47 int read_source(struct sourcelist * sol, struct lex *, int);
48 int insert_filename(char *, int, int, char *);
49 __END_DECLS
50
51 const char *default_symux_port = SYMUX_PORT;
52
53 int
insert_filename(char * path,int maxlen,int type,char * args)54 insert_filename(char *path, int maxlen, int type, char *args)
55 {
56 int i, result;
57 char *ts;
58 char *ta;
59 char *fta;
60
61 fta = ts = ta = NULL;
62
63 switch (type) {
64 case MT_CPU:
65 ts = "cpu";
66 ta = args;
67 break;
68 case MT_CPUIOW:
69 ts = "cpuiow";
70 ta = args;
71 break;
72 case MT_DF:
73 ts = "df_";
74 ta = args;
75 break;
76 case MT_IF1: /* rrd stores 64bits, if1 and if2 are equivalent */
77 case MT_IF2:
78 ts = "if_";
79 ta = args;
80 break;
81 case MT_IO1:
82 ts = "io1_";
83 ta = args;
84 break;
85 case MT_IO2:
86 ts = "io_";
87 ta = args;
88 break;
89 case MT_MEM1: /* rrd stores 64bits, mem1 and mem2 are equivalent */
90 case MT_MEM2:
91 ts = "mem";
92 ta = "";
93 break;
94 case MT_PF:
95 ts = "pf";
96 ta = "";
97 break;
98 case MT_PFQ:
99 ts = "pfq_";
100 ta = args;
101 break;
102 case MT_MBUF:
103 ts = "mbuf";
104 ta = "";
105 break;
106 case MT_DEBUG:
107 ts = "debug";
108 ta = "";
109 break;
110 case MT_PROC:
111 ts = "proc_";
112 ta = args;
113 break;
114 case MT_SENSOR:
115 ts = "sensor_";
116 ta = args;
117 break;
118 case MT_SMART:
119 ts = "smart_";
120 ta = args;
121 break;
122 case MT_LOAD:
123 ts = "load";
124 ta = "";
125 break;
126 case MT_FLUKSO:
127 ts = "flukso_";
128 ta = args;
129 break;
130
131 default:
132 warning("%.200s:%d: internal error: type (%d) unknown",
133 __FILE__, __LINE__, type);
134 return 0;
135 }
136
137 /* ensure that no '/' remain in args */
138 fta = xstrdup(ta);
139
140 for (i = 0; i < strlen(fta); i++) {
141 if (fta[i] == '/') fta[i] = '_';
142 }
143
144 if ((snprintf(path, maxlen, "/%s%s.rrd", ts, fta)) >= maxlen) {
145 result = 0;
146 } else {
147 result = 1;
148 }
149
150 xfree(fta);
151 return result;
152 }
153 /* parse "'mux' (ip4addr | ip6addr | hostname) [['port' | ',' portnumber]" */
154 int
read_mux(struct muxlist * mul,struct lex * l)155 read_mux(struct muxlist * mul, struct lex * l)
156 {
157 char muxname[_POSIX2_LINE_MAX];
158 struct mux *mux;
159
160 if (!SLIST_EMPTY(mul)) {
161 warning("%.200s:%d: only one mux statement allowed",
162 l->filename, l->cline);
163 return 0;
164 }
165
166 lex_nexttoken(l);
167 if (!getip(l->token, AF_INET) && !getip(l->token, AF_INET6)) {
168 warning("%.200s:%d: could not resolve '%s'",
169 l->filename, l->cline, l->token);
170 return 0;
171 }
172
173 mux = add_mux(mul, SYMON_UNKMUX);
174 mux->addr = xstrdup((const char *) &res_host);
175
176 /* check for port statement */
177 lex_nexttoken(l);
178
179 if (l->op == LXT_PORT || l->op == LXT_COMMA)
180 lex_nexttoken(l);
181
182 if (l->type != LXY_NUMBER) {
183 lex_ungettoken(l);
184 mux->port = xstrdup(default_symux_port);
185 } else {
186 mux->port = xstrdup((const char *) l->token);
187 }
188
189 bzero(&muxname, sizeof(muxname));
190 snprintf(&muxname[0], sizeof(muxname), "%s %s", mux->addr, mux->port);
191
192 if (rename_mux(mul, mux, muxname) == NULL)
193 fatal("%s:%d: internal error: dual mux", __FILE__, __LINE__);
194
195 return 1;
196 }
197 /* parse "'source' host '{' accept-stmst [write-stmts] [datadir-stmts] '}'" */
198 int
read_source(struct sourcelist * sol,struct lex * l,int filecheck)199 read_source(struct sourcelist * sol, struct lex * l, int filecheck)
200 {
201 struct source *source;
202 struct stream *stream;
203 struct stat sb;
204 char path[_POSIX2_LINE_MAX];
205 char sn[_POSIX2_LINE_MAX];
206 char sa[_POSIX2_LINE_MAX];
207 int st;
208 int pc;
209 int fd;
210
211 /* get hostname */
212 lex_nexttoken(l);
213 if (!getip(l->token, AF_INET) && !getip(l->token, AF_INET6)) {
214 warning("%.200s:%d: could not resolve '%s'",
215 l->filename, l->cline, l->token);
216 return 0;
217 }
218
219 source = add_source(sol, res_host);
220
221 EXPECT(l, LXT_BEGIN);
222 while (lex_nexttoken(l)) {
223 switch (l->op) {
224 /* accept { cpu(x), ... } */
225 case LXT_ACCEPT:
226 EXPECT(l, LXT_BEGIN);
227 while (lex_nexttoken(l) && l->op != LXT_END) {
228 switch (l->op) {
229 case LXT_CPU:
230 case LXT_CPUIOW:
231 case LXT_DEBUG:
232 case LXT_DF:
233 case LXT_IF1:
234 case LXT_IF:
235 case LXT_IO1:
236 case LXT_IO:
237 case LXT_MBUF:
238 case LXT_MEM1:
239 case LXT_MEM:
240 case LXT_PF:
241 case LXT_PFQ:
242 case LXT_PROC:
243 case LXT_SENSOR:
244 case LXT_SMART:
245 case LXT_LOAD:
246 case LXT_FLUKSO:
247 st = token2type(l->op);
248 strncpy(&sn[0], l->token, _POSIX2_LINE_MAX);
249
250 /* parse arg */
251 lex_nexttoken(l);
252 if (l->op == LXT_OPEN) {
253 lex_nexttoken(l);
254 if (l->op == LXT_CLOSE) {
255 parse_error(l, "<stream argument>");
256 return 0;
257 }
258
259 strncpy(&sa[0], l->token, _POSIX2_LINE_MAX);
260 lex_nexttoken(l);
261
262 if (l->op != LXT_CLOSE) {
263 parse_error(l, ")");
264 return 0;
265 }
266 } else {
267 lex_ungettoken(l);
268 sa[0] = '\0';
269 }
270
271 if (strlen(sa) > (SYMON_PS_ARGLENV2 - 1)) {
272 warning("%.200s:%d: argument '%.200s' too long for network format, "
273 "will accept initial " SYMON_PS_ARGLENSTRV2 " chars only",
274 l->filename, l->cline, sa);
275 sa[SYMON_PS_ARGLENV2 - 1] = '\0';
276 }
277
278 if ((stream = add_source_stream(source, st, sa)) == NULL) {
279 warning("%.200s:%d: stream %.200s(%.200s) redefined",
280 l->filename, l->cline, sn, sa);
281 return 0;
282 }
283
284 break; /* LXT_resource */
285 case LXT_COMMA:
286 break;
287 default:
288 parse_error(l, "{cpu|cpuiow|df|if|if1|io|io1|mem|mem1|pf|pfq|mbuf|debug|proc|sensor|smart|load|flukso}");
289 return 0;
290
291 break;
292 }
293 }
294 break; /* LXT_ACCEPT */
295 /* datadir "path" */
296 case LXT_DATADIR:
297 lex_nexttoken(l);
298 /* is path absolute */
299 if (l->token && l->token[0] != '/') {
300 warning("%.200s:%d: datadir path '%.200s' is not absolute",
301 l->filename, l->cline, l->token);
302 return 0;
303 }
304
305 if (filecheck) {
306 /* make sure that directory exists */
307 bzero(&sb, sizeof(struct stat));
308
309 if (stat(l->token, &sb) == 0) {
310 if (!(sb.st_mode & S_IFDIR)) {
311 warning("%.200s:%d: datadir path '%.200s' is not a directory",
312 l->filename, l->cline, l->token);
313 return 0;
314 }
315 } else {
316 warning("%.200s:%d: could not stat datadir path '%.200s'",
317 l->filename, l->cline, l->token);
318 return 0;
319 }
320 }
321
322 strncpy(&path[0], l->token, _POSIX2_LINE_MAX);
323 path[_POSIX2_LINE_MAX - 1] = '\0';
324
325 pc = strlen(path);
326
327 if (path[pc - 1] == '/') {
328 path[pc - 1] = '\0';
329 pc--;
330 }
331
332 /* add path to empty streams */
333 SLIST_FOREACH(stream, &source->sl, streams) {
334 if (stream->file == NULL) {
335 if (!(insert_filename(&path[pc],
336 _POSIX2_LINE_MAX - pc,
337 stream->type,
338 stream->arg))) {
339 if (stream->arg && strlen(stream->arg)) {
340 warning("%.200s:%d: failed to construct stream "
341 "%.200s(%.200s) filename using datadir '%.200s'",
342 l->filename, l->cline,
343 type2str(stream->type),
344 stream->arg, l->token);
345 } else {
346 warning("%.200s:%d: failed to construct stream "
347 "%.200s) filename using datadir '%.200s'",
348 l->filename, l->cline,
349 type2str(stream->type),
350 l->token);
351 }
352 return 0;
353 }
354
355 if (filecheck) {
356 /* try filename */
357 if ((fd = open(path, O_RDWR | O_NONBLOCK, 0)) == -1) {
358 /* warn, but allow */
359 warning("%.200s:%d: file '%.200s', guessed by datadir, cannot be opened",
360 l->filename, l->cline, path);
361 } else {
362 close(fd);
363 stream->file = xstrdup(path);
364 }
365 } else {
366 stream->file = xstrdup(path);
367 }
368 }
369 }
370 break; /* LXT_DATADIR */
371 /* write cpu(0) in "filename" */
372 case LXT_WRITE:
373 lex_nexttoken(l);
374 switch (l->op) {
375 case LXT_CPU:
376 case LXT_CPUIOW:
377 case LXT_DEBUG:
378 case LXT_DF:
379 case LXT_IF1:
380 case LXT_IF:
381 case LXT_IO1:
382 case LXT_IO:
383 case LXT_MBUF:
384 case LXT_MEM1:
385 case LXT_MEM:
386 case LXT_PF:
387 case LXT_PFQ:
388 case LXT_PROC:
389 case LXT_SENSOR:
390 case LXT_SMART:
391 case LXT_LOAD:
392 case LXT_FLUKSO:
393 st = token2type(l->op);
394 strncpy(&sn[0], l->token, _POSIX2_LINE_MAX);
395
396 /* parse arg */
397 lex_nexttoken(l);
398 if (l->op == LXT_OPEN) {
399 lex_nexttoken(l);
400 if (l->op == LXT_CLOSE) {
401 parse_error(l, "<stream argument>");
402 return 0;
403 }
404
405 strncpy(&sa[0], l->token, _POSIX2_LINE_MAX);
406 lex_nexttoken(l);
407 if (l->op != LXT_CLOSE) {
408 parse_error(l, ")");
409 return 0;
410 }
411 } else {
412 lex_ungettoken(l);
413 sa[0] = '\0';
414 }
415
416 EXPECT(l, LXT_IN);
417
418 lex_nexttoken(l);
419
420 if ((stream = find_source_stream(source, st, sa)) == NULL) {
421 if (strlen(sa)) {
422 warning("%.200s:%d: stream %.200s(%.200s) is not accepted for %.200s",
423 l->filename, l->cline, sn, sa, source->addr);
424 return 0;
425 } else {
426 warning("%.200s:%d: stream %.200s is not accepted for %.200s",
427 l->filename, l->cline, sn, source->addr);
428 return 0;
429 }
430 } else {
431 if (filecheck) {
432 /* try filename */
433 if ((fd = open(l->token, O_RDWR | O_NONBLOCK, 0)) == -1) {
434 warning("%.200s:%d: file '%.200s' cannot be opened",
435 l->filename, l->cline, l->token);
436 return 0;
437 } else {
438 close(fd);
439
440 if (stream->file != NULL) {
441 warning("%.200s:%d: file '%.200s' overwrites previous definition '%.200s'",
442 l->filename, l->cline, l->token, stream->file);
443 xfree(stream->file);
444 }
445
446 stream->file = xstrdup(l->token);
447 }
448 } else {
449 stream->file = xstrdup(l->token);
450 }
451 }
452 break; /* LXT_resource */
453 default:
454 parse_error(l, "{cpu|cpuiow|df|if|if1|io|io1|mem|mem1|pf|pfq|mbuf|debug|proc|sensor|smart|load|flukso}");
455 return 0;
456 break;
457 }
458 break; /* LXT_WRITE */
459 case LXT_END:
460 return 1;
461 default:
462 parse_error(l, "accept|datadir|write");
463 return 0;
464 }
465 }
466
467 warning("%.200s:%d: missing close brace on source statement",
468 l->filename, l->cline);
469
470 return 0;
471 }
472 /* Read symux.conf */
473 int
read_config_file(struct muxlist * mul,const char * filename,int filechecks)474 read_config_file(struct muxlist * mul, const char *filename, int filechecks)
475 {
476 struct lex *l;
477 struct source *source;
478 struct stream *stream;
479 struct mux *mux;
480 struct sourcelist sol;
481 SLIST_INIT(mul);
482 SLIST_INIT(&sol);
483
484 if ((l = open_lex(filename)) == NULL)
485 return 0;
486
487 while (lex_nexttoken(l)) {
488 /* expecting keyword now */
489 switch (l->op) {
490 case LXT_MUX:
491 if (!read_mux(mul, l)) {
492 free_sourcelist(&sol);
493 return 0;
494 }
495 break;
496 case LXT_SOURCE:
497 if (!read_source(&sol, l, filechecks)) {
498 free_sourcelist(&sol);
499 return 0;
500 }
501 break;
502 default:
503 parse_error(l, "mux|source");
504 free_sourcelist(&sol);
505 return 0;
506 break;
507 }
508 }
509
510 /* sanity checks */
511 if (SLIST_EMPTY(mul)) {
512 free_sourcelist(&sol);
513 warning("%.200s: no mux statement seen",
514 l->filename);
515 return 0;
516 } else {
517 mux = SLIST_FIRST(mul);
518 mux->sol = sol;
519 if (strncmp(SYMON_UNKMUX, mux->name, sizeof(SYMON_UNKMUX)) == 0) {
520 /* mux was not initialised for some reason */
521 return 0;
522 }
523 }
524
525 if (SLIST_EMPTY(&sol)) {
526 warning("%.200s: no source section seen",
527 l->filename);
528 return 0;
529 } else {
530 SLIST_FOREACH(source, &sol, sources) {
531 if (SLIST_EMPTY(&source->sl)) {
532 warning("%.200s: no streams accepted for source '%.200s'",
533 l->filename, source->addr);
534 return 0;
535 } else {
536 SLIST_FOREACH(stream, &source->sl, streams) {
537 if (stream->file == NULL) {
538 /* warn, but allow */
539 warning("%.200s: no filename specified for stream '%.200s(%.200s)' in source '%.200s'",
540 l->filename, type2str(stream->type), stream->arg, source->addr);
541 }
542 }
543 }
544 }
545 }
546
547 close_lex(l);
548
549 return 1;
550 }
551