GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dvmrpd/parse.y Lines: 0 283 0.0 %
Date: 2017-11-07 Branches: 0 211 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: parse.y,v 1.32 2017/01/05 13:53:09 krw Exp $ */
2
3
/*
4
 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
5
 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
6
 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7
 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
8
 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
9
 * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
10
 *
11
 * Permission to use, copy, modify, and distribute this software for any
12
 * purpose with or without fee is hereby granted, provided that the above
13
 * copyright notice and this permission notice appear in all copies.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
 */
23
24
%{
25
#include <sys/types.h>
26
#include <sys/time.h>
27
#include <sys/stat.h>
28
#include <sys/socket.h>
29
#include <netinet/in.h>
30
#include <arpa/inet.h>
31
#include <net/if.h>
32
#include <ctype.h>
33
#include <err.h>
34
#include <limits.h>
35
#include <unistd.h>
36
#include <errno.h>
37
#include <stdarg.h>
38
#include <stdio.h>
39
#include <string.h>
40
#include <syslog.h>
41
42
#include "igmp.h"
43
#include "dvmrp.h"
44
#include "dvmrpd.h"
45
#include "dvmrpe.h"
46
#include "log.h"
47
48
TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
49
static struct file {
50
	TAILQ_ENTRY(file)	 entry;
51
	FILE			*stream;
52
	char			*name;
53
	int			 lineno;
54
	int			 errors;
55
} *file, *topfile;
56
struct file	*pushfile(const char *, int);
57
int		 popfile(void);
58
int		 check_file_secrecy(int, const char *);
59
int		 yyparse(void);
60
int		 yylex(void);
61
int		 yyerror(const char *, ...)
62
    __attribute__((__format__ (printf, 1, 2)))
63
    __attribute__((__nonnull__ (1)));
64
int		 kw_cmp(const void *, const void *);
65
int		 lookup(char *);
66
int		 lgetc(int);
67
int		 lungetc(int);
68
int		 findeol(void);
69
70
TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
71
struct sym {
72
	TAILQ_ENTRY(sym)	 entry;
73
	int			 used;
74
	int			 persist;
75
	char			*nam;
76
	char			*val;
77
};
78
int		 symset(const char *, const char *, int);
79
char		*symget(const char *);
80
81
static struct dvmrpd_conf	*conf;
82
char				*start_state;
83
struct iface			*iface = NULL;
84
85
static struct {
86
	u_int32_t	 probe_interval;
87
	u_int32_t	 query_interval;
88
	u_int32_t	 query_resp_interval;
89
	u_int32_t	 startup_query_interval;
90
	u_int32_t	 startup_query_cnt;
91
	u_int32_t	 last_member_query_interval;
92
	u_int32_t	 last_member_query_cnt;
93
	u_int32_t	 dead_interval;
94
	u_int16_t	 metric;
95
	u_int8_t	 robustness;
96
	u_int8_t	 igmp_version;
97
} *defs, *grdefs, globaldefs, groupdefs, ifacedefs;
98
99
void		 clear_config(struct dvmrpd_conf *xconf);
100
struct iface	*conf_get_if(struct kif *);
101
struct iface	*new_group(void);
102
103
typedef struct {
104
	union {
105
		int64_t		 number;
106
		char		*string;
107
	} v;
108
	int lineno;
109
} YYSTYPE;
110
111
%}
112
113
%token	INTERFACE FIBUPDATE
114
%token	GROUP
115
%token	METRIC PASSIVE
116
%token	ROBUSTNESS QUERYINTERVAL QUERYRESPINTERVAL
117
%token	STARTUPQUERYINTERVAL STARTUPQUERYCNT
118
%token	LASTMEMBERQUERYINTERVAL LASTMEMBERQUERYCNT
119
%token	IGMPVERSION
120
%token	ERROR
121
%token	<v.string>	STRING
122
%token	<v.number>	NUMBER
123
%type	<v.number>	yesno
124
%type	<v.string>	string
125
126
%%
127
128
grammar		: /* empty */
129
		| grammar '\n'
130
		| grammar conf_main '\n'
131
		| grammar varset '\n'
132
		| grammar interface '\n'
133
		| grammar group '\n'
134
		| grammar error '\n'		{ file->errors++; }
135
		;
136
137
string		: string STRING {
138
			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
139
				free($1);
140
				free($2);
141
				yyerror("string: asprintf");
142
				YYERROR;
143
			}
144
			free($1);
145
			free($2);
146
		}
147
		| STRING
148
		;
149
150
yesno		: STRING {
151
			if (!strcmp($1, "yes"))
152
				$$ = 1;
153
			else if (!strcmp($1, "no"))
154
				$$ = 0;
155
			else {
156
				yyerror("syntax error, "
157
				    "either yes or no expected");
158
				free($1);
159
				YYERROR;
160
			}
161
			free($1);
162
		}
163
		;
164
165
varset		: STRING '=' string		{
166
			char *s = $1;
167
			if (conf->opts & DVMRPD_OPT_VERBOSE)
168
				printf("%s = \"%s\"\n", $1, $3);
169
			while (*s++) {
170
				if (isspace((unsigned char)*s)) {
171
					yyerror("macro name cannot contain "
172
					    "whitespace");
173
					YYERROR;
174
				}
175
			}
176
			if (symset($1, $3, 0) == -1)
177
				fatal("cannot store variable");
178
			free($1);
179
			free($3);
180
		}
181
		;
182
183
conf_main	: FIBUPDATE yesno {
184
			if ($2 == 0)
185
				conf->flags |= DVMRPD_FLAG_NO_FIB_UPDATE;
186
			else
187
				conf->flags &= ~DVMRPD_FLAG_NO_FIB_UPDATE;
188
		}
189
		| defaults
190
		;
191
192
defaults	: LASTMEMBERQUERYCNT NUMBER {
193
			if ($2 < MIN_LAST_MEMBER_QUERY_CNT ||
194
			    $2 > MAX_LAST_MEMBER_QUERY_CNT) {
195
				yyerror("last-member-query-count out of "
196
				    "range (%d-%d)",
197
				    MIN_LAST_MEMBER_QUERY_CNT,
198
				    MAX_LAST_MEMBER_QUERY_CNT);
199
				YYERROR;
200
			}
201
			defs->last_member_query_cnt = $2;
202
		}
203
		| LASTMEMBERQUERYINTERVAL NUMBER {
204
			if ($2 < MIN_LAST_MEMBER_QUERY_INTERVAL ||
205
			    $2 > MAX_LAST_MEMBER_QUERY_INTERVAL) {
206
				yyerror("last-member-query-interval out of "
207
				    "range (%d-%d)",
208
				    MIN_LAST_MEMBER_QUERY_INTERVAL,
209
				    MAX_LAST_MEMBER_QUERY_INTERVAL);
210
				YYERROR;
211
			}
212
			defs->last_member_query_interval = $2;
213
		}
214
		| METRIC NUMBER {
215
			if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
216
				yyerror("metric out of range (%d-%d)",
217
				    MIN_METRIC, MAX_METRIC);
218
				YYERROR;
219
			}
220
			defs->metric = $2;
221
		}
222
		| QUERYINTERVAL NUMBER {
223
			if ($2 < MIN_QUERY_INTERVAL ||
224
			    $2 > MAX_QUERY_INTERVAL) {
225
				yyerror("query-interval out of range (%d-%d)",
226
				    MIN_QUERY_INTERVAL, MAX_QUERY_INTERVAL);
227
				YYERROR;
228
			}
229
			defs->query_interval = $2;
230
		}
231
		| QUERYRESPINTERVAL NUMBER {
232
			if ($2 < MIN_QUERY_RESP_INTERVAL ||
233
			    $2 > MAX_QUERY_RESP_INTERVAL) {
234
				yyerror("query-response-interval out of "
235
				    "range (%d-%d)",
236
				    MIN_QUERY_RESP_INTERVAL,
237
				    MAX_QUERY_RESP_INTERVAL);
238
				YYERROR;
239
			}
240
			defs->query_resp_interval = $2;
241
		}
242
		| ROBUSTNESS NUMBER {
243
			if ($2 < MIN_ROBUSTNESS || $2 > MAX_ROBUSTNESS) {
244
				yyerror("robustness out of range (%d-%d)",
245
				    MIN_ROBUSTNESS, MAX_ROBUSTNESS);
246
				YYERROR;
247
			}
248
			defs->robustness = $2;
249
		}
250
		| STARTUPQUERYCNT NUMBER {
251
			if ($2 < MIN_STARTUP_QUERY_CNT ||
252
			    $2 > MAX_STARTUP_QUERY_CNT) {
253
				yyerror("startup-query-count out of "
254
				    "range (%d-%d)",
255
				    MIN_STARTUP_QUERY_CNT,
256
				    MAX_STARTUP_QUERY_CNT);
257
				YYERROR;
258
			}
259
			defs->startup_query_cnt = $2;
260
		}
261
		| STARTUPQUERYINTERVAL NUMBER {
262
			if ($2 < MIN_STARTUP_QUERY_INTERVAL ||
263
			    $2 > MAX_STARTUP_QUERY_INTERVAL) {
264
				yyerror("startup-query-interval out of "
265
				    "range (%d-%d)",
266
				    MIN_STARTUP_QUERY_INTERVAL,
267
				    MAX_STARTUP_QUERY_INTERVAL);
268
				YYERROR;
269
			}
270
			defs->startup_query_interval = $2;
271
		}
272
		| IGMPVERSION NUMBER {
273
			if ($2 < MIN_IGMP_VERSION ||
274
			    $2 > MAX_IGMP_VERSION) {
275
				yyerror("igmp-version out of range (%d-%d)",
276
				    MIN_IGMP_VERSION, MAX_IGMP_VERSION);
277
				YYERROR;
278
			}
279
			defs->igmp_version = $2;
280
		}
281
		;
282
283
optnl		: '\n' optnl
284
		|
285
		;
286
287
nl		: '\n' optnl		/* one newline or more */
288
		;
289
290
interface	: INTERFACE STRING	{
291
			struct kif *kif;
292
293
			if ((kif = kif_findname($2)) == NULL) {
294
				yyerror("unknown interface %s", $2);
295
				free($2);
296
				YYERROR;
297
			}
298
			free($2);
299
			iface = conf_get_if(kif);
300
			if (iface == NULL)
301
				YYERROR;
302
			LIST_INSERT_HEAD(&conf->iface_list, iface, entry);
303
304
			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
305
			defs = &ifacedefs;
306
		} interface_block {
307
			iface->probe_interval = defs->probe_interval;
308
			iface->query_interval = defs->query_interval;
309
			iface->query_resp_interval = defs->query_resp_interval;
310
			iface->startup_query_interval =
311
			    defs->startup_query_interval;
312
			iface->startup_query_cnt = defs->startup_query_cnt;
313
			iface->last_member_query_interval =
314
			    defs->last_member_query_interval;
315
			iface->last_member_query_cnt =
316
			    defs->last_member_query_cnt;
317
			iface->dead_interval = defs->dead_interval;
318
			iface->metric = defs->metric;
319
			iface->robustness = defs->robustness;
320
			iface->igmp_version = defs->igmp_version;
321
			if (grdefs)
322
				defs = grdefs;
323
			else
324
				defs = &globaldefs;
325
			iface = NULL;
326
		}
327
		;
328
329
interface_block	: '{' optnl interfaceopts_l '}'
330
		| '{' optnl '}'
331
		|
332
		;
333
334
interfaceopts_l	: interfaceopts_l interfaceoptsl
335
		| interfaceoptsl
336
		;
337
338
interfaceoptsl	: PASSIVE nl		{ iface->passive = 1; }
339
		| defaults nl
340
		;
341
342
group		: GROUP optnl '{' optnl {
343
			memcpy(&groupdefs, defs, sizeof(groupdefs));
344
			grdefs = defs = &groupdefs;
345
		}
346
		    groupopts_l '}' {
347
			grdefs = NULL;
348
			defs = &globaldefs;
349
		}
350
		;
351
352
groupopts_l	: groupopts_l groupoptsl
353
		| groupoptsl
354
		;
355
356
groupoptsl	: interface nl
357
		| defaults nl
358
		| error nl
359
		;
360
361
%%
362
363
struct keywords {
364
	const char	*k_name;
365
	int		 k_val;
366
};
367
368
int
369
yyerror(const char *fmt, ...)
370
{
371
	va_list		 ap;
372
	char		*msg;
373
374
	file->errors++;
375
	va_start(ap, fmt);
376
	if (vasprintf(&msg, fmt, ap) == -1)
377
		fatalx("yyerror vasprintf");
378
	va_end(ap);
379
	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
380
	free(msg);
381
	return (0);
382
}
383
384
int
385
kw_cmp(const void *k, const void *e)
386
{
387
	return (strcmp(k, ((const struct keywords *)e)->k_name));
388
}
389
390
int
391
lookup(char *s)
392
{
393
	/* this has to be sorted always */
394
	static const struct keywords keywords[] = {
395
		{"fib-update",			FIBUPDATE},
396
		{"group",			GROUP},
397
		{"igmp-version",		IGMPVERSION},
398
		{"interface",			INTERFACE},
399
		{"last-member-query-count",	LASTMEMBERQUERYCNT},
400
		{"last-member-query-interval",	LASTMEMBERQUERYINTERVAL},
401
		{"metric",			METRIC},
402
		{"passive",			PASSIVE},
403
		{"query-interval",		QUERYINTERVAL},
404
		{"query-response-interval",	QUERYRESPINTERVAL},
405
		{"robustness",			ROBUSTNESS},
406
		{"startup-query-count",		STARTUPQUERYCNT},
407
		{"startup-query-interval",	STARTUPQUERYINTERVAL}
408
	};
409
	const struct keywords	*p;
410
411
	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
412
	    sizeof(keywords[0]), kw_cmp);
413
414
	if (p)
415
		return (p->k_val);
416
	else
417
		return (STRING);
418
}
419
420
#define MAXPUSHBACK	128
421
422
u_char	*parsebuf;
423
int	 parseindex;
424
u_char	 pushback_buffer[MAXPUSHBACK];
425
int	 pushback_index = 0;
426
427
int
428
lgetc(int quotec)
429
{
430
	int		c, next;
431
432
	if (parsebuf) {
433
		/* Read character from the parsebuffer instead of input. */
434
		if (parseindex >= 0) {
435
			c = parsebuf[parseindex++];
436
			if (c != '\0')
437
				return (c);
438
			parsebuf = NULL;
439
		} else
440
			parseindex++;
441
	}
442
443
	if (pushback_index)
444
		return (pushback_buffer[--pushback_index]);
445
446
	if (quotec) {
447
		if ((c = getc(file->stream)) == EOF) {
448
			yyerror("reached end of file while parsing "
449
			    "quoted string");
450
			if (file == topfile || popfile() == EOF)
451
				return (EOF);
452
			return (quotec);
453
		}
454
		return (c);
455
	}
456
457
	while ((c = getc(file->stream)) == '\\') {
458
		next = getc(file->stream);
459
		if (next != '\n') {
460
			c = next;
461
			break;
462
		}
463
		yylval.lineno = file->lineno;
464
		file->lineno++;
465
	}
466
467
	while (c == EOF) {
468
		if (file == topfile || popfile() == EOF)
469
			return (EOF);
470
		c = getc(file->stream);
471
	}
472
	return (c);
473
}
474
475
int
476
lungetc(int c)
477
{
478
	if (c == EOF)
479
		return (EOF);
480
	if (parsebuf) {
481
		parseindex--;
482
		if (parseindex >= 0)
483
			return (c);
484
	}
485
	if (pushback_index < MAXPUSHBACK-1)
486
		return (pushback_buffer[pushback_index++] = c);
487
	else
488
		return (EOF);
489
}
490
491
int
492
findeol(void)
493
{
494
	int	c;
495
496
	parsebuf = NULL;
497
498
	/* skip to either EOF or the first real EOL */
499
	while (1) {
500
		if (pushback_index)
501
			c = pushback_buffer[--pushback_index];
502
		else
503
			c = lgetc(0);
504
		if (c == '\n') {
505
			file->lineno++;
506
			break;
507
		}
508
		if (c == EOF)
509
			break;
510
	}
511
	return (ERROR);
512
}
513
514
int
515
yylex(void)
516
{
517
	u_char	 buf[8096];
518
	u_char	*p, *val;
519
	int	 quotec, next, c;
520
	int	 token;
521
522
top:
523
	p = buf;
524
	while ((c = lgetc(0)) == ' ' || c == '\t')
525
		; /* nothing */
526
527
	yylval.lineno = file->lineno;
528
	if (c == '#')
529
		while ((c = lgetc(0)) != '\n' && c != EOF)
530
			; /* nothing */
531
	if (c == '$' && parsebuf == NULL) {
532
		while (1) {
533
			if ((c = lgetc(0)) == EOF)
534
				return (0);
535
536
			if (p + 1 >= buf + sizeof(buf) - 1) {
537
				yyerror("string too long");
538
				return (findeol());
539
			}
540
			if (isalnum(c) || c == '_') {
541
				*p++ = c;
542
				continue;
543
			}
544
			*p = '\0';
545
			lungetc(c);
546
			break;
547
		}
548
		val = symget(buf);
549
		if (val == NULL) {
550
			yyerror("macro '%s' not defined", buf);
551
			return (findeol());
552
		}
553
		parsebuf = val;
554
		parseindex = 0;
555
		goto top;
556
	}
557
558
	switch (c) {
559
	case '\'':
560
	case '"':
561
		quotec = c;
562
		while (1) {
563
			if ((c = lgetc(quotec)) == EOF)
564
				return (0);
565
			if (c == '\n') {
566
				file->lineno++;
567
				continue;
568
			} else if (c == '\\') {
569
				if ((next = lgetc(quotec)) == EOF)
570
					return (0);
571
				if (next == quotec || c == ' ' || c == '\t')
572
					c = next;
573
				else if (next == '\n') {
574
					file->lineno++;
575
					continue;
576
				} else
577
					lungetc(next);
578
			} else if (c == quotec) {
579
				*p = '\0';
580
				break;
581
			} else if (c == '\0') {
582
				yyerror("syntax error");
583
				return (findeol());
584
			}
585
			if (p + 1 >= buf + sizeof(buf) - 1) {
586
				yyerror("string too long");
587
				return (findeol());
588
			}
589
			*p++ = c;
590
		}
591
		yylval.v.string = strdup(buf);
592
		if (yylval.v.string == NULL)
593
			err(1, "yylex: strdup");
594
		return (STRING);
595
	}
596
597
#define allowed_to_end_number(x) \
598
	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
599
600
	if (c == '-' || isdigit(c)) {
601
		do {
602
			*p++ = c;
603
			if ((unsigned)(p-buf) >= sizeof(buf)) {
604
				yyerror("string too long");
605
				return (findeol());
606
			}
607
		} while ((c = lgetc(0)) != EOF && isdigit(c));
608
		lungetc(c);
609
		if (p == buf + 1 && buf[0] == '-')
610
			goto nodigits;
611
		if (c == EOF || allowed_to_end_number(c)) {
612
			const char *errstr = NULL;
613
614
			*p = '\0';
615
			yylval.v.number = strtonum(buf, LLONG_MIN,
616
			    LLONG_MAX, &errstr);
617
			if (errstr) {
618
				yyerror("\"%s\" invalid number: %s",
619
				    buf, errstr);
620
				return (findeol());
621
			}
622
			return (NUMBER);
623
		} else {
624
nodigits:
625
			while (p > buf + 1)
626
				lungetc(*--p);
627
			c = *--p;
628
			if (c == '-')
629
				return (c);
630
		}
631
	}
632
633
#define allowed_in_string(x) \
634
	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
635
	x != '{' && x != '}' && \
636
	x != '!' && x != '=' && x != '#' && \
637
	x != ','))
638
639
	if (isalnum(c) || c == ':' || c == '_') {
640
		do {
641
			*p++ = c;
642
			if ((unsigned)(p-buf) >= sizeof(buf)) {
643
				yyerror("string too long");
644
				return (findeol());
645
			}
646
		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
647
		lungetc(c);
648
		*p = '\0';
649
		if ((token = lookup(buf)) == STRING)
650
			if ((yylval.v.string = strdup(buf)) == NULL)
651
				err(1, "yylex: strdup");
652
		return (token);
653
	}
654
	if (c == '\n') {
655
		yylval.lineno = file->lineno;
656
		file->lineno++;
657
	}
658
	if (c == EOF)
659
		return (0);
660
	return (c);
661
}
662
663
int
664
check_file_secrecy(int fd, const char *fname)
665
{
666
	struct stat	st;
667
668
	if (fstat(fd, &st)) {
669
		log_warn("cannot stat %s", fname);
670
		return (-1);
671
	}
672
	if (st.st_uid != 0 && st.st_uid != getuid()) {
673
		log_warnx("%s: owner not root or current user", fname);
674
		return (-1);
675
	}
676
	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
677
		log_warnx("%s: group writable or world read/writable", fname);
678
		return (-1);
679
	}
680
	return (0);
681
}
682
683
struct file *
684
pushfile(const char *name, int secret)
685
{
686
	struct file	*nfile;
687
688
	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
689
		log_warn("malloc");
690
		return (NULL);
691
	}
692
	if ((nfile->name = strdup(name)) == NULL) {
693
		log_warn("malloc");
694
		free(nfile);
695
		return (NULL);
696
	}
697
	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
698
		log_warn("%s", nfile->name);
699
		free(nfile->name);
700
		free(nfile);
701
		return (NULL);
702
	} else if (secret &&
703
	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
704
		fclose(nfile->stream);
705
		free(nfile->name);
706
		free(nfile);
707
		return (NULL);
708
	}
709
	nfile->lineno = 1;
710
	TAILQ_INSERT_TAIL(&files, nfile, entry);
711
	return (nfile);
712
}
713
714
int
715
popfile(void)
716
{
717
	struct file	*prev;
718
719
	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
720
		prev->errors += file->errors;
721
722
	TAILQ_REMOVE(&files, file, entry);
723
	fclose(file->stream);
724
	free(file->name);
725
	free(file);
726
	file = prev;
727
	return (file ? 0 : EOF);
728
}
729
730
struct dvmrpd_conf *
731
parse_config(char *filename, int opts)
732
{
733
	int		 errors = 0;
734
	struct sym	*sym, *next;
735
	struct timeval	 now;
736
737
	if ((conf = calloc(1, sizeof(struct dvmrpd_conf))) == NULL) {
738
		errx(1, "parse_config calloc");
739
		return (NULL);
740
	}
741
742
	defs = &globaldefs;
743
	defs->probe_interval = DEFAULT_PROBE_INTERVAL;
744
	defs->last_member_query_cnt = DEFAULT_LAST_MEMBER_QUERY_CNT;
745
	defs->last_member_query_interval = DEFAULT_LAST_MEMBER_QUERY_INTERVAL;
746
	defs->metric = DEFAULT_METRIC;
747
	defs->query_interval = DEFAULT_QUERY_INTERVAL;
748
	defs->query_resp_interval = DEFAULT_QUERY_RESP_INTERVAL;
749
	defs->robustness = DEFAULT_ROBUSTNESS;
750
	defs->startup_query_cnt = DEFAULT_STARTUP_QUERY_CNT;
751
	defs->startup_query_interval = DEFAULT_STARTUP_QUERY_INTERVAL;
752
	defs->igmp_version = DEFAULT_IGMP_VERSION;
753
	defs->dead_interval = NBR_TMOUT;
754
755
	if ((file = pushfile(filename, 1)) == NULL) {
756
		free(conf);
757
		return (NULL);
758
	}
759
	topfile = file;
760
761
	gettimeofday(&now, NULL);
762
	conf->gen_id = (u_int32_t)now.tv_sec;	/* for a while after 2038 */
763
	conf->opts = opts;
764
765
	yyparse();
766
	errors = file->errors;
767
	popfile();
768
769
	/* Free macros and check which have not been used. */
770
	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
771
		if ((conf->opts & DVMRPD_OPT_VERBOSE2) && !sym->used)
772
			fprintf(stderr, "warning: macro '%s' not "
773
			    "used\n", sym->nam);
774
		if (!sym->persist) {
775
			free(sym->nam);
776
			free(sym->val);
777
			TAILQ_REMOVE(&symhead, sym, entry);
778
			free(sym);
779
		}
780
	}
781
782
	if (errors) {
783
		clear_config(conf);
784
		return (NULL);
785
	}
786
787
	return (conf);
788
}
789
790
int
791
symset(const char *nam, const char *val, int persist)
792
{
793
	struct sym	*sym;
794
795
	TAILQ_FOREACH(sym, &symhead, entry) {
796
		if (strcmp(nam, sym->nam) == 0)
797
			break;
798
	}
799
800
	if (sym != NULL) {
801
		if (sym->persist == 1)
802
			return (0);
803
		else {
804
			free(sym->nam);
805
			free(sym->val);
806
			TAILQ_REMOVE(&symhead, sym, entry);
807
			free(sym);
808
		}
809
	}
810
	if ((sym = calloc(1, sizeof(*sym))) == NULL)
811
		return (-1);
812
813
	sym->nam = strdup(nam);
814
	if (sym->nam == NULL) {
815
		free(sym);
816
		return (-1);
817
	}
818
	sym->val = strdup(val);
819
	if (sym->val == NULL) {
820
		free(sym->nam);
821
		free(sym);
822
		return (-1);
823
	}
824
	sym->used = 0;
825
	sym->persist = persist;
826
	TAILQ_INSERT_TAIL(&symhead, sym, entry);
827
	return (0);
828
}
829
830
int
831
cmdline_symset(char *s)
832
{
833
	char	*sym, *val;
834
	int	ret;
835
	size_t	len;
836
837
	if ((val = strrchr(s, '=')) == NULL)
838
		return (-1);
839
840
	len = strlen(s) - strlen(val) + 1;
841
	if ((sym = malloc(len)) == NULL)
842
		errx(1, "cmdline_symset: malloc");
843
844
	strlcpy(sym, s, len);
845
846
	ret = symset(sym, val + 1, 1);
847
	free(sym);
848
849
	return (ret);
850
}
851
852
char *
853
symget(const char *nam)
854
{
855
	struct sym	*sym;
856
857
	TAILQ_FOREACH(sym, &symhead, entry) {
858
		if (strcmp(nam, sym->nam) == 0) {
859
			sym->used = 1;
860
			return (sym->val);
861
		}
862
	}
863
	return (NULL);
864
}
865
866
struct iface *
867
conf_get_if(struct kif *kif)
868
{
869
	struct iface	*i;
870
871
	if (kif->ifindex >= MAXVIFS) {
872
		yyerror("interface %s index too large", kif->ifname);
873
		return (NULL);
874
	}
875
876
	LIST_FOREACH(i, &conf->iface_list, entry)
877
		if (i->ifindex == kif->ifindex) {
878
			yyerror("interface %s already configured",
879
			    kif->ifname);
880
			return (NULL);
881
		}
882
883
	i = if_new(kif);
884
	i->passive = 0;
885
	i->recv_query_resp_interval = DEFAULT_QUERY_RESP_INTERVAL;
886
887
	return (i);
888
}
889
890
void
891
clear_config(struct dvmrpd_conf *xconf)
892
{
893
	/* XXX clear conf */
894
		/* ... */
895
}