readconf.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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. #include <sys/stat.h>
  31. #include <string.h>
  32. #include <fcntl.h>
  33. #include <unistd.h>
  34. #include "conf.h"
  35. #include "data.h"
  36. #include "error.h"
  37. #include "lex.h"
  38. #include "net.h"
  39. #include "readconf.h"
  40. #include "xmalloc.h"
  41. __BEGIN_DECLS
  42. int read_mux(struct muxlist * mul, struct lex *);
  43. int read_source(struct sourcelist * sol, struct lex *, int);
  44. int insert_filename(char *, int, int, char *);
  45. __END_DECLS
  46. const char *default_symux_port = SYMUX_PORT;
  47. int
  48. insert_filename(char *path, int maxlen, int type, char *args)
  49. {
  50. int i, result;
  51. char *ts;
  52. char *ta;
  53. char *fta;
  54. fta = ts = ta = NULL;
  55. switch (type) {
  56. case MT_CPU:
  57. ts = "cpu";
  58. ta = args;
  59. break;
  60. case MT_CPUIOW:
  61. ts = "cpuiow";
  62. ta = args;
  63. break;
  64. case MT_DF:
  65. ts = "df_";
  66. ta = args;
  67. break;
  68. case MT_IF1: /* rrd stores 64bits, if1 and if2 are equivalent */
  69. case MT_IF2:
  70. ts = "if_";
  71. ta = args;
  72. break;
  73. case MT_IO1:
  74. ts = "io1_";
  75. ta = args;
  76. break;
  77. case MT_IO2:
  78. ts = "io_";
  79. ta = args;
  80. break;
  81. case MT_MEM1: /* rrd stores 64bits, mem1 and mem2 are equivalent */
  82. case MT_MEM2:
  83. ts = "mem";
  84. ta = "";
  85. break;
  86. case MT_PF:
  87. ts = "pf";
  88. ta = "";
  89. break;
  90. case MT_PFQ:
  91. ts = "pfq_";
  92. ta = args;
  93. break;
  94. case MT_MBUF:
  95. ts = "mbuf";
  96. ta = "";
  97. break;
  98. case MT_DEBUG:
  99. ts = "debug";
  100. ta = "";
  101. break;
  102. case MT_PROC:
  103. ts = "proc_";
  104. ta = args;
  105. break;
  106. case MT_SENSOR:
  107. ts = "sensor_";
  108. ta = args;
  109. break;
  110. case MT_SMART:
  111. ts = "smart_";
  112. ta = args;
  113. break;
  114. case MT_LOAD:
  115. ts = "load";
  116. ta = "";
  117. break;
  118. case MT_FLUKSO:
  119. ts = "flukso_";
  120. ta = args;
  121. break;
  122. default:
  123. warning("%.200s:%d: internal error: type (%d) unknown",
  124. __FILE__, __LINE__, type);
  125. return 0;
  126. }
  127. /* ensure that no '/' remain in args */
  128. fta = xstrdup(ta);
  129. for (i = 0; i < strlen(fta); i++) {
  130. if (fta[i] == '/') fta[i] = '_';
  131. }
  132. if ((snprintf(path, maxlen, "/%s%s.rrd", ts, fta)) >= maxlen) {
  133. result = 0;
  134. } else {
  135. result = 1;
  136. }
  137. xfree(fta);
  138. return result;
  139. }
  140. /* parse "'mux' (ip4addr | ip6addr | hostname) [['port' | ',' portnumber]" */
  141. int
  142. read_mux(struct muxlist * mul, struct lex * l)
  143. {
  144. char muxname[_POSIX2_LINE_MAX];
  145. struct mux *mux;
  146. if (!SLIST_EMPTY(mul)) {
  147. warning("%.200s:%d: only one mux statement allowed",
  148. l->filename, l->cline);
  149. return 0;
  150. }
  151. lex_nexttoken(l);
  152. if (!getip(l->token, AF_INET) && !getip(l->token, AF_INET6)) {
  153. warning("%.200s:%d: could not resolve '%s'",
  154. l->filename, l->cline, l->token);
  155. return 0;
  156. }
  157. mux = add_mux(mul, SYMON_UNKMUX);
  158. mux->addr = xstrdup((const char *) &res_host);
  159. /* check for port statement */
  160. lex_nexttoken(l);
  161. if (l->op == LXT_PORT || l->op == LXT_COMMA)
  162. lex_nexttoken(l);
  163. if (l->type != LXY_NUMBER) {
  164. lex_ungettoken(l);
  165. mux->port = xstrdup(default_symux_port);
  166. } else {
  167. mux->port = xstrdup((const char *) l->token);
  168. }
  169. bzero(&muxname, sizeof(muxname));
  170. snprintf(&muxname[0], sizeof(muxname), "%s %s", mux->addr, mux->port);
  171. if (rename_mux(mul, mux, muxname) == NULL)
  172. fatal("%s:%d: internal error: dual mux", __FILE__, __LINE__);
  173. return 1;
  174. }
  175. /* parse "'source' host '{' accept-stmst [write-stmts] [datadir-stmts] '}'" */
  176. int
  177. read_source(struct sourcelist * sol, struct lex * l, int filecheck)
  178. {
  179. struct source *source;
  180. struct stream *stream;
  181. struct stat sb;
  182. char path[_POSIX2_LINE_MAX];
  183. char sn[_POSIX2_LINE_MAX];
  184. char sa[_POSIX2_LINE_MAX];
  185. int st;
  186. int pc;
  187. int fd;
  188. /* get hostname */
  189. lex_nexttoken(l);
  190. if (!getip(l->token, AF_INET) && !getip(l->token, AF_INET6)) {
  191. warning("%.200s:%d: could not resolve '%s'",
  192. l->filename, l->cline, l->token);
  193. return 0;
  194. }
  195. source = add_source(sol, res_host);
  196. EXPECT(l, LXT_BEGIN);
  197. while (lex_nexttoken(l)) {
  198. switch (l->op) {
  199. /* accept { cpu(x), ... } */
  200. case LXT_ACCEPT:
  201. EXPECT(l, LXT_BEGIN);
  202. while (lex_nexttoken(l) && l->op != LXT_END) {
  203. switch (l->op) {
  204. case LXT_CPU:
  205. case LXT_CPUIOW:
  206. case LXT_DEBUG:
  207. case LXT_DF:
  208. case LXT_IF1:
  209. case LXT_IF:
  210. case LXT_IO1:
  211. case LXT_IO:
  212. case LXT_MBUF:
  213. case LXT_MEM1:
  214. case LXT_MEM:
  215. case LXT_PF:
  216. case LXT_PFQ:
  217. case LXT_PROC:
  218. case LXT_SENSOR:
  219. case LXT_SMART:
  220. case LXT_LOAD:
  221. case LXT_FLUKSO:
  222. st = token2type(l->op);
  223. strncpy(&sn[0], l->token, _POSIX2_LINE_MAX);
  224. /* parse arg */
  225. lex_nexttoken(l);
  226. if (l->op == LXT_OPEN) {
  227. lex_nexttoken(l);
  228. if (l->op == LXT_CLOSE) {
  229. parse_error(l, "<stream argument>");
  230. return 0;
  231. }
  232. strncpy(&sa[0], l->token, _POSIX2_LINE_MAX);
  233. lex_nexttoken(l);
  234. if (l->op != LXT_CLOSE) {
  235. parse_error(l, ")");
  236. return 0;
  237. }
  238. } else {
  239. lex_ungettoken(l);
  240. sa[0] = '\0';
  241. }
  242. if (strlen(sa) > (SYMON_PS_ARGLENV2 - 1)) {
  243. warning("%.200s:%d: argument '%.200s' too long for network format, "
  244. "will accept initial " SYMON_PS_ARGLENSTRV2 " chars only",
  245. l->filename, l->cline, sa);
  246. sa[SYMON_PS_ARGLENV2 - 1] = '\0';
  247. }
  248. if ((stream = add_source_stream(source, st, sa)) == NULL) {
  249. warning("%.200s:%d: stream %.200s(%.200s) redefined",
  250. l->filename, l->cline, sn, sa);
  251. return 0;
  252. }
  253. break; /* LXT_resource */
  254. case LXT_COMMA:
  255. break;
  256. default:
  257. parse_error(l, "{cpu|cpuiow|df|if|if1|io|io1|mem|mem1|pf|pfq|mbuf|debug|proc|sensor|smart|load|flukso}");
  258. return 0;
  259. break;
  260. }
  261. }
  262. break; /* LXT_ACCEPT */
  263. /* datadir "path" */
  264. case LXT_DATADIR:
  265. lex_nexttoken(l);
  266. /* is path absolute */
  267. if (l->token && l->token[0] != '/') {
  268. warning("%.200s:%d: datadir path '%.200s' is not absolute",
  269. l->filename, l->cline, l->token);
  270. return 0;
  271. }
  272. if (filecheck) {
  273. /* make sure that directory exists */
  274. bzero(&sb, sizeof(struct stat));
  275. if (stat(l->token, &sb) == 0) {
  276. if (!(sb.st_mode & S_IFDIR)) {
  277. warning("%.200s:%d: datadir path '%.200s' is not a directory",
  278. l->filename, l->cline, l->token);
  279. return 0;
  280. }
  281. } else {
  282. warning("%.200s:%d: could not stat datadir path '%.200s'",
  283. l->filename, l->cline, l->token);
  284. return 0;
  285. }
  286. }
  287. strncpy(&path[0], l->token, _POSIX2_LINE_MAX);
  288. path[_POSIX2_LINE_MAX - 1] = '\0';
  289. pc = strlen(path);
  290. if (path[pc - 1] == '/') {
  291. path[pc - 1] = '\0';
  292. pc--;
  293. }
  294. /* add path to empty streams */
  295. SLIST_FOREACH(stream, &source->sl, streams) {
  296. if (stream->file == NULL) {
  297. if (!(insert_filename(&path[pc],
  298. _POSIX2_LINE_MAX - pc,
  299. stream->type,
  300. stream->arg))) {
  301. if (stream->arg && strlen(stream->arg)) {
  302. warning("%.200s:%d: failed to construct stream "
  303. "%.200s(%.200s) filename using datadir '%.200s'",
  304. l->filename, l->cline,
  305. type2str(stream->type),
  306. stream->arg, l->token);
  307. } else {
  308. warning("%.200s:%d: failed to construct stream "
  309. "%.200s) filename using datadir '%.200s'",
  310. l->filename, l->cline,
  311. type2str(stream->type),
  312. l->token);
  313. }
  314. return 0;
  315. }
  316. if (filecheck) {
  317. /* try filename */
  318. if ((fd = open(path, O_RDWR | O_NONBLOCK, 0)) == -1) {
  319. /* warn, but allow */
  320. warning("%.200s:%d: file '%.200s', guessed by datadir, cannot be opened",
  321. l->filename, l->cline, path);
  322. } else {
  323. close(fd);
  324. stream->file = xstrdup(path);
  325. }
  326. } else {
  327. stream->file = xstrdup(path);
  328. }
  329. }
  330. }
  331. break; /* LXT_DATADIR */
  332. /* write cpu(0) in "filename" */
  333. case LXT_WRITE:
  334. lex_nexttoken(l);
  335. switch (l->op) {
  336. case LXT_CPU:
  337. case LXT_CPUIOW:
  338. case LXT_DEBUG:
  339. case LXT_DF:
  340. case LXT_IF1:
  341. case LXT_IF:
  342. case LXT_IO1:
  343. case LXT_IO:
  344. case LXT_MBUF:
  345. case LXT_MEM1:
  346. case LXT_MEM:
  347. case LXT_PF:
  348. case LXT_PFQ:
  349. case LXT_PROC:
  350. case LXT_SENSOR:
  351. case LXT_SMART:
  352. case LXT_LOAD:
  353. case LXT_FLUKSO:
  354. st = token2type(l->op);
  355. strncpy(&sn[0], l->token, _POSIX2_LINE_MAX);
  356. /* parse arg */
  357. lex_nexttoken(l);
  358. if (l->op == LXT_OPEN) {
  359. lex_nexttoken(l);
  360. if (l->op == LXT_CLOSE) {
  361. parse_error(l, "<stream argument>");
  362. return 0;
  363. }
  364. strncpy(&sa[0], l->token, _POSIX2_LINE_MAX);
  365. lex_nexttoken(l);
  366. if (l->op != LXT_CLOSE) {
  367. parse_error(l, ")");
  368. return 0;
  369. }
  370. } else {
  371. lex_ungettoken(l);
  372. sa[0] = '\0';
  373. }
  374. EXPECT(l, LXT_IN);
  375. lex_nexttoken(l);
  376. if ((stream = find_source_stream(source, st, sa)) == NULL) {
  377. if (strlen(sa)) {
  378. warning("%.200s:%d: stream %.200s(%.200s) is not accepted for %.200s",
  379. l->filename, l->cline, sn, sa, source->addr);
  380. return 0;
  381. } else {
  382. warning("%.200s:%d: stream %.200s is not accepted for %.200s",
  383. l->filename, l->cline, sn, source->addr);
  384. return 0;
  385. }
  386. } else {
  387. if (filecheck) {
  388. /* try filename */
  389. if ((fd = open(l->token, O_RDWR | O_NONBLOCK, 0)) == -1) {
  390. warning("%.200s:%d: file '%.200s' cannot be opened",
  391. l->filename, l->cline, l->token);
  392. return 0;
  393. } else {
  394. close(fd);
  395. if (stream->file != NULL) {
  396. warning("%.200s:%d: file '%.200s' overwrites previous definition '%.200s'",
  397. l->filename, l->cline, l->token, stream->file);
  398. xfree(stream->file);
  399. }
  400. stream->file = xstrdup(l->token);
  401. }
  402. } else {
  403. stream->file = xstrdup(l->token);
  404. }
  405. }
  406. break; /* LXT_resource */
  407. default:
  408. parse_error(l, "{cpu|cpuiow|df|if|if1|io|io1|mem|mem1|pf|pfq|mbuf|debug|proc|sensor|smart|load|flukso}");
  409. return 0;
  410. break;
  411. }
  412. break; /* LXT_WRITE */
  413. case LXT_END:
  414. return 1;
  415. default:
  416. parse_error(l, "accept|datadir|write");
  417. return 0;
  418. }
  419. }
  420. warning("%.200s:%d: missing close brace on source statement",
  421. l->filename, l->cline);
  422. return 0;
  423. }
  424. /* Read symux.conf */
  425. int
  426. read_config_file(struct muxlist * mul, const char *filename, int filechecks)
  427. {
  428. struct lex *l;
  429. struct source *source;
  430. struct stream *stream;
  431. struct mux *mux;
  432. struct sourcelist sol;
  433. SLIST_INIT(mul);
  434. SLIST_INIT(&sol);
  435. if ((l = open_lex(filename)) == NULL)
  436. return 0;
  437. while (lex_nexttoken(l)) {
  438. /* expecting keyword now */
  439. switch (l->op) {
  440. case LXT_MUX:
  441. if (!read_mux(mul, l)) {
  442. free_sourcelist(&sol);
  443. return 0;
  444. }
  445. break;
  446. case LXT_SOURCE:
  447. if (!read_source(&sol, l, filechecks)) {
  448. free_sourcelist(&sol);
  449. return 0;
  450. }
  451. break;
  452. default:
  453. parse_error(l, "mux|source");
  454. free_sourcelist(&sol);
  455. return 0;
  456. break;
  457. }
  458. }
  459. /* sanity checks */
  460. if (SLIST_EMPTY(mul)) {
  461. free_sourcelist(&sol);
  462. warning("%.200s: no mux statement seen",
  463. l->filename);
  464. return 0;
  465. } else {
  466. mux = SLIST_FIRST(mul);
  467. mux->sol = sol;
  468. if (strncmp(SYMON_UNKMUX, mux->name, sizeof(SYMON_UNKMUX)) == 0) {
  469. /* mux was not initialised for some reason */
  470. return 0;
  471. }
  472. }
  473. if (SLIST_EMPTY(&sol)) {
  474. warning("%.200s: no source section seen",
  475. l->filename);
  476. return 0;
  477. } else {
  478. SLIST_FOREACH(source, &sol, sources) {
  479. if (SLIST_EMPTY(&source->sl)) {
  480. warning("%.200s: no streams accepted for source '%.200s'",
  481. l->filename, source->addr);
  482. return 0;
  483. } else {
  484. SLIST_FOREACH(stream, &source->sl, streams) {
  485. if (stream->file == NULL) {
  486. /* warn, but allow */
  487. warning("%.200s: no filename specified for stream '%.200s(%.200s)' in source '%.200s'",
  488. l->filename, type2str(stream->type), stream->arg, source->addr);
  489. }
  490. }
  491. }
  492. }
  493. }
  494. close_lex(l);
  495. return 1;
  496. }