readconf.c 17 KB

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