xref: /openbsd-src/usr.sbin/ifstated/parse.y (revision 08f6ba1906d01c4a24fa700d568400f71bcf9611)
1*08f6ba19Snaddy /*	$OpenBSD: parse.y,v 1.56 2021/10/15 15:01:28 naddy Exp $	*/
2b73b88efSmcbride 
3b73b88efSmcbride /*
4b73b88efSmcbride  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
5b73b88efSmcbride  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
6b73b88efSmcbride  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
7b73b88efSmcbride  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
8b73b88efSmcbride  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
9b73b88efSmcbride  *
10b73b88efSmcbride  * Permission to use, copy, modify, and distribute this software for any
11b73b88efSmcbride  * purpose with or without fee is hereby granted, provided that the above
12b73b88efSmcbride  * copyright notice and this permission notice appear in all copies.
13b73b88efSmcbride  *
14b73b88efSmcbride  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15b73b88efSmcbride  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16b73b88efSmcbride  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17b73b88efSmcbride  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18b73b88efSmcbride  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19b73b88efSmcbride  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20b73b88efSmcbride  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21b73b88efSmcbride  */
22b73b88efSmcbride 
23b73b88efSmcbride %{
24b73b88efSmcbride #include <sys/types.h>
25b73b88efSmcbride #include <sys/time.h>
26b73b88efSmcbride #include <sys/socket.h>
2720741916Sderaadt #include <sys/stat.h>
28b73b88efSmcbride #include <netinet/in.h>
29b73b88efSmcbride #include <arpa/inet.h>
30b73b88efSmcbride #include <net/if.h>
31b73b88efSmcbride 
32b73b88efSmcbride #include <ctype.h>
3320741916Sderaadt #include <unistd.h>
34b73b88efSmcbride #include <err.h>
35b73b88efSmcbride #include <errno.h>
3620741916Sderaadt #include <limits.h>
37b73b88efSmcbride #include <stdarg.h>
38b73b88efSmcbride #include <stdio.h>
39b73b88efSmcbride #include <string.h>
40b73b88efSmcbride #include <syslog.h>
41b73b88efSmcbride #include <event.h>
42b73b88efSmcbride 
43b73b88efSmcbride #include "ifstated.h"
44bfdb9ad4Sbenno #include "log.h"
45b73b88efSmcbride 
4620741916Sderaadt TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
4720741916Sderaadt static struct file {
4820741916Sderaadt 	TAILQ_ENTRY(file)	 entry;
4920741916Sderaadt 	FILE			*stream;
5020741916Sderaadt 	char			*name;
5120741916Sderaadt 	int			 lineno;
5220741916Sderaadt 	int			 errors;
53c6004ab9Smpf } *file, *topfile;
5420741916Sderaadt struct file	*pushfile(const char *, int);
5520741916Sderaadt int		 popfile(void);
5620741916Sderaadt int		 check_file_secrecy(int, const char *);
57b73b88efSmcbride int		 yyparse(void);
5820741916Sderaadt int		 yylex(void);
597fe19e9cSdoug int		 yyerror(const char *, ...)
607fe19e9cSdoug     __attribute__((__format__ (printf, 1, 2)))
617fe19e9cSdoug     __attribute__((__nonnull__ (1)));
62b73b88efSmcbride int		 kw_cmp(const void *, const void *);
63b73b88efSmcbride int		 lookup(char *);
64d5d66eaeSderaadt int		 lgetc(int);
65b73b88efSmcbride int		 lungetc(int);
66b73b88efSmcbride int		 findeol(void);
67b73b88efSmcbride 
68b73b88efSmcbride TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
69b73b88efSmcbride struct sym {
7020741916Sderaadt 	TAILQ_ENTRY(sym)	 entry;
71b73b88efSmcbride 	int			 used;
72b73b88efSmcbride 	int			 persist;
73b73b88efSmcbride 	char			*nam;
74b73b88efSmcbride 	char			*val;
75b73b88efSmcbride };
76b73b88efSmcbride int		 symset(const char *, const char *, int);
77b73b88efSmcbride char		*symget(const char *);
7820741916Sderaadt 
7920741916Sderaadt static struct ifsd_config	*conf;
8020741916Sderaadt char				*start_state;
8120741916Sderaadt 
8220741916Sderaadt struct ifsd_action		*curaction;
83d64c7ac9Sderaadt struct ifsd_state		*curstate;
8420741916Sderaadt 
8520741916Sderaadt void			 link_states(struct ifsd_action *);
86b73b88efSmcbride void			 set_expression_depth(struct ifsd_expression *, int);
87b73b88efSmcbride void			 init_state(struct ifsd_state *);
8818e4260cSrob struct ifsd_ifstate	*new_ifstate(char *, int);
89b73b88efSmcbride struct ifsd_external	*new_external(char *, u_int32_t);
90b73b88efSmcbride 
91b73b88efSmcbride typedef struct {
92b73b88efSmcbride 	union {
9339c88d90Sderaadt 		int64_t		 number;
94b73b88efSmcbride 		char		*string;
95b73b88efSmcbride 		struct in_addr	 addr;
96b73b88efSmcbride 
97b73b88efSmcbride 		struct ifsd_expression	*expression;
98b73b88efSmcbride 		struct ifsd_ifstate	*ifstate;
99b73b88efSmcbride 		struct ifsd_external	*external;
100b73b88efSmcbride 
101b73b88efSmcbride 	} v;
102b73b88efSmcbride 	int lineno;
103b73b88efSmcbride } YYSTYPE;
104b73b88efSmcbride 
105b73b88efSmcbride %}
106b73b88efSmcbride 
107b73b88efSmcbride %token	STATE INITSTATE
108ac553da5Sbenno %token	LINK UP DOWN UNKNOWN
10935360db1Spyr %token	IF RUN SETSTATE EVERY INIT
110b73b88efSmcbride %left	AND OR
111b73b88efSmcbride %left	UNARY
112b73b88efSmcbride %token	ERROR
113b73b88efSmcbride %token	<v.string>	STRING
11439c88d90Sderaadt %token	<v.number>	NUMBER
115b73b88efSmcbride %type	<v.string>	string
11618e4260cSrob %type	<v.string>	interface
117b73b88efSmcbride %type	<v.ifstate>	if_test
118b73b88efSmcbride %type	<v.external>	ext_test
119b73b88efSmcbride %type	<v.expression>	expr term
120b73b88efSmcbride %%
121b73b88efSmcbride 
122b73b88efSmcbride grammar		: /* empty */
123b73b88efSmcbride 		| grammar '\n'
124b73b88efSmcbride 		| grammar conf_main '\n'
125b73b88efSmcbride 		| grammar varset '\n'
126b73b88efSmcbride 		| grammar action '\n'
127b73b88efSmcbride 		| grammar state '\n'
12820741916Sderaadt 		| grammar error '\n'		{ file->errors++; }
129b73b88efSmcbride 		;
130b73b88efSmcbride 
131b73b88efSmcbride string		: string STRING				{
132b73b88efSmcbride 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
13332c20dfcShenning 				free($1);
13432c20dfcShenning 				free($2);
135b73b88efSmcbride 				yyerror("string: asprintf");
136b73b88efSmcbride 				YYERROR;
137b73b88efSmcbride 			}
138b73b88efSmcbride 			free($1);
139b73b88efSmcbride 			free($2);
140b73b88efSmcbride 		}
141b73b88efSmcbride 		| STRING
142b73b88efSmcbride 		;
143b73b88efSmcbride 
144b73b88efSmcbride varset		: STRING '=' string		{
1450c7b4ca6Sbenno 			char *s = $1;
146b73b88efSmcbride 			if (conf->opts & IFSD_OPT_VERBOSE)
147b73b88efSmcbride 				printf("%s = \"%s\"\n", $1, $3);
1480c7b4ca6Sbenno 			while (*s++) {
1490c7b4ca6Sbenno 				if (isspace((unsigned char)*s)) {
1500c7b4ca6Sbenno 					yyerror("macro name cannot contain "
1510c7b4ca6Sbenno 					    "whitespace");
15216a0a906Skrw 					free($1);
15316a0a906Skrw 					free($3);
1540c7b4ca6Sbenno 					YYERROR;
1550c7b4ca6Sbenno 				}
1560c7b4ca6Sbenno 			}
157b73b88efSmcbride 			if (symset($1, $3, 0) == -1) {
15832c20dfcShenning 				free($1);
15932c20dfcShenning 				free($3);
160b73b88efSmcbride 				yyerror("cannot store variable");
161b73b88efSmcbride 				YYERROR;
162b73b88efSmcbride 			}
16332c20dfcShenning 			free($1);
16432c20dfcShenning 			free($3);
165b73b88efSmcbride 		}
166b73b88efSmcbride 		;
167b73b88efSmcbride 
168b73b88efSmcbride conf_main	: INITSTATE STRING		{
16932c20dfcShenning 			start_state = $2;
170b73b88efSmcbride 		}
171b73b88efSmcbride 		;
172b73b88efSmcbride 
173b73b88efSmcbride interface	: STRING		{
17418e4260cSrob 			if (if_nametoindex($1) == 0) {
175b73b88efSmcbride 				yyerror("unknown interface %s", $1);
17632c20dfcShenning 				free($1);
177b73b88efSmcbride 				YYERROR;
178b73b88efSmcbride 			}
17918e4260cSrob 			$$ = $1;
180b73b88efSmcbride 		}
181b73b88efSmcbride 		;
182b73b88efSmcbride 
183b73b88efSmcbride optnl		: '\n' optnl
184b73b88efSmcbride 		|
185b73b88efSmcbride 		;
186b73b88efSmcbride 
187b73b88efSmcbride nl		: '\n' optnl		/* one newline or more */
188b73b88efSmcbride 		;
189b73b88efSmcbride 
190b73b88efSmcbride action		: RUN STRING		{
191b73b88efSmcbride 			struct ifsd_action *action;
192b73b88efSmcbride 
193b73b88efSmcbride 			if ((action = calloc(1, sizeof(*action))) == NULL)
194b73b88efSmcbride 				err(1, "action: calloc");
195b73b88efSmcbride 			action->type = IFSD_ACTION_COMMAND;
19632c20dfcShenning 			action->act.command = $2;
197b73b88efSmcbride 			TAILQ_INSERT_TAIL(&curaction->act.c.actions,
198b73b88efSmcbride 			    action, entries);
199b73b88efSmcbride 		}
200b73b88efSmcbride 		| SETSTATE STRING	{
201b73b88efSmcbride 			struct ifsd_action *action;
202b73b88efSmcbride 
203b73b88efSmcbride 			if (curstate == NULL) {
20432c20dfcShenning 				free($2);
205f03638d1Smcbride 				yyerror("set-state must be used inside 'if'");
206b73b88efSmcbride 				YYERROR;
207b73b88efSmcbride 			}
208b73b88efSmcbride 			if ((action = calloc(1, sizeof(*action))) == NULL)
209b73b88efSmcbride 				err(1, "action: calloc");
210b73b88efSmcbride 			action->type = IFSD_ACTION_CHANGESTATE;
21132c20dfcShenning 			action->act.statename = $2;
212b73b88efSmcbride 			TAILQ_INSERT_TAIL(&curaction->act.c.actions,
213b73b88efSmcbride 			    action, entries);
214b73b88efSmcbride 		}
215b73b88efSmcbride 		| IF {
216b73b88efSmcbride 			struct ifsd_action *action;
217b73b88efSmcbride 
218b73b88efSmcbride 			if ((action = calloc(1, sizeof(*action))) == NULL)
219b73b88efSmcbride 				err(1, "action: calloc");
220b73b88efSmcbride 			action->type = IFSD_ACTION_CONDITION;
221b73b88efSmcbride 			TAILQ_INIT(&action->act.c.actions);
222b73b88efSmcbride 			TAILQ_INSERT_TAIL(&curaction->act.c.actions,
223b73b88efSmcbride 			    action, entries);
224b73b88efSmcbride 			action->parent = curaction;
225b73b88efSmcbride 			curaction = action;
22642b18258Smpf 		} expr action_block {
227b73b88efSmcbride 			set_expression_depth(curaction->act.c.expression, 0);
228b73b88efSmcbride 			curaction = curaction->parent;
229b73b88efSmcbride 		}
230b73b88efSmcbride 		;
231b73b88efSmcbride 
23242b18258Smpf action_block	: optnl '{' optnl action_l '}'
23342b18258Smpf 		| optnl action
23442b18258Smpf 		;
23542b18258Smpf 
236b73b88efSmcbride action_l	: action_l action nl
237b73b88efSmcbride 		| action nl
238b73b88efSmcbride 		;
239b73b88efSmcbride 
240b73b88efSmcbride init		: INIT {
241b73b88efSmcbride 			if (curstate != NULL)
242b73b88efSmcbride 				curaction = curstate->init;
243b73b88efSmcbride 			else
24420863243Sbenno 				curaction = conf->initstate.init;
2454726560cSsturm 		} action_block {
246b73b88efSmcbride 			if (curstate != NULL)
247138e089fSbenno 				curaction = curstate->body;
248b73b88efSmcbride 			else
24920863243Sbenno 				curaction = conf->initstate.body;
250b73b88efSmcbride 		}
25197c59c6cSderaadt 		;
252b73b88efSmcbride 
25342b18258Smpf if_test		: interface '.' LINK '.' UP		{
254b73b88efSmcbride 			$$ = new_ifstate($1, IFSD_LINKUP);
255b73b88efSmcbride 		}
25642b18258Smpf 		| interface '.' LINK '.' DOWN		{
257b73b88efSmcbride 			$$ = new_ifstate($1, IFSD_LINKDOWN);
258b73b88efSmcbride 		}
25942b18258Smpf 		| interface '.' LINK '.' UNKNOWN	{
260b73b88efSmcbride 			$$ = new_ifstate($1, IFSD_LINKUNKNOWN);
261b73b88efSmcbride 		}
262b73b88efSmcbride 		;
263b73b88efSmcbride 
26439c88d90Sderaadt ext_test	: STRING EVERY NUMBER {
26565cb20dfSderaadt 			if ($3 <= 0 || $3 > UINT_MAX) {
2667fe19e9cSdoug 				yyerror("invalid interval: %lld", $3);
26739c88d90Sderaadt 				free($1);
26839c88d90Sderaadt 				YYERROR;
26939c88d90Sderaadt 			}
270b73b88efSmcbride 			$$ = new_external($1, $3);
27132c20dfcShenning 			free($1);
272b73b88efSmcbride 		}
273b73b88efSmcbride 		;
274b73b88efSmcbride 
275b73b88efSmcbride term		: if_test {
276b73b88efSmcbride 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
277e9514afcSmmcc 				err(1, NULL);
278b73b88efSmcbride 			curaction->act.c.expression = $$;
279b73b88efSmcbride 			$$->type = IFSD_OPER_IFSTATE;
280b73b88efSmcbride 			$$->u.ifstate = $1;
281b73b88efSmcbride 			TAILQ_INSERT_TAIL(&$1->expressions, $$, entries);
282b73b88efSmcbride 		}
283b73b88efSmcbride 		| ext_test {
284b73b88efSmcbride 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
285e9514afcSmmcc 				err(1, NULL);
286b73b88efSmcbride 			curaction->act.c.expression = $$;
287b73b88efSmcbride 			$$->type = IFSD_OPER_EXTERNAL;
288b73b88efSmcbride 			$$->u.external = $1;
289b73b88efSmcbride 			TAILQ_INSERT_TAIL(&$1->expressions, $$, entries);
290b73b88efSmcbride 		}
291b73b88efSmcbride 		| '(' expr ')'			{
292b73b88efSmcbride 			$$ = $2;
293b73b88efSmcbride 		}
294b73b88efSmcbride 		;
295b73b88efSmcbride 
296b73b88efSmcbride expr		: '!' expr %prec UNARY			{
297b73b88efSmcbride 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
298e9514afcSmmcc 				err(1, NULL);
299b73b88efSmcbride 			curaction->act.c.expression = $$;
300b73b88efSmcbride 			$$->type = IFSD_OPER_NOT;
301b73b88efSmcbride 			$2->parent = $$;
302b73b88efSmcbride 			$$->right = $2;
303b73b88efSmcbride 		}
304b73b88efSmcbride 		| expr AND expr			{
305b73b88efSmcbride 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
306e9514afcSmmcc 				err(1, NULL);
307b73b88efSmcbride 			curaction->act.c.expression = $$;
308b73b88efSmcbride 			$$->type = IFSD_OPER_AND;
309b73b88efSmcbride 			$1->parent = $$;
310b73b88efSmcbride 			$3->parent = $$;
311b73b88efSmcbride 			$$->left = $1;
312b73b88efSmcbride 			$$->right = $3;
313b73b88efSmcbride 		}
314b73b88efSmcbride 		| expr OR expr			{
315b73b88efSmcbride 			if (($$ = calloc(1, sizeof(*$$))) == NULL)
316e9514afcSmmcc 				err(1, NULL);
317b73b88efSmcbride 			curaction->act.c.expression = $$;
318b73b88efSmcbride 			$$->type = IFSD_OPER_OR;
319b73b88efSmcbride 			$1->parent = $$;
320b73b88efSmcbride 			$3->parent = $$;
321b73b88efSmcbride 			$$->left = $1;
322b73b88efSmcbride 			$$->right = $3;
323b73b88efSmcbride 		}
324b73b88efSmcbride 		| term
325b73b88efSmcbride 		;
326b73b88efSmcbride 
327b73b88efSmcbride state		: STATE string {
328b73b88efSmcbride 			struct ifsd_state *state = NULL;
329b73b88efSmcbride 
330b73b88efSmcbride 			TAILQ_FOREACH(state, &conf->states, entries)
331b73b88efSmcbride 				if (!strcmp(state->name, $2)) {
332b73b88efSmcbride 					yyerror("state %s already exists", $2);
33332c20dfcShenning 					free($2);
334b73b88efSmcbride 					YYERROR;
335b73b88efSmcbride 				}
336b73b88efSmcbride 			if ((state = calloc(1, sizeof(*curstate))) == NULL)
337e9514afcSmmcc 				err(1, NULL);
338b73b88efSmcbride 			init_state(state);
33932c20dfcShenning 			state->name = $2;
340b73b88efSmcbride 			curstate = state;
341138e089fSbenno 			curaction = state->body;
342b73b88efSmcbride 		} optnl '{' optnl stateopts_l '}' {
343b73b88efSmcbride 			TAILQ_INSERT_TAIL(&conf->states, curstate, entries);
344b73b88efSmcbride 			curstate = NULL;
34520863243Sbenno 			curaction = conf->initstate.body;
346b73b88efSmcbride 		}
347b73b88efSmcbride 		;
348b73b88efSmcbride 
349b73b88efSmcbride stateopts_l	: stateopts_l stateoptsl
350b73b88efSmcbride 		| stateoptsl
351b73b88efSmcbride 		;
352b73b88efSmcbride 
353b73b88efSmcbride stateoptsl	: init nl
354b73b88efSmcbride 		| action nl
355b73b88efSmcbride 		;
356b73b88efSmcbride 
357b73b88efSmcbride %%
358b73b88efSmcbride 
359b73b88efSmcbride struct keywords {
360b73b88efSmcbride 	const char	*k_name;
361b73b88efSmcbride 	int		 k_val;
362b73b88efSmcbride };
363b73b88efSmcbride 
364b73b88efSmcbride int
yyerror(const char * fmt,...)365b73b88efSmcbride yyerror(const char *fmt, ...)
366b73b88efSmcbride {
367b73b88efSmcbride 	va_list		 ap;
368e3490c9cSbluhm 	char		*msg;
369b73b88efSmcbride 
37020741916Sderaadt 	file->errors++;
371b73b88efSmcbride 	va_start(ap, fmt);
372e3490c9cSbluhm 	if (vasprintf(&msg, fmt, ap) == -1)
373e3490c9cSbluhm 		fatalx("yyerror vasprintf");
374b73b88efSmcbride 	va_end(ap);
375e3490c9cSbluhm 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
376e3490c9cSbluhm 	free(msg);
377b73b88efSmcbride 	return (0);
378b73b88efSmcbride }
379b73b88efSmcbride 
380b73b88efSmcbride int
kw_cmp(const void * k,const void * e)381b73b88efSmcbride kw_cmp(const void *k, const void *e)
382b73b88efSmcbride {
383b73b88efSmcbride 	return (strcmp(k, ((const struct keywords *)e)->k_name));
384b73b88efSmcbride }
385b73b88efSmcbride 
386b73b88efSmcbride int
lookup(char * s)387b73b88efSmcbride lookup(char *s)
388b73b88efSmcbride {
389b73b88efSmcbride 	/* this has to be sorted always */
390b73b88efSmcbride 	static const struct keywords keywords[] = {
39142b18258Smpf 		{ "&&",			AND},
392b73b88efSmcbride 		{ "down",		DOWN},
393b73b88efSmcbride 		{ "every",		EVERY},
394b73b88efSmcbride 		{ "if",			IF},
395b73b88efSmcbride 		{ "init",		INIT},
396b73b88efSmcbride 		{ "init-state",		INITSTATE},
397b73b88efSmcbride 		{ "link",		LINK},
398b73b88efSmcbride 		{ "run",		RUN},
399b73b88efSmcbride 		{ "set-state",		SETSTATE},
400b73b88efSmcbride 		{ "state",		STATE},
401b73b88efSmcbride 		{ "unknown",		UNKNOWN},
40242b18258Smpf 		{ "up",			UP},
40342b18258Smpf 		{ "||",			OR}
404b73b88efSmcbride 	};
405b73b88efSmcbride 	const struct keywords	*p;
406b73b88efSmcbride 
407b73b88efSmcbride 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
408b73b88efSmcbride 	    sizeof(keywords[0]), kw_cmp);
409b73b88efSmcbride 
4105dbd3954Shenning 	if (p)
411b73b88efSmcbride 		return (p->k_val);
4125dbd3954Shenning 	else
413b73b88efSmcbride 		return (STRING);
414b73b88efSmcbride }
415b73b88efSmcbride 
416b73b88efSmcbride #define MAXPUSHBACK	128
417b73b88efSmcbride 
418*08f6ba19Snaddy char	*parsebuf;
419b73b88efSmcbride int	 parseindex;
420*08f6ba19Snaddy char	 pushback_buffer[MAXPUSHBACK];
4214a99a2bcSrob int	 pushback_index = 0;
422b73b88efSmcbride 
423b73b88efSmcbride int
lgetc(int quotec)42420741916Sderaadt lgetc(int quotec)
425b73b88efSmcbride {
426b73b88efSmcbride 	int		c, next;
427b73b88efSmcbride 
428b73b88efSmcbride 	if (parsebuf) {
429b73b88efSmcbride 		/* Read character from the parsebuffer instead of input. */
430b73b88efSmcbride 		if (parseindex >= 0) {
431*08f6ba19Snaddy 			c = (unsigned char)parsebuf[parseindex++];
432b73b88efSmcbride 			if (c != '\0')
433b73b88efSmcbride 				return (c);
434b73b88efSmcbride 			parsebuf = NULL;
435b73b88efSmcbride 		} else
436b73b88efSmcbride 			parseindex++;
437b73b88efSmcbride 	}
438b73b88efSmcbride 
439b73b88efSmcbride 	if (pushback_index)
440*08f6ba19Snaddy 		return ((unsigned char)pushback_buffer[--pushback_index]);
441b73b88efSmcbride 
44220741916Sderaadt 	if (quotec) {
44320741916Sderaadt 		if ((c = getc(file->stream)) == EOF) {
444c6004ab9Smpf 			yyerror("reached end of file while parsing "
445c6004ab9Smpf 			    "quoted string");
446c6004ab9Smpf 			if (file == topfile || popfile() == EOF)
44720741916Sderaadt 				return (EOF);
44820741916Sderaadt 			return (quotec);
44920741916Sderaadt 		}
450d5d66eaeSderaadt 		return (c);
451d5d66eaeSderaadt 	}
452d5d66eaeSderaadt 
45320741916Sderaadt 	while ((c = getc(file->stream)) == '\\') {
45420741916Sderaadt 		next = getc(file->stream);
455b73b88efSmcbride 		if (next != '\n') {
456e3bfd77aSderaadt 			c = next;
457b73b88efSmcbride 			break;
458b73b88efSmcbride 		}
45920741916Sderaadt 		yylval.lineno = file->lineno;
46020741916Sderaadt 		file->lineno++;
461b73b88efSmcbride 	}
462b73b88efSmcbride 
46320741916Sderaadt 	while (c == EOF) {
464c6004ab9Smpf 		if (file == topfile || popfile() == EOF)
46520741916Sderaadt 			return (EOF);
46620741916Sderaadt 		c = getc(file->stream);
46720741916Sderaadt 	}
468b73b88efSmcbride 	return (c);
469b73b88efSmcbride }
470b73b88efSmcbride 
471b73b88efSmcbride int
lungetc(int c)472b73b88efSmcbride lungetc(int c)
473b73b88efSmcbride {
474b73b88efSmcbride 	if (c == EOF)
475b73b88efSmcbride 		return (EOF);
476b73b88efSmcbride 	if (parsebuf) {
477b73b88efSmcbride 		parseindex--;
478b73b88efSmcbride 		if (parseindex >= 0)
479b73b88efSmcbride 			return (c);
480b73b88efSmcbride 	}
481*08f6ba19Snaddy 	if (pushback_index + 1 >= MAXPUSHBACK)
482b73b88efSmcbride 		return (EOF);
483*08f6ba19Snaddy 	pushback_buffer[pushback_index++] = c;
484*08f6ba19Snaddy 	return (c);
485b73b88efSmcbride }
486b73b88efSmcbride 
487b73b88efSmcbride int
findeol(void)488b73b88efSmcbride findeol(void)
489b73b88efSmcbride {
490b73b88efSmcbride 	int	c;
491b73b88efSmcbride 
492b73b88efSmcbride 	parsebuf = NULL;
493b73b88efSmcbride 
494b73b88efSmcbride 	/* skip to either EOF or the first real EOL */
495b73b88efSmcbride 	while (1) {
4961a28f514Shenning 		if (pushback_index)
497*08f6ba19Snaddy 			c = (unsigned char)pushback_buffer[--pushback_index];
4981a28f514Shenning 		else
499d5d66eaeSderaadt 			c = lgetc(0);
500b73b88efSmcbride 		if (c == '\n') {
50120741916Sderaadt 			file->lineno++;
502b73b88efSmcbride 			break;
503b73b88efSmcbride 		}
504b73b88efSmcbride 		if (c == EOF)
505b73b88efSmcbride 			break;
506b73b88efSmcbride 	}
507b73b88efSmcbride 	return (ERROR);
508b73b88efSmcbride }
509b73b88efSmcbride 
510b73b88efSmcbride int
yylex(void)511b73b88efSmcbride yylex(void)
512b73b88efSmcbride {
513*08f6ba19Snaddy 	char	 buf[8096];
514*08f6ba19Snaddy 	char	*p, *val;
51520741916Sderaadt 	int	 quotec, next, c;
516b73b88efSmcbride 	int	 token;
517b73b88efSmcbride 
518b73b88efSmcbride top:
519b73b88efSmcbride 	p = buf;
5202053f12aSmpf 	while ((c = lgetc(0)) == ' ' || c == '\t')
521b73b88efSmcbride 		; /* nothing */
522b73b88efSmcbride 
52320741916Sderaadt 	yylval.lineno = file->lineno;
524b73b88efSmcbride 	if (c == '#')
525d5d66eaeSderaadt 		while ((c = lgetc(0)) != '\n' && c != EOF)
526b73b88efSmcbride 			; /* nothing */
527b73b88efSmcbride 	if (c == '$' && parsebuf == NULL) {
528b73b88efSmcbride 		while (1) {
529d5d66eaeSderaadt 			if ((c = lgetc(0)) == EOF)
530b73b88efSmcbride 				return (0);
531b73b88efSmcbride 
532b73b88efSmcbride 			if (p + 1 >= buf + sizeof(buf) - 1) {
533b73b88efSmcbride 				yyerror("string too long");
534b73b88efSmcbride 				return (findeol());
535b73b88efSmcbride 			}
536b73b88efSmcbride 			if (isalnum(c) || c == '_') {
537015d7b4dSbenno 				*p++ = c;
538b73b88efSmcbride 				continue;
539b73b88efSmcbride 			}
540b73b88efSmcbride 			*p = '\0';
541b73b88efSmcbride 			lungetc(c);
542b73b88efSmcbride 			break;
543b73b88efSmcbride 		}
544b73b88efSmcbride 		val = symget(buf);
545b73b88efSmcbride 		if (val == NULL) {
546b73b88efSmcbride 			yyerror("macro '%s' not defined", buf);
547b73b88efSmcbride 			return (findeol());
548b73b88efSmcbride 		}
549b73b88efSmcbride 		parsebuf = val;
550b73b88efSmcbride 		parseindex = 0;
551b73b88efSmcbride 		goto top;
552b73b88efSmcbride 	}
553b73b88efSmcbride 
554b73b88efSmcbride 	switch (c) {
555b73b88efSmcbride 	case '\'':
556b73b88efSmcbride 	case '"':
55720741916Sderaadt 		quotec = c;
558b73b88efSmcbride 		while (1) {
55920741916Sderaadt 			if ((c = lgetc(quotec)) == EOF)
560b73b88efSmcbride 				return (0);
561b73b88efSmcbride 			if (c == '\n') {
56220741916Sderaadt 				file->lineno++;
563b73b88efSmcbride 				continue;
564d5d66eaeSderaadt 			} else if (c == '\\') {
56520741916Sderaadt 				if ((next = lgetc(quotec)) == EOF)
566d5d66eaeSderaadt 					return (0);
567a1533359Ssashan 				if (next == quotec || next == ' ' ||
568a1533359Ssashan 				    next == '\t')
569d5d66eaeSderaadt 					c = next;
570daf24110Shenning 				else if (next == '\n') {
571daf24110Shenning 					file->lineno++;
572ea014f46Sderaadt 					continue;
573daf24110Shenning 				} else
574d5d66eaeSderaadt 					lungetc(next);
57520741916Sderaadt 			} else if (c == quotec) {
576d5d66eaeSderaadt 				*p = '\0';
577d5d66eaeSderaadt 				break;
57841eef22fSjsg 			} else if (c == '\0') {
57941eef22fSjsg 				yyerror("syntax error");
58041eef22fSjsg 				return (findeol());
581b73b88efSmcbride 			}
582b73b88efSmcbride 			if (p + 1 >= buf + sizeof(buf) - 1) {
583b73b88efSmcbride 				yyerror("string too long");
584b73b88efSmcbride 				return (findeol());
585b73b88efSmcbride 			}
586015d7b4dSbenno 			*p++ = c;
587b73b88efSmcbride 		}
588b73b88efSmcbride 		yylval.v.string = strdup(buf);
589b73b88efSmcbride 		if (yylval.v.string == NULL)
590a062aa9dSkrw 			err(1, "%s", __func__);
591b73b88efSmcbride 		return (STRING);
592b73b88efSmcbride 	}
593b73b88efSmcbride 
59439c88d90Sderaadt #define allowed_to_end_number(x) \
5950cf2c9c3Smpf 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
59639c88d90Sderaadt 
59739c88d90Sderaadt 	if (c == '-' || isdigit(c)) {
59839c88d90Sderaadt 		do {
59939c88d90Sderaadt 			*p++ = c;
600915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
60139c88d90Sderaadt 				yyerror("string too long");
60239c88d90Sderaadt 				return (findeol());
60339c88d90Sderaadt 			}
604d5d66eaeSderaadt 		} while ((c = lgetc(0)) != EOF && isdigit(c));
60539c88d90Sderaadt 		lungetc(c);
60639c88d90Sderaadt 		if (p == buf + 1 && buf[0] == '-')
60739c88d90Sderaadt 			goto nodigits;
60839c88d90Sderaadt 		if (c == EOF || allowed_to_end_number(c)) {
60939c88d90Sderaadt 			const char *errstr = NULL;
61039c88d90Sderaadt 
61139c88d90Sderaadt 			*p = '\0';
61239c88d90Sderaadt 			yylval.v.number = strtonum(buf, LLONG_MIN,
61339c88d90Sderaadt 			    LLONG_MAX, &errstr);
61439c88d90Sderaadt 			if (errstr) {
61539c88d90Sderaadt 				yyerror("\"%s\" invalid number: %s",
61639c88d90Sderaadt 				    buf, errstr);
61739c88d90Sderaadt 				return (findeol());
61839c88d90Sderaadt 			}
61939c88d90Sderaadt 			return (NUMBER);
62039c88d90Sderaadt 		} else {
62139c88d90Sderaadt nodigits:
62239c88d90Sderaadt 			while (p > buf + 1)
623*08f6ba19Snaddy 				lungetc((unsigned char)*--p);
624*08f6ba19Snaddy 			c = (unsigned char)*--p;
62539c88d90Sderaadt 			if (c == '-')
62639c88d90Sderaadt 				return (c);
62739c88d90Sderaadt 		}
62839c88d90Sderaadt 	}
62939c88d90Sderaadt 
630b73b88efSmcbride #define allowed_in_string(x) \
631b73b88efSmcbride 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
632b73b88efSmcbride 	x != '{' && x != '}' && \
633b73b88efSmcbride 	x != '!' && x != '=' && x != '#' && \
63442b18258Smpf 	x != ',' && x != '.'))
635b73b88efSmcbride 
63642b18258Smpf 	if (isalnum(c) || c == ':' || c == '_' || c == '&' || c == '|') {
637b73b88efSmcbride 		do {
638b73b88efSmcbride 			*p++ = c;
639915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
640b73b88efSmcbride 				yyerror("string too long");
641b73b88efSmcbride 				return (findeol());
642b73b88efSmcbride 			}
643d5d66eaeSderaadt 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
644b73b88efSmcbride 		lungetc(c);
645b73b88efSmcbride 		*p = '\0';
646edda3f1eShenning 		if ((token = lookup(buf)) == STRING)
647edda3f1eShenning 			if ((yylval.v.string = strdup(buf)) == NULL)
648a062aa9dSkrw 				err(1, "%s", __func__);
649b73b88efSmcbride 		return (token);
650b73b88efSmcbride 	}
651b73b88efSmcbride 	if (c == '\n') {
65220741916Sderaadt 		yylval.lineno = file->lineno;
65320741916Sderaadt 		file->lineno++;
654b73b88efSmcbride 	}
655b73b88efSmcbride 	if (c == EOF)
656b73b88efSmcbride 		return (0);
657b73b88efSmcbride 	return (c);
658b73b88efSmcbride }
659b73b88efSmcbride 
66020741916Sderaadt int
check_file_secrecy(int fd,const char * fname)66120741916Sderaadt check_file_secrecy(int fd, const char *fname)
66220741916Sderaadt {
66320741916Sderaadt 	struct stat	st;
66420741916Sderaadt 
66520741916Sderaadt 	if (fstat(fd, &st)) {
66620741916Sderaadt 		warn("cannot stat %s", fname);
66720741916Sderaadt 		return (-1);
66820741916Sderaadt 	}
66920741916Sderaadt 	if (st.st_uid != 0 && st.st_uid != getuid()) {
67020741916Sderaadt 		warnx("%s: owner not root or current user", fname);
67120741916Sderaadt 		return (-1);
67220741916Sderaadt 	}
6737140c133Shenning 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
6747140c133Shenning 		warnx("%s: group writable or world read/writable", fname);
67520741916Sderaadt 		return (-1);
67620741916Sderaadt 	}
67720741916Sderaadt 	return (0);
67820741916Sderaadt }
67920741916Sderaadt 
68020741916Sderaadt struct file *
pushfile(const char * name,int secret)68120741916Sderaadt pushfile(const char *name, int secret)
68220741916Sderaadt {
68320741916Sderaadt 	struct file	*nfile;
68420741916Sderaadt 
6857fc93de0Stobias 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
6866a3d55f9Skrw 		warn("%s", __func__);
68720741916Sderaadt 		return (NULL);
688fc0bc67fSpyr 	}
6897fc93de0Stobias 	if ((nfile->name = strdup(name)) == NULL) {
6906a3d55f9Skrw 		warn("%s", __func__);
6917fc93de0Stobias 		free(nfile);
6927fc93de0Stobias 		return (NULL);
6937fc93de0Stobias 	}
69420741916Sderaadt 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
6956a3d55f9Skrw 		warn("%s: %s", __func__, nfile->name);
69620741916Sderaadt 		free(nfile->name);
69720741916Sderaadt 		free(nfile);
69820741916Sderaadt 		return (NULL);
69920741916Sderaadt 	} else if (secret &&
70020741916Sderaadt 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
70120741916Sderaadt 		fclose(nfile->stream);
70220741916Sderaadt 		free(nfile->name);
70320741916Sderaadt 		free(nfile);
70420741916Sderaadt 		return (NULL);
70520741916Sderaadt 	}
70620741916Sderaadt 	nfile->lineno = 1;
70720741916Sderaadt 	TAILQ_INSERT_TAIL(&files, nfile, entry);
70820741916Sderaadt 	return (nfile);
70920741916Sderaadt }
71020741916Sderaadt 
71120741916Sderaadt int
popfile(void)71220741916Sderaadt popfile(void)
71320741916Sderaadt {
71420741916Sderaadt 	struct file	*prev;
71520741916Sderaadt 
716c6004ab9Smpf 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
71720741916Sderaadt 		prev->errors += file->errors;
718c6004ab9Smpf 
71920741916Sderaadt 	TAILQ_REMOVE(&files, file, entry);
72020741916Sderaadt 	fclose(file->stream);
72120741916Sderaadt 	free(file->name);
72220741916Sderaadt 	free(file);
72320741916Sderaadt 	file = prev;
724c6004ab9Smpf 	return (file ? 0 : EOF);
72520741916Sderaadt }
72620741916Sderaadt 
7278bb56c35Smcbride struct ifsd_config *
parse_config(char * filename,int opts)7288bb56c35Smcbride parse_config(char *filename, int opts)
729b73b88efSmcbride {
73020741916Sderaadt 	int		 errors = 0;
731b73b88efSmcbride 	struct sym	*sym, *next;
732b73b88efSmcbride 	struct ifsd_state *state;
733b73b88efSmcbride 
7348bb56c35Smcbride 	if ((conf = calloc(1, sizeof(struct ifsd_config))) == NULL) {
735a062aa9dSkrw 		err(1, "%s", __func__);
7368bb56c35Smcbride 		return (NULL);
7378bb56c35Smcbride 	}
7388bb56c35Smcbride 
73920741916Sderaadt 	if ((file = pushfile(filename, 0)) == NULL) {
7408bb56c35Smcbride 		free(conf);
7418bb56c35Smcbride 		return (NULL);
7428bb56c35Smcbride 	}
743c6004ab9Smpf 	topfile = file;
744b73b88efSmcbride 
745b73b88efSmcbride 	TAILQ_INIT(&conf->states);
746b73b88efSmcbride 
74720863243Sbenno 	init_state(&conf->initstate);
74820863243Sbenno 	curaction = conf->initstate.body;
7498bb56c35Smcbride 	conf->opts = opts;
750b73b88efSmcbride 
751b73b88efSmcbride 	yyparse();
752b73b88efSmcbride 
753b73b88efSmcbride 	/* Link states */
754b73b88efSmcbride 	TAILQ_FOREACH(state, &conf->states, entries) {
755b73b88efSmcbride 		link_states(state->init);
756138e089fSbenno 		link_states(state->body);
757b73b88efSmcbride 	}
758b73b88efSmcbride 
759172ae0e5Smpf 	errors = file->errors;
760172ae0e5Smpf 	popfile();
761172ae0e5Smpf 
762b73b88efSmcbride 	if (start_state != NULL) {
763b73b88efSmcbride 		TAILQ_FOREACH(state, &conf->states, entries) {
764b73b88efSmcbride 			if (strcmp(start_state, state->name) == 0) {
765b73b88efSmcbride 				conf->curstate = state;
766b73b88efSmcbride 				break;
767b73b88efSmcbride 			}
768b73b88efSmcbride 		}
769b73b88efSmcbride 		if (conf->curstate == NULL)
770b73b88efSmcbride 			errx(1, "invalid start state %s", start_state);
771b73b88efSmcbride 	} else {
772b73b88efSmcbride 		conf->curstate = TAILQ_FIRST(&conf->states);
773b73b88efSmcbride 	}
774b73b88efSmcbride 
775b73b88efSmcbride 	/* Free macros and check which have not been used. */
77646bca67bSkrw 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
777b73b88efSmcbride 		if ((conf->opts & IFSD_OPT_VERBOSE2) && !sym->used)
778b73b88efSmcbride 			fprintf(stderr, "warning: macro '%s' not "
779b73b88efSmcbride 			    "used\n", sym->nam);
780b73b88efSmcbride 		if (!sym->persist) {
781b73b88efSmcbride 			free(sym->nam);
782b73b88efSmcbride 			free(sym->val);
78320741916Sderaadt 			TAILQ_REMOVE(&symhead, sym, entry);
784b73b88efSmcbride 			free(sym);
785b73b88efSmcbride 		}
786b73b88efSmcbride 	}
787b73b88efSmcbride 
7888bb56c35Smcbride 	if (errors) {
7898bb56c35Smcbride 		clear_config(conf);
7909e05c8a2Smcbride 		errors = 0;
7918bb56c35Smcbride 		return (NULL);
7928bb56c35Smcbride 	}
793b73b88efSmcbride 
7948bb56c35Smcbride 	return (conf);
795b73b88efSmcbride }
796b73b88efSmcbride 
797b73b88efSmcbride void
link_states(struct ifsd_action * action)798b73b88efSmcbride link_states(struct ifsd_action *action)
799b73b88efSmcbride {
800b73b88efSmcbride 	struct ifsd_action *subaction;
801b73b88efSmcbride 
802b73b88efSmcbride 	switch (action->type) {
803b73b88efSmcbride 	default:
804b73b88efSmcbride 	case IFSD_ACTION_COMMAND:
805b73b88efSmcbride 		break;
806b73b88efSmcbride 	case IFSD_ACTION_CHANGESTATE: {
807b73b88efSmcbride 		struct ifsd_state *state;
808b73b88efSmcbride 
809b73b88efSmcbride 		TAILQ_FOREACH(state, &conf->states, entries) {
810b73b88efSmcbride 			if (strcmp(action->act.statename,
811b73b88efSmcbride 			    state->name) == 0) {
812b73b88efSmcbride 				action->act.nextstate = state;
813b73b88efSmcbride 				break;
814b73b88efSmcbride 			}
815b73b88efSmcbride 		}
816addc91abSmcbride 		if (state == NULL) {
817addc91abSmcbride 			fprintf(stderr, "error: state '%s' not declared\n",
818addc91abSmcbride 			    action->act.statename);
81920741916Sderaadt 			file->errors++;
820addc91abSmcbride 		}
821b73b88efSmcbride 		break;
822b73b88efSmcbride 	}
823b73b88efSmcbride 	case IFSD_ACTION_CONDITION:
824b73b88efSmcbride 		TAILQ_FOREACH(subaction, &action->act.c.actions, entries)
825b73b88efSmcbride 			link_states(subaction);
826b73b88efSmcbride 		break;
827b73b88efSmcbride 	}
828b73b88efSmcbride }
829b73b88efSmcbride 
830b73b88efSmcbride int
symset(const char * nam,const char * val,int persist)831b73b88efSmcbride symset(const char *nam, const char *val, int persist)
832b73b88efSmcbride {
833b73b88efSmcbride 	struct sym	*sym;
834b73b88efSmcbride 
83554c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
83654c95b7aSkrw 		if (strcmp(nam, sym->nam) == 0)
83754c95b7aSkrw 			break;
83854c95b7aSkrw 	}
839b73b88efSmcbride 
840b73b88efSmcbride 	if (sym != NULL) {
841b73b88efSmcbride 		if (sym->persist == 1)
842b73b88efSmcbride 			return (0);
843b73b88efSmcbride 		else {
844b73b88efSmcbride 			free(sym->nam);
845b73b88efSmcbride 			free(sym->val);
84620741916Sderaadt 			TAILQ_REMOVE(&symhead, sym, entry);
847b73b88efSmcbride 			free(sym);
848b73b88efSmcbride 		}
849b73b88efSmcbride 	}
850b73b88efSmcbride 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
851b73b88efSmcbride 		return (-1);
852b73b88efSmcbride 
853b73b88efSmcbride 	sym->nam = strdup(nam);
854b73b88efSmcbride 	if (sym->nam == NULL) {
855b73b88efSmcbride 		free(sym);
856b73b88efSmcbride 		return (-1);
857b73b88efSmcbride 	}
858b73b88efSmcbride 	sym->val = strdup(val);
859b73b88efSmcbride 	if (sym->val == NULL) {
860b73b88efSmcbride 		free(sym->nam);
861b73b88efSmcbride 		free(sym);
862b73b88efSmcbride 		return (-1);
863b73b88efSmcbride 	}
864b73b88efSmcbride 	sym->used = 0;
865b73b88efSmcbride 	sym->persist = persist;
86620741916Sderaadt 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
867b73b88efSmcbride 	return (0);
868b73b88efSmcbride }
869b73b88efSmcbride 
870b73b88efSmcbride int
cmdline_symset(char * s)871b73b88efSmcbride cmdline_symset(char *s)
872b73b88efSmcbride {
873b73b88efSmcbride 	char	*sym, *val;
874b73b88efSmcbride 	int	ret;
875b73b88efSmcbride 
876b73b88efSmcbride 	if ((val = strrchr(s, '=')) == NULL)
877b73b88efSmcbride 		return (-1);
878ed1b9eb8Smiko 	sym = strndup(s, val - s);
879ed1b9eb8Smiko 	if (sym == NULL)
880a062aa9dSkrw 		err(1, "%s", __func__);
881b73b88efSmcbride 	ret = symset(sym, val + 1, 1);
882b73b88efSmcbride 	free(sym);
883b73b88efSmcbride 
884b73b88efSmcbride 	return (ret);
885b73b88efSmcbride }
886b73b88efSmcbride 
887b73b88efSmcbride char *
symget(const char * nam)888b73b88efSmcbride symget(const char *nam)
889b73b88efSmcbride {
890b73b88efSmcbride 	struct sym	*sym;
891b73b88efSmcbride 
89254c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
893b73b88efSmcbride 		if (strcmp(nam, sym->nam) == 0) {
894b73b88efSmcbride 			sym->used = 1;
895b73b88efSmcbride 			return (sym->val);
896b73b88efSmcbride 		}
89754c95b7aSkrw 	}
898b73b88efSmcbride 	return (NULL);
899b73b88efSmcbride }
900b73b88efSmcbride 
901b73b88efSmcbride void
set_expression_depth(struct ifsd_expression * expression,int depth)902b73b88efSmcbride set_expression_depth(struct ifsd_expression *expression, int depth)
903b73b88efSmcbride {
904b73b88efSmcbride 	expression->depth = depth;
905b73b88efSmcbride 	if (conf->maxdepth < depth)
906b73b88efSmcbride 		conf->maxdepth = depth;
907b73b88efSmcbride 	if (expression->left != NULL)
908b73b88efSmcbride 		set_expression_depth(expression->left, depth + 1);
909b73b88efSmcbride 	if (expression->right != NULL)
910b73b88efSmcbride 		set_expression_depth(expression->right, depth + 1);
911b73b88efSmcbride }
912b73b88efSmcbride 
913b73b88efSmcbride void
init_state(struct ifsd_state * state)914b73b88efSmcbride init_state(struct ifsd_state *state)
915b73b88efSmcbride {
916b73b88efSmcbride 	TAILQ_INIT(&state->interface_states);
917b73b88efSmcbride 	TAILQ_INIT(&state->external_tests);
918b73b88efSmcbride 
919b73b88efSmcbride 	if ((state->init = calloc(1, sizeof(*state->init))) == NULL)
920a062aa9dSkrw 		err(1, "%s", __func__);
921b73b88efSmcbride 	state->init->type = IFSD_ACTION_CONDITION;
922b73b88efSmcbride 	TAILQ_INIT(&state->init->act.c.actions);
923b73b88efSmcbride 
924138e089fSbenno 	if ((state->body = calloc(1, sizeof(*state->body))) == NULL)
925a062aa9dSkrw 		err(1, "%s", __func__);
926138e089fSbenno 	state->body->type = IFSD_ACTION_CONDITION;
927138e089fSbenno 	TAILQ_INIT(&state->body->act.c.actions);
928b73b88efSmcbride }
929b73b88efSmcbride 
930b73b88efSmcbride struct ifsd_ifstate *
new_ifstate(char * ifname,int s)93118e4260cSrob new_ifstate(char *ifname, int s)
932b73b88efSmcbride {
933b73b88efSmcbride 	struct ifsd_ifstate *ifstate = NULL;
934b73b88efSmcbride 	struct ifsd_state *state;
935b73b88efSmcbride 
936b73b88efSmcbride 	if (curstate != NULL)
937b73b88efSmcbride 		state = curstate;
938b73b88efSmcbride 	else
93920863243Sbenno 		state = &conf->initstate;
940b73b88efSmcbride 
941b73b88efSmcbride 	TAILQ_FOREACH(ifstate, &state->interface_states, entries)
94218e4260cSrob 		if (strcmp(ifstate->ifname, ifname) == 0 &&
94318e4260cSrob 		    ifstate->ifstate == s)
944b73b88efSmcbride 			break;
945b73b88efSmcbride 	if (ifstate == NULL) {
946b73b88efSmcbride 		if ((ifstate = calloc(1, sizeof(*ifstate))) == NULL)
947a062aa9dSkrw 			err(1, "%s", __func__);
94818e4260cSrob 		if (strlcpy(ifstate->ifname, ifname,
94918e4260cSrob 		    sizeof(ifstate->ifname)) >= sizeof(ifstate->ifname))
95018e4260cSrob 			errx(1, "ifname strlcpy truncation");
95118e4260cSrob 		free(ifname);
952b73b88efSmcbride 		ifstate->ifstate = s;
953b73b88efSmcbride 		TAILQ_INIT(&ifstate->expressions);
954b73b88efSmcbride 		TAILQ_INSERT_TAIL(&state->interface_states, ifstate, entries);
955b73b88efSmcbride 	}
956b73b88efSmcbride 	ifstate->prevstate = -1;
957b73b88efSmcbride 	ifstate->refcount++;
958b73b88efSmcbride 	return (ifstate);
959b73b88efSmcbride }
960b73b88efSmcbride 
961b73b88efSmcbride struct ifsd_external *
new_external(char * command,u_int32_t frequency)962b73b88efSmcbride new_external(char *command, u_int32_t frequency)
963b73b88efSmcbride {
964b73b88efSmcbride 	struct ifsd_external *external = NULL;
965b73b88efSmcbride 	struct ifsd_state *state;
966b73b88efSmcbride 
967b73b88efSmcbride 	if (curstate != NULL)
968b73b88efSmcbride 		state = curstate;
969b73b88efSmcbride 	else
97020863243Sbenno 		state = &conf->initstate;
971b73b88efSmcbride 
972b73b88efSmcbride 	TAILQ_FOREACH(external, &state->external_tests, entries)
973b73b88efSmcbride 		if (strcmp(external->command, command) == 0 &&
974b73b88efSmcbride 		    external->frequency == frequency)
975b73b88efSmcbride 			break;
976b73b88efSmcbride 	if (external == NULL) {
977b73b88efSmcbride 		if ((external = calloc(1, sizeof(*external))) == NULL)
978a062aa9dSkrw 			err(1, "%s", __func__);
979b73b88efSmcbride 		if ((external->command = strdup(command)) == NULL)
980a062aa9dSkrw 			err(1, "%s", __func__);
981b73b88efSmcbride 		external->frequency = frequency;
982b73b88efSmcbride 		TAILQ_INIT(&external->expressions);
983b73b88efSmcbride 		TAILQ_INSERT_TAIL(&state->external_tests, external, entries);
984b73b88efSmcbride 	}
985b73b88efSmcbride 	external->prevstatus = -1;
986b73b88efSmcbride 	external->refcount++;
987b73b88efSmcbride 	return (external);
988b73b88efSmcbride }
989