Bug Summary

File:src/usr.sbin/ifstated/ifstated.c
Warning:line 133, column 2
Value stored to 'argv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ifstated.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/ifstated/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/ifstated -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/ifstated/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/ifstated/ifstated.c
1/* $OpenBSD: ifstated.c,v 1.66 2021/07/12 15:09:21 beck Exp $ */
2
3/*
4 * Copyright (c) 2004 Marco Pfatschbacher <mpf@openbsd.org>
5 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20/*
21 * ifstated listens to link_state transitions on interfaces
22 * and executes predefined commands.
23 */
24
25#include <sys/types.h>
26#include <sys/time.h>
27#include <sys/socket.h>
28#include <sys/wait.h>
29
30#include <net/if.h>
31#include <net/route.h>
32#include <netinet/in.h>
33
34#include <paths.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <signal.h>
39#include <stdint.h>
40#include <syslog.h>
41#include <errno(*__errno()).h>
42#include <event.h>
43#include <unistd.h>
44#include <ifaddrs.h>
45
46#include "ifstated.h"
47#include "log.h"
48
49struct ifsd_config *conf, *newconf;
50
51int opts;
52int opt_inhibit;
53char *configfile = "/etc/ifstated.conf";
54struct event rt_msg_ev, sighup_ev, startup_ev, sigchld_ev;
55
56void startup_handler(int, short, void *);
57void sighup_handler(int, short, void *);
58int load_config(void);
59void sigchld_handler(int, short, void *);
60void rt_msg_handler(int, short, void *);
61void external_handler(int, short, void *);
62void external_exec(struct ifsd_external *, int);
63void check_external_status(struct ifsd_state *);
64void check_ifdeparture(void);
65void external_evtimer_setup(struct ifsd_state *, int);
66void scan_ifstate(const char *, int, int);
67int scan_ifstate_single(const char *, int, struct ifsd_state *);
68void fetch_ifstate(int);
69__dead__attribute__((__noreturn__)) void usage(void);
70void adjust_expressions(struct ifsd_expression_list *, int);
71void adjust_external_expressions(struct ifsd_state *);
72void eval_state(struct ifsd_state *);
73int state_change(void);
74void do_action(struct ifsd_action *);
75void remove_action(struct ifsd_action *, struct ifsd_state *);
76void remove_expression(struct ifsd_expression *,
77 struct ifsd_state *);
78
79__dead__attribute__((__noreturn__)) void
80usage(void)
81{
82 extern char *__progname;
83
84 fprintf(stderr(&__sF[2]), "usage: %s [-dhinv] [-D macro=value] [-f file]\n",
85 __progname);
86 exit(1);
87}
88
89int
90main(int argc, char *argv[])
91{
92 struct timeval tv;
93 int ch, rt_fd;
94 int debug = 0;
95 unsigned int rtfilter;
96
97 log_init(1, LOG_DAEMON(3<<3)); /* log to stderr until daemonized */
98 log_setverbose(1);
99
100 while ((ch = getopt(argc, argv, "dD:f:hniv")) != -1) {
101 switch (ch) {
102 case 'd':
103 debug = 1;
104 break;
105 case 'D':
106 if (cmdline_symset(optarg) < 0)
107 fatalx("could not parse macro definition %s",
108 optarg);
109 break;
110 case 'f':
111 configfile = optarg;
112 break;
113 case 'h':
114 usage();
115 break;
116 case 'n':
117 opts |= IFSD_OPT_NOACTION0x00000004;
118 break;
119 case 'i':
120 opt_inhibit = 1;
121 break;
122 case 'v':
123 if (opts & IFSD_OPT_VERBOSE0x00000001)
124 opts |= IFSD_OPT_VERBOSE20x00000002;
125 opts |= IFSD_OPT_VERBOSE0x00000001;
126 break;
127 default:
128 usage();
129 }
130 }
131
132 argc -= optind;
133 argv += optind;
Value stored to 'argv' is never read
134 if (argc > 0)
135 usage();
136
137 if (opts & IFSD_OPT_NOACTION0x00000004) {
138 if ((newconf = parse_config(configfile, opts)) == NULL((void *)0))
139 exit(1);
140 fprintf(stderr(&__sF[2]), "configuration OK\n");
141 exit(0);
142 }
143
144 if (!debug)
145 daemon(1, 0);
146
147 event_init();
148 log_init(debug, LOG_DAEMON(3<<3));
149 log_setverbose(opts & IFSD_OPT_VERBOSE0x00000001);
150
151 if ((rt_fd = socket(AF_ROUTE17, SOCK_RAW3, 0)) == -1)
152 fatal("no routing socket");
153
154 rtfilter = ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) | ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf));
155 if (setsockopt(rt_fd, AF_ROUTE17, ROUTE_MSGFILTER1,
156 &rtfilter, sizeof(rtfilter)) == -1) /* not fatal */
157 log_warn("%s: setsockopt msgfilter", __func__);
158
159 rtfilter = RTABLE_ANY0xffffffff;
160 if (setsockopt(rt_fd, AF_ROUTE17, ROUTE_TABLEFILTER2,
161 &rtfilter, sizeof(rtfilter)) == -1) /* not fatal */
162 log_warn("%s: setsockopt tablefilter", __func__);
163
164 if (unveil(configfile, "r") == -1)
165 fatal("unveil %s", configfile);
166 if (unveil(_PATH_BSHELL"/bin/sh", "x") == -1)
167 fatal("unveil %s", _PATH_BSHELL"/bin/sh");
168 if (pledge("stdio rpath route proc exec", NULL((void *)0)) == -1)
169 fatal("pledge");
170
171 signal_set(&sigchld_ev, SIGCHLD, sigchld_handler, NULL)event_set(&sigchld_ev, 20, 0x08|0x10, sigchld_handler, ((
void *)0))
;
172 signal_add(&sigchld_ev, NULL)event_add(&sigchld_ev, ((void *)0));
173
174 /* Loading the config needs to happen in the event loop */
175 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
176 evtimer_set(&startup_ev, startup_handler, (void *)(long)rt_fd)event_set(&startup_ev, -1, 0, startup_handler, (void *)(long
)rt_fd)
;
177 evtimer_add(&startup_ev, &tv)event_add(&startup_ev, &tv);
178
179 event_loop(0);
180 exit(0);
181}
182
183void
184startup_handler(int fd, short event, void *arg)
185{
186 int rfd = (int)(long)arg;
187
188 if (load_config() != 0) {
189 log_warnx("unable to load config");
190 exit(1);
191 }
192
193 event_set(&rt_msg_ev, rfd, EV_READ0x02|EV_PERSIST0x10, rt_msg_handler, NULL((void *)0));
194 event_add(&rt_msg_ev, NULL((void *)0));
195
196 signal_set(&sighup_ev, SIGHUP, sighup_handler, NULL)event_set(&sighup_ev, 1, 0x08|0x10, sighup_handler, ((void
*)0))
;
197 signal_add(&sighup_ev, NULL)event_add(&sighup_ev, ((void *)0));
198
199 log_info("started");
200}
201
202void
203sighup_handler(int fd, short event, void *arg)
204{
205 log_info("reloading config");
206 if (load_config() != 0)
207 log_warnx("unable to reload config");
208}
209
210int
211load_config(void)
212{
213 if ((newconf = parse_config(configfile, opts)) == NULL((void *)0))
214 return (-1);
215 if (conf != NULL((void *)0))
216 clear_config(conf);
217 conf = newconf;
218 conf->initstate.entered = time(NULL((void *)0));
219 fetch_ifstate(0);
220 external_evtimer_setup(&conf->initstate, IFSD_EVTIMER_ADD);
221 adjust_external_expressions(&conf->initstate);
222 eval_state(&conf->initstate);
223 if (conf->curstate != NULL((void *)0)) {
224 log_info("initial state: %s", conf->curstate->name);
225 conf->curstate->entered = time(NULL((void *)0));
226 conf->nextstate = conf->curstate;
227 conf->curstate = NULL((void *)0);
228 while (state_change()) {
229 do_action(conf->curstate->init);
230 do_action(conf->curstate->body);
231 }
232 }
233 return (0);
234}
235
236void
237rt_msg_handler(int fd, short event, void *arg)
238{
239 char msg[2048];
240 struct rt_msghdr *rtm = (struct rt_msghdr *)&msg;
241 struct if_msghdr ifm;
242 struct if_announcemsghdr ifan;
243 char ifnamebuf[IFNAMSIZ16];
244 char *ifname;
245 ssize_t len;
246
247 if ((len = read(fd, msg, sizeof(msg))) == -1) {
248 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
249 return;
250 fatal("%s: routing socket read error", __func__);
251 }
252
253 if (len == 0)
254 fatal("%s: routing socket closed", __func__);
255
256 if (rtm->rtm_version != RTM_VERSION5)
257 return;
258
259 switch (rtm->rtm_type) {
260 case RTM_IFINFO0xe:
261 memcpy(&ifm, rtm, sizeof(ifm));
262 ifname = if_indextoname(ifm.ifm_index, ifnamebuf);
263 /* ifname is NULL on interface departure */
264 if (ifname != NULL((void *)0))
265 scan_ifstate(ifname, ifm.ifm_data.ifi_link_state, 1);
266 break;
267 case RTM_IFANNOUNCE0xf:
268 memcpy(&ifan, rtm, sizeof(ifan));
269 switch (ifan.ifan_what) {
270 case IFAN_DEPARTURE1:
271 log_warnx("interface %s departed", ifan.ifan_name);
272 check_ifdeparture();
273 break;
274 case IFAN_ARRIVAL0:
275 log_warnx("interface %s arrived", ifan.ifan_name);
276 fetch_ifstate(1);
277 break;
278 }
279 break;
280 case RTM_DESYNC0x10:
281 /* we lost some routing messages so rescan interfaces */
282 check_ifdeparture();
283 fetch_ifstate(1);
284 break;
285 }
286 return;
287}
288
289void
290sigchld_handler(int fd, short event, void *arg)
291{
292 check_external_status(&conf->initstate);
293 if (conf->curstate != NULL((void *)0))
294 check_external_status(conf->curstate);
295}
296
297void
298external_handler(int fd, short event, void *arg)
299{
300 struct ifsd_external *external = (struct ifsd_external *)arg;
301 struct timeval tv;
302
303 /* re-schedule */
304 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
305 tv.tv_sec = external->frequency;
306 evtimer_set(&external->ev, external_handler, external)event_set(&external->ev, -1, 0, external_handler, external
)
;
307 evtimer_add(&external->ev, &tv)event_add(&external->ev, &tv);
308
309 /* execute */
310 external_exec(external, 1);
311}
312
313void
314external_exec(struct ifsd_external *external, int async)
315{
316 char *argp[] = {"sh", "-c", NULL((void *)0), NULL((void *)0)};
317 pid_t pid;
318 int s;
319
320 if (external->pid > 0) {
321 log_debug("previous command %s [%d] still running, killing it",
322 external->command, external->pid);
323 kill(external->pid, SIGKILL9);
324 waitpid(external->pid, &s, 0);
325 external->pid = 0;
326 }
327
328 argp[2] = external->command;
329 log_debug("running %s", external->command);
330 pid = fork();
331 if (pid == -1) {
332 log_warn("fork error");
333 } else if (pid == 0) {
334 execv(_PATH_BSHELL"/bin/sh", argp);
335 _exit(1);
336 /* NOTREACHED */
337 } else {
338 external->pid = pid;
339 }
340 if (!async) {
341 waitpid(external->pid, &s, 0);
342 external->pid = 0;
343 if (WIFEXITED(s)(((s) & 0177) == 0))
344 external->prevstatus = WEXITSTATUS(s)(int)(((unsigned)(s) >> 8) & 0xff);
345 }
346}
347
348void
349adjust_external_expressions(struct ifsd_state *state)
350{
351 struct ifsd_external *external;
352 struct ifsd_expression_list expressions;
353
354 TAILQ_INIT(&expressions)do { (&expressions)->tqh_first = ((void *)0); (&expressions
)->tqh_last = &(&expressions)->tqh_first; } while
(0)
;
355 TAILQ_FOREACH(external, &state->external_tests, entries)for((external) = ((&state->external_tests)->tqh_first
); (external) != ((void *)0); (external) = ((external)->entries
.tqe_next))
{
356 struct ifsd_expression *expression;
357
358 if (external->prevstatus == -1)
359 continue;
360
361 TAILQ_FOREACH(expression, &external->expressions, entries)for((expression) = ((&external->expressions)->tqh_first
); (expression) != ((void *)0); (expression) = ((expression)->
entries.tqe_next))
{
362 TAILQ_INSERT_TAIL(&expressions,do { (expression)->eval.tqe_next = ((void *)0); (expression
)->eval.tqe_prev = (&expressions)->tqh_last; *(&
expressions)->tqh_last = (expression); (&expressions)->
tqh_last = &(expression)->eval.tqe_next; } while (0)
363 expression, eval)do { (expression)->eval.tqe_next = ((void *)0); (expression
)->eval.tqe_prev = (&expressions)->tqh_last; *(&
expressions)->tqh_last = (expression); (&expressions)->
tqh_last = &(expression)->eval.tqe_next; } while (0)
;
364 expression->truth = !external->prevstatus;
365 }
366 adjust_expressions(&expressions, conf->maxdepth);
367 }
368}
369
370void
371check_external_status(struct ifsd_state *state)
372{
373 struct ifsd_external *external, *end = NULL((void *)0);
374 int status, s, changed = 0;
375
376 /* Do this manually; change ordering so the oldest is first */
377 external = TAILQ_FIRST(&state->external_tests)((&state->external_tests)->tqh_first);
378 while (external != NULL((void *)0) && external != end) {
379 struct ifsd_external *newexternal;
380
381 newexternal = TAILQ_NEXT(external, entries)((external)->entries.tqe_next);
382
383 if (external->pid <= 0)
384 goto loop;
385
386 if (wait4(external->pid, &s, WNOHANG1, NULL((void *)0)) == 0)
387 goto loop;
388
389 external->pid = 0;
390 if (end == NULL((void *)0))
391 end = external;
392 if (WIFEXITED(s)(((s) & 0177) == 0))
393 status = WEXITSTATUS(s)(int)(((unsigned)(s) >> 8) & 0xff);
394 else {
395 log_warnx("%s exited abnormally", external->command);
396 goto loop;
397 }
398
399 if (external->prevstatus != status &&
400 (external->prevstatus != -1 || !opt_inhibit)) {
401 changed = 1;
402 external->prevstatus = status;
403 }
404 external->lastexec = time(NULL((void *)0));
405 TAILQ_REMOVE(&state->external_tests, external, entries)do { if (((external)->entries.tqe_next) != ((void *)0)) (external
)->entries.tqe_next->entries.tqe_prev = (external)->
entries.tqe_prev; else (&state->external_tests)->tqh_last
= (external)->entries.tqe_prev; *(external)->entries.tqe_prev
= (external)->entries.tqe_next; ; ; } while (0)
;
406 TAILQ_INSERT_TAIL(&state->external_tests, external, entries)do { (external)->entries.tqe_next = ((void *)0); (external
)->entries.tqe_prev = (&state->external_tests)->
tqh_last; *(&state->external_tests)->tqh_last = (external
); (&state->external_tests)->tqh_last = &(external
)->entries.tqe_next; } while (0)
;
407loop:
408 external = newexternal;
409 }
410
411 if (changed) {
412 adjust_external_expressions(state);
413 eval_state(state);
414 }
415}
416
417void
418external_evtimer_setup(struct ifsd_state *state, int action)
419{
420 struct ifsd_external *external;
421 int s;
422
423 if (state != NULL((void *)0)) {
424 switch (action) {
425 case IFSD_EVTIMER_ADD:
426 TAILQ_FOREACH(external,for((external) = ((&state->external_tests)->tqh_first
); (external) != ((void *)0); (external) = ((external)->entries
.tqe_next))
427 &state->external_tests, entries)for((external) = ((&state->external_tests)->tqh_first
); (external) != ((void *)0); (external) = ((external)->entries
.tqe_next))
{
428 struct timeval tv;
429
430 /* run it once right away */
431 external_exec(external, 0);
432
433 /* schedule it for later */
434 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
435 tv.tv_sec = external->frequency;
436 evtimer_set(&external->ev, external_handler,event_set(&external->ev, -1, 0, external_handler, external
)
437 external)event_set(&external->ev, -1, 0, external_handler, external
)
;
438 evtimer_add(&external->ev, &tv)event_add(&external->ev, &tv);
439 }
440 break;
441 case IFSD_EVTIMER_DEL:
442 TAILQ_FOREACH(external,for((external) = ((&state->external_tests)->tqh_first
); (external) != ((void *)0); (external) = ((external)->entries
.tqe_next))
443 &state->external_tests, entries)for((external) = ((&state->external_tests)->tqh_first
); (external) != ((void *)0); (external) = ((external)->entries
.tqe_next))
{
444 if (external->pid > 0) {
445 kill(external->pid, SIGKILL9);
446 waitpid(external->pid, &s, 0);
447 external->pid = 0;
448 }
449 evtimer_del(&external->ev)event_del(&external->ev);
450 }
451 break;
452 }
453 }
454}
455
456#define LINK_STATE_IS_DOWN(_s)(!(((_s)) >= 4 || ((_s)) == 0)) (!LINK_STATE_IS_UP((_s))(((_s)) >= 4 || ((_s)) == 0))
457
458int
459scan_ifstate_single(const char *ifname, int s, struct ifsd_state *state)
460{
461 struct ifsd_ifstate *ifstate;
462 struct ifsd_expression_list expressions;
463 int changed = 0;
464
465 TAILQ_INIT(&expressions)do { (&expressions)->tqh_first = ((void *)0); (&expressions
)->tqh_last = &(&expressions)->tqh_first; } while
(0)
;
466
467 TAILQ_FOREACH(ifstate, &state->interface_states, entries)for((ifstate) = ((&state->interface_states)->tqh_first
); (ifstate) != ((void *)0); (ifstate) = ((ifstate)->entries
.tqe_next))
{
468 if (strcmp(ifstate->ifname, ifname) == 0) {
469 if (ifstate->prevstate != s &&
470 (ifstate->prevstate != -1 || !opt_inhibit)) {
471 struct ifsd_expression *expression;
472 int truth;
473
474 truth =
475 (ifstate->ifstate == IFSD_LINKUNKNOWN0 &&
476 s == LINK_STATE_UNKNOWN0) ||
477 (ifstate->ifstate == IFSD_LINKDOWN1 &&
478 LINK_STATE_IS_DOWN(s)(!(((s)) >= 4 || ((s)) == 0))) ||
479 (ifstate->ifstate == IFSD_LINKUP2 &&
480 LINK_STATE_IS_UP(s)((s) >= 4 || (s) == 0));
481
482 TAILQ_FOREACH(expression,for((expression) = ((&ifstate->expressions)->tqh_first
); (expression) != ((void *)0); (expression) = ((expression)->
entries.tqe_next))
483 &ifstate->expressions, entries)for((expression) = ((&ifstate->expressions)->tqh_first
); (expression) != ((void *)0); (expression) = ((expression)->
entries.tqe_next))
{
484 expression->truth = truth;
485 TAILQ_INSERT_TAIL(&expressions,do { (expression)->eval.tqe_next = ((void *)0); (expression
)->eval.tqe_prev = (&expressions)->tqh_last; *(&
expressions)->tqh_last = (expression); (&expressions)->
tqh_last = &(expression)->eval.tqe_next; } while (0)
486 expression, eval)do { (expression)->eval.tqe_next = ((void *)0); (expression
)->eval.tqe_prev = (&expressions)->tqh_last; *(&
expressions)->tqh_last = (expression); (&expressions)->
tqh_last = &(expression)->eval.tqe_next; } while (0)
;
487 changed = 1;
488 }
489 ifstate->prevstate = s;
490 }
491 }
492 }
493
494 if (changed)
495 adjust_expressions(&expressions, conf->maxdepth);
496 return (changed);
497}
498
499void
500scan_ifstate(const char *ifname, int s, int do_eval)
501{
502 struct ifsd_state *state;
503 int cur_eval = 0;
504
505 if (scan_ifstate_single(ifname, s, &conf->initstate) && do_eval)
506 eval_state(&conf->initstate);
507 TAILQ_FOREACH(state, &conf->states, entries)for((state) = ((&conf->states)->tqh_first); (state)
!= ((void *)0); (state) = ((state)->entries.tqe_next))
{
508 if (scan_ifstate_single(ifname, s, state) &&
509 (do_eval && state == conf->curstate))
510 cur_eval = 1;
511 }
512 /* execute actions _after_ all expressions have been adjusted */
513 if (cur_eval)
514 eval_state(conf->curstate);
515}
516
517/*
518 * Do a bottom-up ajustment of the expression tree's truth value,
519 * level-by-level to ensure that each expression's subexpressions have been
520 * evaluated.
521 */
522void
523adjust_expressions(struct ifsd_expression_list *expressions, int depth)
524{
525 struct ifsd_expression_list nexpressions;
526 struct ifsd_expression *expression;
527
528 TAILQ_INIT(&nexpressions)do { (&nexpressions)->tqh_first = ((void *)0); (&nexpressions
)->tqh_last = &(&nexpressions)->tqh_first; } while
(0)
;
529 while ((expression = TAILQ_FIRST(expressions)((expressions)->tqh_first)) != NULL((void *)0)) {
530 TAILQ_REMOVE(expressions, expression, eval)do { if (((expression)->eval.tqe_next) != ((void *)0)) (expression
)->eval.tqe_next->eval.tqe_prev = (expression)->eval
.tqe_prev; else (expressions)->tqh_last = (expression)->
eval.tqe_prev; *(expression)->eval.tqe_prev = (expression)
->eval.tqe_next; ; ; } while (0)
;
531 if (expression->depth == depth) {
532 struct ifsd_expression *te;
533
534 switch (expression->type) {
535 case IFSD_OPER_AND1:
536 expression->truth = expression->left->truth &&
537 expression->right->truth;
538 break;
539 case IFSD_OPER_OR2:
540 expression->truth = expression->left->truth ||
541 expression->right->truth;
542 break;
543 case IFSD_OPER_NOT3:
544 expression->truth = !expression->right->truth;
545 break;
546 default:
547 break;
548 }
549 if (expression->parent != NULL((void *)0)) {
550 if (TAILQ_EMPTY(&nexpressions)(((&nexpressions)->tqh_first) == ((void *)0)))
551 te = NULL((void *)0);
552 TAILQ_FOREACH(te, &nexpressions, eval)for((te) = ((&nexpressions)->tqh_first); (te) != ((void
*)0); (te) = ((te)->eval.tqe_next))
553 if (expression->parent == te)
554 break;
555 if (te == NULL((void *)0))
556 TAILQ_INSERT_TAIL(&nexpressions,do { (expression->parent)->eval.tqe_next = ((void *)0);
(expression->parent)->eval.tqe_prev = (&nexpressions
)->tqh_last; *(&nexpressions)->tqh_last = (expression
->parent); (&nexpressions)->tqh_last = &(expression
->parent)->eval.tqe_next; } while (0)
557 expression->parent, eval)do { (expression->parent)->eval.tqe_next = ((void *)0);
(expression->parent)->eval.tqe_prev = (&nexpressions
)->tqh_last; *(&nexpressions)->tqh_last = (expression
->parent); (&nexpressions)->tqh_last = &(expression
->parent)->eval.tqe_next; } while (0)
;
558 }
559 } else
560 TAILQ_INSERT_TAIL(&nexpressions, expression, eval)do { (expression)->eval.tqe_next = ((void *)0); (expression
)->eval.tqe_prev = (&nexpressions)->tqh_last; *(&
nexpressions)->tqh_last = (expression); (&nexpressions
)->tqh_last = &(expression)->eval.tqe_next; } while
(0)
;
561 }
562 if (depth > 0)
563 adjust_expressions(&nexpressions, depth - 1);
564}
565
566void
567eval_state(struct ifsd_state *state)
568{
569 struct ifsd_external *external;
570
571 external = TAILQ_FIRST(&state->external_tests)((&state->external_tests)->tqh_first);
572 if (external == NULL((void *)0) || external->lastexec >= state->entered ||
573 external->lastexec == 0) {
574 do_action(state->body);
575 while (state_change()) {
576 do_action(conf->curstate->init);
577 do_action(conf->curstate->body);
578 }
579 }
580}
581
582int
583state_change(void)
584{
585 if (conf->nextstate != NULL((void *)0) && conf->curstate != conf->nextstate) {
586 log_info("changing state to %s", conf->nextstate->name);
587 if (conf->curstate != NULL((void *)0)) {
588 evtimer_del(&conf->curstate->ev)event_del(&conf->curstate->ev);
589 external_evtimer_setup(conf->curstate,
590 IFSD_EVTIMER_DEL);
591 }
592 conf->curstate = conf->nextstate;
593 conf->nextstate = NULL((void *)0);
594 conf->curstate->entered = time(NULL((void *)0));
595 external_evtimer_setup(conf->curstate, IFSD_EVTIMER_ADD);
596 adjust_external_expressions(conf->curstate);
597 return (1);
598 }
599 return (0);
600}
601
602/*
603 * Run recursively through the tree of actions.
604 */
605void
606do_action(struct ifsd_action *action)
607{
608 struct ifsd_action *subaction;
609
610 switch (action->type) {
611 case IFSD_ACTION_COMMAND1:
612 log_debug("running %s", action->act.command);
613 system(action->act.command);
614 break;
615 case IFSD_ACTION_CHANGESTATE2:
616 conf->nextstate = action->act.nextstate;
617 break;
618 case IFSD_ACTION_CONDITION3:
619 if ((action->act.c.expression != NULL((void *)0) &&
620 action->act.c.expression->truth) ||
621 action->act.c.expression == NULL((void *)0)) {
622 TAILQ_FOREACH(subaction, &action->act.c.actions,for((subaction) = ((&action->act.c.actions)->tqh_first
); (subaction) != ((void *)0); (subaction) = ((subaction)->
entries.tqe_next))
623 entries)for((subaction) = ((&action->act.c.actions)->tqh_first
); (subaction) != ((void *)0); (subaction) = ((subaction)->
entries.tqe_next))
624 do_action(subaction);
625 }
626 break;
627 default:
628 log_debug("%s: unknown action %d", __func__, action->type);
629 break;
630 }
631}
632
633/*
634 * Fetch the current link states.
635 */
636void
637fetch_ifstate(int do_eval)
638{
639 struct ifaddrs *ifap, *ifa;
640
641 if (getifaddrs(&ifap) != 0)
642 fatal("getifaddrs");
643
644 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
645 if (ifa->ifa_addr != NULL((void *)0) &&
646 ifa->ifa_addr->sa_family == AF_LINK18) {
647 struct if_data *ifdata = ifa->ifa_data;
648 scan_ifstate(ifa->ifa_name, ifdata->ifi_link_state,
649 do_eval);
650 }
651 }
652
653 freeifaddrs(ifap);
654}
655
656void
657check_ifdeparture(void)
658{
659 struct ifsd_state *state;
660 struct ifsd_ifstate *ifstate;
661
662 TAILQ_FOREACH(state, &conf->states, entries)for((state) = ((&conf->states)->tqh_first); (state)
!= ((void *)0); (state) = ((state)->entries.tqe_next))
{
663 TAILQ_FOREACH(ifstate, &state->interface_states, entries)for((ifstate) = ((&state->interface_states)->tqh_first
); (ifstate) != ((void *)0); (ifstate) = ((ifstate)->entries
.tqe_next))
{
664 if (if_nametoindex(ifstate->ifname) == 0)
665 scan_ifstate(ifstate->ifname,
666 LINK_STATE_DOWN2, 1);
667 }
668 }
669}
670
671void
672clear_config(struct ifsd_config *oconf)
673{
674 struct ifsd_state *state;
675
676 external_evtimer_setup(&conf->initstate, IFSD_EVTIMER_DEL);
677 if (conf != NULL((void *)0) && conf->curstate != NULL((void *)0))
678 external_evtimer_setup(conf->curstate, IFSD_EVTIMER_DEL);
679 while ((state = TAILQ_FIRST(&oconf->states)((&oconf->states)->tqh_first)) != NULL((void *)0)) {
680 TAILQ_REMOVE(&oconf->states, state, entries)do { if (((state)->entries.tqe_next) != ((void *)0)) (state
)->entries.tqe_next->entries.tqe_prev = (state)->entries
.tqe_prev; else (&oconf->states)->tqh_last = (state
)->entries.tqe_prev; *(state)->entries.tqe_prev = (state
)->entries.tqe_next; ; ; } while (0)
;
681 remove_action(state->init, state);
682 remove_action(state->body, state);
683 free(state->name);
684 free(state);
685 }
686 remove_action(oconf->initstate.init, &oconf->initstate);
687 remove_action(oconf->initstate.body, &oconf->initstate);
688 free(oconf);
689}
690
691void
692remove_action(struct ifsd_action *action, struct ifsd_state *state)
693{
694 struct ifsd_action *subaction;
695
696 if (action == NULL((void *)0) || state == NULL((void *)0))
697 return;
698
699 switch (action->type) {
700 case IFSD_ACTION_COMMAND1:
701 free(action->act.command);
702 break;
703 case IFSD_ACTION_CHANGESTATE2:
704 break;
705 case IFSD_ACTION_CONDITION3:
706 if (action->act.c.expression != NULL((void *)0))
707 remove_expression(action->act.c.expression, state);
708 while ((subaction =
709 TAILQ_FIRST(&action->act.c.actions)((&action->act.c.actions)->tqh_first)) != NULL((void *)0)) {
710 TAILQ_REMOVE(&action->act.c.actions,do { if (((subaction)->entries.tqe_next) != ((void *)0)) (
subaction)->entries.tqe_next->entries.tqe_prev = (subaction
)->entries.tqe_prev; else (&action->act.c.actions)->
tqh_last = (subaction)->entries.tqe_prev; *(subaction)->
entries.tqe_prev = (subaction)->entries.tqe_next; ; ; } while
(0)
711 subaction, entries)do { if (((subaction)->entries.tqe_next) != ((void *)0)) (
subaction)->entries.tqe_next->entries.tqe_prev = (subaction
)->entries.tqe_prev; else (&action->act.c.actions)->
tqh_last = (subaction)->entries.tqe_prev; *(subaction)->
entries.tqe_prev = (subaction)->entries.tqe_next; ; ; } while
(0)
;
712 remove_action(subaction, state);
713 }
714 }
715 free(action);
716}
717
718void
719remove_expression(struct ifsd_expression *expression,
720 struct ifsd_state *state)
721{
722 switch (expression->type) {
723 case IFSD_OPER_IFSTATE5:
724 TAILQ_REMOVE(&expression->u.ifstate->expressions, expression,do { if (((expression)->entries.tqe_next) != ((void *)0)) (
expression)->entries.tqe_next->entries.tqe_prev = (expression
)->entries.tqe_prev; else (&expression->u.ifstate->
expressions)->tqh_last = (expression)->entries.tqe_prev
; *(expression)->entries.tqe_prev = (expression)->entries
.tqe_next; ; ; } while (0)
725 entries)do { if (((expression)->entries.tqe_next) != ((void *)0)) (
expression)->entries.tqe_next->entries.tqe_prev = (expression
)->entries.tqe_prev; else (&expression->u.ifstate->
expressions)->tqh_last = (expression)->entries.tqe_prev
; *(expression)->entries.tqe_prev = (expression)->entries
.tqe_next; ; ; } while (0)
;
726 if (--expression->u.ifstate->refcount == 0) {
727 TAILQ_REMOVE(&state->interface_states,do { if (((expression->u.ifstate)->entries.tqe_next) !=
((void *)0)) (expression->u.ifstate)->entries.tqe_next
->entries.tqe_prev = (expression->u.ifstate)->entries
.tqe_prev; else (&state->interface_states)->tqh_last
= (expression->u.ifstate)->entries.tqe_prev; *(expression
->u.ifstate)->entries.tqe_prev = (expression->u.ifstate
)->entries.tqe_next; ; ; } while (0)
728 expression->u.ifstate, entries)do { if (((expression->u.ifstate)->entries.tqe_next) !=
((void *)0)) (expression->u.ifstate)->entries.tqe_next
->entries.tqe_prev = (expression->u.ifstate)->entries
.tqe_prev; else (&state->interface_states)->tqh_last
= (expression->u.ifstate)->entries.tqe_prev; *(expression
->u.ifstate)->entries.tqe_prev = (expression->u.ifstate
)->entries.tqe_next; ; ; } while (0)
;
729 free(expression->u.ifstate);
730 }
731 break;
732 case IFSD_OPER_EXTERNAL4:
733 TAILQ_REMOVE(&expression->u.external->expressions, expression,do { if (((expression)->entries.tqe_next) != ((void *)0)) (
expression)->entries.tqe_next->entries.tqe_prev = (expression
)->entries.tqe_prev; else (&expression->u.external->
expressions)->tqh_last = (expression)->entries.tqe_prev
; *(expression)->entries.tqe_prev = (expression)->entries
.tqe_next; ; ; } while (0)
734 entries)do { if (((expression)->entries.tqe_next) != ((void *)0)) (
expression)->entries.tqe_next->entries.tqe_prev = (expression
)->entries.tqe_prev; else (&expression->u.external->
expressions)->tqh_last = (expression)->entries.tqe_prev
; *(expression)->entries.tqe_prev = (expression)->entries
.tqe_next; ; ; } while (0)
;
735 if (--expression->u.external->refcount == 0) {
736 TAILQ_REMOVE(&state->external_tests,do { if (((expression->u.external)->entries.tqe_next) !=
((void *)0)) (expression->u.external)->entries.tqe_next
->entries.tqe_prev = (expression->u.external)->entries
.tqe_prev; else (&state->external_tests)->tqh_last =
(expression->u.external)->entries.tqe_prev; *(expression
->u.external)->entries.tqe_prev = (expression->u.external
)->entries.tqe_next; ; ; } while (0)
737 expression->u.external, entries)do { if (((expression->u.external)->entries.tqe_next) !=
((void *)0)) (expression->u.external)->entries.tqe_next
->entries.tqe_prev = (expression->u.external)->entries
.tqe_prev; else (&state->external_tests)->tqh_last =
(expression->u.external)->entries.tqe_prev; *(expression
->u.external)->entries.tqe_prev = (expression->u.external
)->entries.tqe_next; ; ; } while (0)
;
738 free(expression->u.external->command);
739 event_del(&expression->u.external->ev);
740 free(expression->u.external);
741 }
742 break;
743 default:
744 if (expression->left != NULL((void *)0))
745 remove_expression(expression->left, state);
746 if (expression->right != NULL((void *)0))
747 remove_expression(expression->right, state);
748 break;
749 }
750 free(expression);
751}