Source code pulled from OpenBSD for OpenNTPD. The place to contribute to this code is via the OpenBSD CVS tree.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

835 lines
17 KiB

20 years ago
9 years ago
  1. /* $OpenBSD: parse.y,v 1.75 2019/11/10 19:24:47 otto Exp $ */
  2. /*
  3. * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
  4. * Copyright (c) 2001 Markus Friedl. All rights reserved.
  5. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
  6. * Copyright (c) 2001 Theo de Raadt. All rights reserved.
  7. *
  8. * Permission to use, copy, modify, and distribute this software for any
  9. * purpose with or without fee is hereby granted, provided that the above
  10. * copyright notice and this permission notice appear in all copies.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  13. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  14. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  15. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  16. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  17. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  18. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19. */
  20. %{
  21. #include <sys/types.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>
  25. #include <ctype.h>
  26. #include <errno.h>
  27. #include <limits.h>
  28. #include <stdarg.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <syslog.h>
  33. #include "ntpd.h"
  34. TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
  35. static struct file {
  36. TAILQ_ENTRY(file) entry;
  37. FILE *stream;
  38. char *name;
  39. int lineno;
  40. int errors;
  41. } *file, *topfile;
  42. struct file *pushfile(const char *);
  43. int popfile(void);
  44. int yyparse(void);
  45. int yylex(void);
  46. int yyerror(const char *, ...)
  47. __attribute__((__format__ (printf, 1, 2)))
  48. __attribute__((__nonnull__ (1)));
  49. int kw_cmp(const void *, const void *);
  50. int lookup(char *);
  51. int lgetc(int);
  52. int lungetc(int);
  53. int findeol(void);
  54. struct ntpd_conf *conf;
  55. struct sockaddr_in query_addr4;
  56. struct sockaddr_in6 query_addr6;
  57. int poolseqnum;
  58. struct opts {
  59. int weight;
  60. int correction;
  61. int stratum;
  62. int rtable;
  63. int trusted;
  64. char *refstr;
  65. } opts;
  66. void opts_default(void);
  67. typedef struct {
  68. union {
  69. int64_t number;
  70. char *string;
  71. struct ntp_addr_wrap *addr;
  72. struct opts opts;
  73. } v;
  74. int lineno;
  75. } YYSTYPE;
  76. %}
  77. %token LISTEN ON CONSTRAINT CONSTRAINTS FROM QUERY TRUSTED
  78. %token SERVER SERVERS SENSOR CORRECTION RTABLE REFID STRATUM WEIGHT
  79. %token ERROR
  80. %token <v.string> STRING
  81. %token <v.number> NUMBER
  82. %type <v.addr> address url urllist
  83. %type <v.opts> listen_opts listen_opts_l listen_opt
  84. %type <v.opts> server_opts server_opts_l server_opt
  85. %type <v.opts> sensor_opts sensor_opts_l sensor_opt
  86. %type <v.opts> correction
  87. %type <v.opts> rtable
  88. %type <v.opts> refid
  89. %type <v.opts> stratum
  90. %type <v.opts> weight
  91. %type <v.opts> trusted
  92. %%
  93. grammar : /* empty */
  94. | grammar '\n'
  95. | grammar main '\n'
  96. | grammar error '\n' { file->errors++; }
  97. ;
  98. main : LISTEN ON address listen_opts {
  99. struct listen_addr *la;
  100. struct ntp_addr *h, *next;
  101. if ((h = $3->a) == NULL &&
  102. (host_dns($3->name, 0, &h) == -1 || !h)) {
  103. yyerror("could not resolve \"%s\"", $3->name);
  104. free($3->name);
  105. free($3);
  106. YYERROR;
  107. }
  108. for (; h != NULL; h = next) {
  109. next = h->next;
  110. la = calloc(1, sizeof(struct listen_addr));
  111. if (la == NULL)
  112. fatal("listen on calloc");
  113. la->fd = -1;
  114. la->rtable = $4.rtable;
  115. memcpy(&la->sa, &h->ss,
  116. sizeof(struct sockaddr_storage));
  117. TAILQ_INSERT_TAIL(&conf->listen_addrs, la,
  118. entry);
  119. free(h);
  120. }
  121. free($3->name);
  122. free($3);
  123. }
  124. | QUERY FROM STRING {
  125. struct sockaddr_in sin4;
  126. struct sockaddr_in6 sin6;
  127. memset(&sin4, 0, sizeof(sin4));
  128. sin4.sin_family = AF_INET;
  129. sin4.sin_len = sizeof(struct sockaddr_in);
  130. memset(&sin6, 0, sizeof(sin6));
  131. sin6.sin6_family = AF_INET6;
  132. sin6.sin6_len = sizeof(struct sockaddr_in6);
  133. if (inet_pton(AF_INET, $3, &sin4.sin_addr) == 1)
  134. memcpy(&query_addr4, &sin4, sin4.sin_len);
  135. else if (inet_pton(AF_INET6, $3, &sin6.sin6_addr) == 1)
  136. memcpy(&query_addr6, &sin6, sin6.sin6_len);
  137. else {
  138. yyerror("invalid IPv4 or IPv6 address: %s\n",
  139. $3);
  140. free($3);
  141. YYERROR;
  142. }
  143. free($3);
  144. }
  145. | SERVERS address server_opts {
  146. struct ntp_peer *p;
  147. struct ntp_addr *h, *next;
  148. h = $2->a;
  149. do {
  150. if (h != NULL) {
  151. next = h->next;
  152. if (h->ss.ss_family != AF_INET &&
  153. h->ss.ss_family != AF_INET6) {
  154. yyerror("IPv4 or IPv6 address "
  155. "or hostname expected");
  156. free(h);
  157. free($2->name);
  158. free($2);
  159. YYERROR;
  160. }
  161. h->next = NULL;
  162. } else
  163. next = NULL;
  164. p = new_peer();
  165. p->weight = $3.weight;
  166. p->trusted = $3.trusted;
  167. p->query_addr4 = query_addr4;
  168. p->query_addr6 = query_addr6;
  169. p->addr = h;
  170. p->addr_head.a = h;
  171. p->addr_head.pool = ++poolseqnum;
  172. p->addr_head.name = strdup($2->name);
  173. if (p->addr_head.name == NULL)
  174. fatal(NULL);
  175. if (p->addr != NULL)
  176. p->state = STATE_DNS_DONE;
  177. TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
  178. h = next;
  179. } while (h != NULL);
  180. free($2->name);
  181. free($2);
  182. }
  183. | SERVER address server_opts {
  184. struct ntp_peer *p;
  185. struct ntp_addr *h, *next;
  186. p = new_peer();
  187. for (h = $2->a; h != NULL; h = next) {
  188. next = h->next;
  189. if (h->ss.ss_family != AF_INET &&
  190. h->ss.ss_family != AF_INET6) {
  191. yyerror("IPv4 or IPv6 address "
  192. "or hostname expected");
  193. free(h);
  194. free(p);
  195. free($2->name);
  196. free($2);
  197. YYERROR;
  198. }
  199. h->next = p->addr;
  200. p->addr = h;
  201. }
  202. p->weight = $3.weight;
  203. p->trusted = $3.trusted;
  204. p->query_addr4 = query_addr4;
  205. p->query_addr6 = query_addr6;
  206. p->addr_head.a = p->addr;
  207. p->addr_head.pool = 0;
  208. p->addr_head.name = strdup($2->name);
  209. if (p->addr_head.name == NULL)
  210. fatal(NULL);
  211. if (p->addr != NULL)
  212. p->state = STATE_DNS_DONE;
  213. TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
  214. free($2->name);
  215. free($2);
  216. }
  217. | CONSTRAINTS FROM url {
  218. struct constraint *p;
  219. struct ntp_addr *h, *next;
  220. h = $3->a;
  221. do {
  222. if (h != NULL) {
  223. next = h->next;
  224. if (h->ss.ss_family != AF_INET &&
  225. h->ss.ss_family != AF_INET6) {
  226. yyerror("IPv4 or IPv6 address "
  227. "or hostname expected");
  228. free(h);
  229. free($3->name);
  230. free($3->path);
  231. free($3);
  232. YYERROR;
  233. }
  234. h->next = NULL;
  235. } else
  236. next = NULL;
  237. p = new_constraint();
  238. p->addr = h;
  239. p->addr_head.a = h;
  240. p->addr_head.pool = ++poolseqnum;
  241. p->addr_head.name = strdup($3->name);
  242. p->addr_head.path = strdup($3->path);
  243. if (p->addr_head.name == NULL ||
  244. p->addr_head.path == NULL)
  245. fatal(NULL);
  246. if (p->addr != NULL)
  247. p->state = STATE_DNS_DONE;
  248. constraint_add(p);
  249. h = next;
  250. } while (h != NULL);
  251. free($3->name);
  252. free($3);
  253. }
  254. | CONSTRAINT FROM urllist {
  255. struct constraint *p;
  256. struct ntp_addr *h, *next;
  257. p = new_constraint();
  258. for (h = $3->a; h != NULL; h = next) {
  259. next = h->next;
  260. if (h->ss.ss_family != AF_INET &&
  261. h->ss.ss_family != AF_INET6) {
  262. yyerror("IPv4 or IPv6 address "
  263. "or hostname expected");
  264. free(h);
  265. free(p);
  266. free($3->name);
  267. free($3->path);
  268. free($3);
  269. YYERROR;
  270. }
  271. h->next = p->addr;
  272. p->addr = h;
  273. }
  274. p->addr_head.a = p->addr;
  275. p->addr_head.pool = 0;
  276. p->addr_head.name = strdup($3->name);
  277. p->addr_head.path = strdup($3->path);
  278. if (p->addr_head.name == NULL ||
  279. p->addr_head.path == NULL)
  280. fatal(NULL);
  281. if (p->addr != NULL)
  282. p->state = STATE_DNS_DONE;
  283. constraint_add(p);
  284. free($3->name);
  285. free($3);
  286. }
  287. | SENSOR STRING sensor_opts {
  288. struct ntp_conf_sensor *s;
  289. s = new_sensor($2);
  290. s->weight = $3.weight;
  291. s->correction = $3.correction;
  292. s->refstr = $3.refstr;
  293. s->stratum = $3.stratum;
  294. free($2);
  295. TAILQ_INSERT_TAIL(&conf->ntp_conf_sensors, s, entry);
  296. }
  297. ;
  298. address : STRING {
  299. if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
  300. NULL)
  301. fatal(NULL);
  302. host($1, &$$->a);
  303. $$->name = $1;
  304. }
  305. ;
  306. urllist : urllist address {
  307. struct ntp_addr *p, *q = NULL;
  308. struct in_addr ina;
  309. struct in6_addr in6a;
  310. if (inet_pton(AF_INET, $2->name, &ina) != 1 &&
  311. inet_pton(AF_INET6, $2->name, &in6a) != 1) {
  312. yyerror("url can only be followed by IP "
  313. "addresses");
  314. free($2->name);
  315. free($2);
  316. YYERROR;
  317. }
  318. p = $2->a;
  319. while (p != NULL) {
  320. q = p;
  321. p = p->next;
  322. }
  323. if (q != NULL) {
  324. q->next = $1->a;
  325. $1->a = $2->a;
  326. free($2);
  327. }
  328. $$ = $1;
  329. }
  330. | url {
  331. $$ = $1;
  332. }
  333. ;
  334. url : STRING {
  335. char *hname, *path;
  336. if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
  337. NULL)
  338. fatal("calloc");
  339. if (strncmp("https://", $1,
  340. strlen("https://")) != 0) {
  341. host($1, &$$->a);
  342. $$->name = $1;
  343. } else {
  344. hname = $1 + strlen("https://");
  345. path = hname + strcspn(hname, "/\\");
  346. if (*path != '\0') {
  347. if (($$->path = strdup(path)) == NULL)
  348. fatal("strdup");
  349. *path = '\0';
  350. }
  351. host(hname, &$$->a);
  352. if (($$->name = strdup(hname)) == NULL)
  353. fatal("strdup");
  354. }
  355. if ($$->path == NULL &&
  356. ($$->path = strdup("/")) == NULL)
  357. fatal("strdup");
  358. }
  359. ;
  360. listen_opts : { opts_default(); }
  361. listen_opts_l
  362. { $$ = opts; }
  363. | { opts_default(); $$ = opts; }
  364. ;
  365. listen_opts_l : listen_opts_l listen_opt
  366. | listen_opt
  367. ;
  368. listen_opt : rtable
  369. ;
  370. server_opts : { opts_default(); }
  371. server_opts_l
  372. { $$ = opts; }
  373. | { opts_default(); $$ = opts; }
  374. ;
  375. server_opts_l : server_opts_l server_opt
  376. | server_opt
  377. ;
  378. server_opt : weight
  379. | trusted
  380. ;
  381. sensor_opts : { opts_default(); }
  382. sensor_opts_l
  383. { $$ = opts; }
  384. | { opts_default(); $$ = opts; }
  385. ;
  386. sensor_opts_l : sensor_opts_l sensor_opt
  387. | sensor_opt
  388. ;
  389. sensor_opt : correction
  390. | refid
  391. | stratum
  392. | weight
  393. ;
  394. correction : CORRECTION NUMBER {
  395. if ($2 < -127000000 || $2 > 127000000) {
  396. yyerror("correction must be between "
  397. "-127000000 and 127000000 microseconds");
  398. YYERROR;
  399. }
  400. opts.correction = $2;
  401. }
  402. ;
  403. refid : REFID STRING {
  404. size_t l = strlen($2);
  405. if (l < 1 || l > 4) {
  406. yyerror("refid must be 1 to 4 characters");
  407. free($2);
  408. YYERROR;
  409. }
  410. opts.refstr = $2;
  411. }
  412. ;
  413. stratum : STRATUM NUMBER {
  414. if ($2 < 1 || $2 > 15) {
  415. yyerror("stratum must be between "
  416. "1 and 15");
  417. YYERROR;
  418. }
  419. opts.stratum = $2;
  420. }
  421. ;
  422. weight : WEIGHT NUMBER {
  423. if ($2 < 1 || $2 > 10) {
  424. yyerror("weight must be between 1 and 10");
  425. YYERROR;
  426. }
  427. opts.weight = $2;
  428. }
  429. rtable : RTABLE NUMBER {
  430. if ($2 < 0 || $2 > RT_TABLEID_MAX) {
  431. yyerror("rtable must be between 1"
  432. " and RT_TABLEID_MAX");
  433. YYERROR;
  434. }
  435. opts.rtable = $2;
  436. }
  437. ;
  438. trusted : TRUSTED {
  439. opts.trusted = 1;
  440. conf->trusted_peers = 1;
  441. }
  442. %%
  443. void
  444. opts_default(void)
  445. {
  446. memset(&opts, 0, sizeof opts);
  447. opts.weight = 1;
  448. opts.stratum = 1;
  449. }
  450. struct keywords {
  451. const char *k_name;
  452. int k_val;
  453. };
  454. int
  455. yyerror(const char *fmt, ...)
  456. {
  457. va_list ap;
  458. char *msg;
  459. file->errors++;
  460. va_start(ap, fmt);
  461. if (vasprintf(&msg, fmt, ap) == -1)
  462. fatalx("yyerror vasprintf");
  463. va_end(ap);
  464. log_warnx("%s:%d: %s", file->name, yylval.lineno, msg);
  465. free(msg);
  466. return (0);
  467. }
  468. int
  469. kw_cmp(const void *k, const void *e)
  470. {
  471. return (strcmp(k, ((const struct keywords *)e)->k_name));
  472. }
  473. int
  474. lookup(char *s)
  475. {
  476. /* this has to be sorted always */
  477. static const struct keywords keywords[] = {
  478. { "constraint", CONSTRAINT},
  479. { "constraints", CONSTRAINTS},
  480. { "correction", CORRECTION},
  481. { "from", FROM},
  482. { "listen", LISTEN},
  483. { "on", ON},
  484. { "query", QUERY},
  485. { "refid", REFID},
  486. { "rtable", RTABLE},
  487. { "sensor", SENSOR},
  488. { "server", SERVER},
  489. { "servers", SERVERS},
  490. { "stratum", STRATUM},
  491. { "trusted", TRUSTED},
  492. { "weight", WEIGHT}
  493. };
  494. const struct keywords *p;
  495. p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
  496. sizeof(keywords[0]), kw_cmp);
  497. if (p)
  498. return (p->k_val);
  499. else
  500. return (STRING);
  501. }
  502. #define MAXPUSHBACK 128
  503. u_char *parsebuf;
  504. int parseindex;
  505. u_char pushback_buffer[MAXPUSHBACK];
  506. int pushback_index = 0;
  507. int
  508. lgetc(int quotec)
  509. {
  510. int c, next;
  511. if (parsebuf) {
  512. /* Read character from the parsebuffer instead of input. */
  513. if (parseindex >= 0) {
  514. c = parsebuf[parseindex++];
  515. if (c != '\0')
  516. return (c);
  517. parsebuf = NULL;
  518. } else
  519. parseindex++;
  520. }
  521. if (pushback_index)
  522. return (pushback_buffer[--pushback_index]);
  523. if (quotec) {
  524. if ((c = getc(file->stream)) == EOF) {
  525. yyerror("reached end of file while parsing "
  526. "quoted string");
  527. if (file == topfile || popfile() == EOF)
  528. return (EOF);
  529. return (quotec);
  530. }
  531. return (c);
  532. }
  533. while ((c = getc(file->stream)) == '\\') {
  534. next = getc(file->stream);
  535. if (next != '\n') {
  536. c = next;
  537. break;
  538. }
  539. yylval.lineno = file->lineno;
  540. file->lineno++;
  541. }
  542. while (c == EOF) {
  543. if (file == topfile || popfile() == EOF)
  544. return (EOF);
  545. c = getc(file->stream);
  546. }
  547. return (c);
  548. }
  549. int
  550. lungetc(int c)
  551. {
  552. if (c == EOF)
  553. return (EOF);
  554. if (parsebuf) {
  555. parseindex--;
  556. if (parseindex >= 0)
  557. return (c);
  558. }
  559. if (pushback_index < MAXPUSHBACK-1)
  560. return (pushback_buffer[pushback_index++] = c);
  561. else
  562. return (EOF);
  563. }
  564. int
  565. findeol(void)
  566. {
  567. int c;
  568. parsebuf = NULL;
  569. /* skip to either EOF or the first real EOL */
  570. while (1) {
  571. if (pushback_index)
  572. c = pushback_buffer[--pushback_index];
  573. else
  574. c = lgetc(0);
  575. if (c == '\n') {
  576. file->lineno++;
  577. break;
  578. }
  579. if (c == EOF)
  580. break;
  581. }
  582. return (ERROR);
  583. }
  584. int
  585. yylex(void)
  586. {
  587. u_char buf[8096];
  588. u_char *p;
  589. int quotec, next, c;
  590. int token;
  591. p = buf;
  592. while ((c = lgetc(0)) == ' ' || c == '\t')
  593. ; /* nothing */
  594. yylval.lineno = file->lineno;
  595. if (c == '#')
  596. while ((c = lgetc(0)) != '\n' && c != EOF)
  597. ; /* nothing */
  598. switch (c) {
  599. case '\'':
  600. case '"':
  601. quotec = c;
  602. while (1) {
  603. if ((c = lgetc(quotec)) == EOF)
  604. return (0);
  605. if (c == '\n') {
  606. file->lineno++;
  607. continue;
  608. } else if (c == '\\') {
  609. if ((next = lgetc(quotec)) == EOF)
  610. return (0);
  611. if (next == quotec || next == ' ' ||
  612. next == '\t')
  613. c = next;
  614. else if (next == '\n') {
  615. file->lineno++;
  616. continue;
  617. } else
  618. lungetc(next);
  619. } else if (c == quotec) {
  620. *p = '\0';
  621. break;
  622. } else if (c == '\0') {
  623. yyerror("syntax error");
  624. return (findeol());
  625. }
  626. if (p + 1 >= buf + sizeof(buf) - 1) {
  627. yyerror("string too long");
  628. return (findeol());
  629. }
  630. *p++ = c;
  631. }
  632. yylval.v.string = strdup(buf);
  633. if (yylval.v.string == NULL)
  634. fatal("yylex: strdup");
  635. return (STRING);
  636. }
  637. #define allowed_to_end_number(x) \
  638. (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
  639. if (c == '-' || isdigit(c)) {
  640. do {
  641. *p++ = c;
  642. if ((size_t)(p-buf) >= sizeof(buf)) {
  643. yyerror("string too long");
  644. return (findeol());
  645. }
  646. } while ((c = lgetc(0)) != EOF && isdigit(c));
  647. lungetc(c);
  648. if (p == buf + 1 && buf[0] == '-')
  649. goto nodigits;
  650. if (c == EOF || allowed_to_end_number(c)) {
  651. const char *errstr = NULL;
  652. *p = '\0';
  653. yylval.v.number = strtonum(buf, LLONG_MIN,
  654. LLONG_MAX, &errstr);
  655. if (errstr) {
  656. yyerror("\"%s\" invalid number: %s",
  657. buf, errstr);
  658. return (findeol());
  659. }
  660. return (NUMBER);
  661. } else {
  662. nodigits:
  663. while (p > buf + 1)
  664. lungetc(*--p);
  665. c = *--p;
  666. if (c == '-')
  667. return (c);
  668. }
  669. }
  670. #define allowed_in_string(x) \
  671. (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
  672. x != '{' && x != '}' && x != '<' && x != '>' && \
  673. x != '!' && x != '=' && x != '/' && x != '#' && \
  674. x != ','))
  675. if (isalnum(c) || c == ':' || c == '_' || c == '*') {
  676. do {
  677. *p++ = c;
  678. if ((size_t)(p-buf) >= sizeof(buf)) {
  679. yyerror("string too long");
  680. return (findeol());
  681. }
  682. } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
  683. lungetc(c);
  684. *p = '\0';
  685. if ((token = lookup(buf)) == STRING)
  686. if ((yylval.v.string = strdup(buf)) == NULL)
  687. fatal("yylex: strdup");
  688. return (token);
  689. }
  690. if (c == '\n') {
  691. yylval.lineno = file->lineno;
  692. file->lineno++;
  693. }
  694. if (c == EOF)
  695. return (0);
  696. return (c);
  697. }
  698. struct file *
  699. pushfile(const char *name)
  700. {
  701. struct file *nfile;
  702. if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
  703. log_warn("%s", __func__);
  704. return (NULL);
  705. }
  706. if ((nfile->name = strdup(name)) == NULL) {
  707. log_warn("%s", __func__);
  708. free(nfile);
  709. return (NULL);
  710. }
  711. if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
  712. log_warn("%s: %s", __func__, nfile->name);
  713. free(nfile->name);
  714. free(nfile);
  715. return (NULL);
  716. }
  717. nfile->lineno = 1;
  718. TAILQ_INSERT_TAIL(&files, nfile, entry);
  719. return (nfile);
  720. }
  721. int
  722. popfile(void)
  723. {
  724. struct file *prev;
  725. if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
  726. prev->errors += file->errors;
  727. TAILQ_REMOVE(&files, file, entry);
  728. fclose(file->stream);
  729. free(file->name);
  730. free(file);
  731. file = prev;
  732. return (file ? 0 : EOF);
  733. }
  734. int
  735. parse_config(const char *filename, struct ntpd_conf *xconf)
  736. {
  737. int errors = 0;
  738. conf = xconf;
  739. TAILQ_INIT(&conf->listen_addrs);
  740. TAILQ_INIT(&conf->ntp_peers);
  741. TAILQ_INIT(&conf->ntp_conf_sensors);
  742. TAILQ_INIT(&conf->constraints);
  743. if ((file = pushfile(filename)) == NULL) {
  744. return (-1);
  745. }
  746. topfile = file;
  747. yyparse();
  748. errors = file->errors;
  749. popfile();
  750. return (errors ? -1 : 0);
  751. }