]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/execute.c
- Silence benign static analysis warnings.
[thirdparty/dhcp.git] / common / execute.c
1 /* execute.c
2
3 Support for executable statements. */
4
5 /*
6 * Copyright (c) 2009,2013 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1998-2003 by Internet Software Consortium
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * https://www.isc.org/
27 *
28 * This software has been written for Internet Systems Consortium
29 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30 * To learn more about Internet Systems Consortium, see
31 * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
32 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33 * ``http://www.nominum.com''.
34 */
35
36 #include "dhcpd.h"
37 #include <omapip/omapip_p.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40
41 int execute_statements (result, packet, lease, client_state,
42 in_options, out_options, scope, statements)
43 struct binding_value **result;
44 struct packet *packet;
45 struct lease *lease;
46 struct client_state *client_state;
47 struct option_state *in_options;
48 struct option_state *out_options;
49 struct binding_scope **scope;
50 struct executable_statement *statements;
51 {
52 struct executable_statement *r, *e, *next;
53 int rc;
54 int status;
55 struct binding *binding;
56 struct data_string ds;
57 struct binding_scope *ns;
58
59 if (!statements)
60 return 1;
61
62 r = (struct executable_statement *)0;
63 next = (struct executable_statement *)0;
64 e = (struct executable_statement *)0;
65 executable_statement_reference (&r, statements, MDL);
66 while (r && !(result && *result)) {
67 if (r -> next)
68 executable_statement_reference (&next, r -> next, MDL);
69 switch (r -> op) {
70 case statements_statement:
71 #if defined (DEBUG_EXPRESSIONS)
72 log_debug ("exec: statements");
73 #endif
74 status = execute_statements (result, packet, lease,
75 client_state, in_options,
76 out_options, scope,
77 r -> data.statements);
78 #if defined (DEBUG_EXPRESSIONS)
79 log_debug ("exec: statements returns %d", status);
80 #endif
81 if (!status)
82 return 0;
83 break;
84
85 case on_statement:
86 if (lease) {
87 if (r -> data.on.evtypes & ON_EXPIRY) {
88 #if defined (DEBUG_EXPRESSIONS)
89 log_debug ("exec: on expiry");
90 #endif
91 if (lease -> on_expiry)
92 executable_statement_dereference
93 (&lease -> on_expiry, MDL);
94 if (r -> data.on.statements)
95 executable_statement_reference
96 (&lease -> on_expiry,
97 r -> data.on.statements, MDL);
98 }
99 if (r -> data.on.evtypes & ON_RELEASE) {
100 #if defined (DEBUG_EXPRESSIONS)
101 log_debug ("exec: on release");
102 #endif
103 if (lease -> on_release)
104 executable_statement_dereference
105 (&lease -> on_release, MDL);
106 if (r -> data.on.statements)
107 executable_statement_reference
108 (&lease -> on_release,
109 r -> data.on.statements, MDL);
110 }
111 if (r -> data.on.evtypes & ON_COMMIT) {
112 #if defined (DEBUG_EXPRESSIONS)
113 log_debug ("exec: on commit");
114 #endif
115 if (lease -> on_commit)
116 executable_statement_dereference
117 (&lease -> on_commit, MDL);
118 if (r -> data.on.statements)
119 executable_statement_reference
120 (&lease -> on_commit,
121 r -> data.on.statements, MDL);
122 }
123 }
124 break;
125
126 case switch_statement:
127 #if defined (DEBUG_EXPRESSIONS)
128 log_debug ("exec: switch");
129 #endif
130 status = (find_matching_case
131 (&e, packet, lease, client_state,
132 in_options, out_options, scope,
133 r -> data.s_switch.expr,
134 r -> data.s_switch.statements));
135 #if defined (DEBUG_EXPRESSIONS)
136 log_debug ("exec: switch: case %lx", (unsigned long)e);
137 #endif
138 if (status) {
139 if (!(execute_statements
140 (result, packet, lease, client_state,
141 in_options, out_options, scope, e))) {
142 executable_statement_dereference
143 (&e, MDL);
144 return 0;
145 }
146 executable_statement_dereference (&e, MDL);
147 }
148 break;
149
150 /* These have no effect when executed. */
151 case case_statement:
152 case default_statement:
153 break;
154
155 case if_statement:
156 status = (evaluate_boolean_expression
157 (&rc, packet,
158 lease, client_state, in_options,
159 out_options, scope, r -> data.ie.expr));
160
161 #if defined (DEBUG_EXPRESSIONS)
162 log_debug ("exec: if %s", (status
163 ? (rc ? "true" : "false")
164 : "NULL"));
165 #endif
166 /* XXX Treat NULL as false */
167 if (!status)
168 rc = 0;
169 if (!execute_statements
170 (result, packet, lease, client_state,
171 in_options, out_options, scope,
172 rc ? r -> data.ie.tc : r -> data.ie.fc))
173 return 0;
174 break;
175
176 case eval_statement:
177 status = evaluate_expression
178 ((struct binding_value **)0,
179 packet, lease, client_state, in_options,
180 out_options, scope, r -> data.eval, MDL);
181 #if defined (DEBUG_EXPRESSIONS)
182 log_debug ("exec: evaluate: %s",
183 (status ? "succeeded" : "failed"));
184 #else
185 POST(status);
186 #endif
187 break;
188
189 case execute_statement: {
190 #ifdef ENABLE_EXECUTE
191 struct expression *expr;
192 char **argv;
193 int i, argc = r->data.execute.argc;
194 pid_t p;
195
196 /* save room for the command and the NULL terminator */
197 argv = dmalloc((argc + 2) * sizeof(*argv), MDL);
198 if (!argv)
199 break;
200
201 argv[0] = dmalloc(strlen(r->data.execute.command) + 1,
202 MDL);
203 if (argv[0]) {
204 strcpy(argv[0], r->data.execute.command);
205 } else {
206 goto execute_out;
207 }
208
209 log_debug("execute_statement argv[0] = %s", argv[0]);
210
211 for (i = 1, expr = r->data.execute.arglist; expr;
212 expr = expr->data.arg.next, i++) {
213 memset (&ds, 0, sizeof(ds));
214 status = (evaluate_data_expression
215 (&ds, packet,
216 lease, client_state, in_options,
217 out_options, scope,
218 expr->data.arg.val, MDL));
219 if (status) {
220 argv[i] = dmalloc(ds.len + 1, MDL);
221 if (argv[i]) {
222 memcpy(argv[i], ds.data,
223 ds.len);
224 argv[i][ds.len] = 0;
225 log_debug("execute_statement argv[%d] = %s", i, argv[i]);
226 }
227 data_string_forget (&ds, MDL);
228 if (!argv[i]) {
229 log_debug("execute_statement failed argv[%d]", i);
230 goto execute_out;
231 }
232 } else {
233 log_debug("execute: bad arg %d", i);
234 goto execute_out;
235 }
236 }
237 argv[i] = NULL;
238
239 if ((p = fork()) > 0) {
240 int status;
241 waitpid(p, &status, 0);
242
243 if (status) {
244 log_error("execute: %s exit status %d",
245 argv[0], status);
246 }
247 } else if (p == 0) {
248 execvp(argv[0], argv);
249 log_error("Unable to execute %s: %m", argv[0]);
250 _exit(127);
251 } else {
252 log_error("execute: fork() failed");
253 }
254
255 execute_out:
256 for (i = 0; i <= argc; i++) {
257 if(argv[i])
258 dfree(argv[i], MDL);
259 }
260
261 dfree(argv, MDL);
262 #else /* !ENABLE_EXECUTE */
263 log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE "
264 "is not defined).", MDL);
265 #endif /* ENABLE_EXECUTE */
266 break;
267 }
268
269 case return_statement:
270 status = evaluate_expression
271 (result, packet,
272 lease, client_state, in_options,
273 out_options, scope, r -> data.retval, MDL);
274 #if defined (DEBUG_EXPRESSIONS)
275 log_debug ("exec: return: %s",
276 (status ? "succeeded" : "failed"));
277 #else
278 POST(status);
279 #endif
280 break;
281
282 case add_statement:
283 #if defined (DEBUG_EXPRESSIONS)
284 log_debug ("exec: add %s", (r -> data.add -> name
285 ? r -> data.add -> name
286 : "<unnamed class>"));
287 #endif
288 classify (packet, r -> data.add);
289 break;
290
291 case break_statement:
292 #if defined (DEBUG_EXPRESSIONS)
293 log_debug ("exec: break");
294 #endif
295 return 1;
296
297 case supersede_option_statement:
298 case send_option_statement:
299 #if defined (DEBUG_EXPRESSIONS)
300 log_debug ("exec: %s option %s.%s",
301 (r -> op == supersede_option_statement
302 ? "supersede" : "send"),
303 r -> data.option -> option -> universe -> name,
304 r -> data.option -> option -> name);
305 goto option_statement;
306 #endif
307 case default_option_statement:
308 #if defined (DEBUG_EXPRESSIONS)
309 log_debug ("exec: default option %s.%s",
310 r -> data.option -> option -> universe -> name,
311 r -> data.option -> option -> name);
312 goto option_statement;
313 #endif
314 case append_option_statement:
315 #if defined (DEBUG_EXPRESSIONS)
316 log_debug ("exec: append option %s.%s",
317 r -> data.option -> option -> universe -> name,
318 r -> data.option -> option -> name);
319 goto option_statement;
320 #endif
321 case prepend_option_statement:
322 #if defined (DEBUG_EXPRESSIONS)
323 log_debug ("exec: prepend option %s.%s",
324 r -> data.option -> option -> universe -> name,
325 r -> data.option -> option -> name);
326 option_statement:
327 #endif
328 set_option (r -> data.option -> option -> universe,
329 out_options, r -> data.option, r -> op);
330 break;
331
332 case set_statement:
333 case define_statement:
334 status = 1;
335 if (!scope) {
336 log_error("set %s: no scope",
337 r->data.set.name);
338 break;
339 }
340 if (!*scope) {
341 if (!binding_scope_allocate(scope, MDL)) {
342 log_error("set %s: can't allocate scope",
343 r->data.set.name);
344 break;
345 }
346 }
347 binding = find_binding(*scope, r->data.set.name);
348 #if defined (DEBUG_EXPRESSIONS)
349 log_debug("exec: set %s", r->data.set.name);
350 #else
351 POST(status);
352 #endif
353 if (binding == NULL) {
354 binding = dmalloc(sizeof(*binding), MDL);
355 if (binding != NULL) {
356 memset(binding, 0, sizeof(*binding));
357 binding->name =
358 dmalloc(strlen
359 (r->data.set.name) + 1,
360 MDL);
361 if (binding->name != NULL) {
362 strcpy(binding->name, r->data.set.name);
363 binding->next = (*scope)->bindings;
364 (*scope)->bindings = binding;
365 } else {
366 dfree(binding, MDL);
367 binding = NULL;
368 }
369 }
370 }
371 if (binding != NULL) {
372 if (binding->value != NULL)
373 binding_value_dereference
374 (&binding->value, MDL);
375 if (r->op == set_statement) {
376 status = (evaluate_expression
377 (&binding->value, packet,
378 lease, client_state,
379 in_options, out_options,
380 scope, r->data.set.expr,
381 MDL));
382 } else {
383 if (!(binding_value_allocate
384 (&binding->value, MDL))) {
385 dfree(binding, MDL);
386 binding = NULL;
387 }
388 if ((binding != NULL) &&
389 (binding->value != NULL)) {
390 binding->value->type =
391 binding_function;
392 (fundef_reference
393 (&binding->value->value.fundef,
394 r->data.set.expr->data.func,
395 MDL));
396 }
397 }
398 }
399 #if defined (DEBUG_EXPRESSIONS)
400 log_debug ("exec: set %s%s", r -> data.set.name,
401 (binding && status ? "" : " (failed)"));
402 #else
403 POST(status);
404 #endif
405 break;
406
407 case unset_statement:
408 if (!scope || !*scope)
409 break;
410 binding = find_binding (*scope, r -> data.unset);
411 if (binding) {
412 if (binding -> value)
413 binding_value_dereference
414 (&binding -> value, MDL);
415 status = 1;
416 } else
417 status = 0;
418 #if defined (DEBUG_EXPRESSIONS)
419 log_debug ("exec: unset %s: %s", r -> data.unset,
420 (status ? "found" : "not found"));
421 #else
422 POST(status);
423 #endif
424 break;
425
426 case let_statement:
427 #if defined (DEBUG_EXPRESSIONS)
428 log_debug("exec: let %s", r->data.let.name);
429 #endif
430 status = 0;
431 ns = NULL;
432 binding_scope_allocate (&ns, MDL);
433 e = r;
434
435 next_let:
436 if (ns) {
437 binding = dmalloc(sizeof(*binding), MDL);
438 memset(binding, 0, sizeof(*binding));
439 if (!binding) {
440 blb:
441 binding_scope_dereference(&ns, MDL);
442 } else {
443 binding->name =
444 dmalloc(strlen
445 (e->data.let.name + 1),
446 MDL);
447 if (binding->name)
448 strcpy(binding->name,
449 e->data.let.name);
450 else {
451 dfree(binding, MDL);
452 binding = NULL;
453 goto blb;
454 }
455 }
456 } else
457 binding = NULL;
458
459 if (ns && binding) {
460 status = (evaluate_expression
461 (&binding->value, packet, lease,
462 client_state,
463 in_options, out_options,
464 scope, e->data.set.expr, MDL));
465 binding->next = ns->bindings;
466 ns->bindings = binding;
467 }
468
469 #if defined (DEBUG_EXPRESSIONS)
470 log_debug("exec: let %s%s", e->data.let.name,
471 (binding && status ? "" : "failed"));
472 #else
473 POST(status);
474 #endif
475 if (!e->data.let.statements) {
476 } else if (e->data.let.statements->op ==
477 let_statement) {
478 e = e->data.let.statements;
479 goto next_let;
480 } else if (ns) {
481 if (scope && *scope)
482 binding_scope_reference(&ns->outer,
483 *scope, MDL);
484 execute_statements
485 (result, packet, lease,
486 client_state,
487 in_options, out_options,
488 &ns, e->data.let.statements);
489 }
490 if (ns)
491 binding_scope_dereference(&ns, MDL);
492 break;
493
494 case log_statement:
495 memset (&ds, 0, sizeof ds);
496 status = (evaluate_data_expression
497 (&ds, packet,
498 lease, client_state, in_options,
499 out_options, scope, r -> data.log.expr,
500 MDL));
501
502 #if defined (DEBUG_EXPRESSIONS)
503 log_debug ("exec: log");
504 #endif
505
506 if (status) {
507 switch (r -> data.log.priority) {
508 case log_priority_fatal:
509 log_fatal ("%.*s", (int)ds.len,
510 ds.data);
511 break;
512 case log_priority_error:
513 log_error ("%.*s", (int)ds.len,
514 ds.data);
515 break;
516 case log_priority_debug:
517 log_debug ("%.*s", (int)ds.len,
518 ds.data);
519 break;
520 case log_priority_info:
521 log_info ("%.*s", (int)ds.len,
522 ds.data);
523 break;
524 }
525 data_string_forget (&ds, MDL);
526 }
527
528 break;
529
530 default:
531 log_error ("bogus statement type %d", r -> op);
532 break;
533 }
534 executable_statement_dereference (&r, MDL);
535 if (next) {
536 executable_statement_reference (&r, next, MDL);
537 executable_statement_dereference (&next, MDL);
538 }
539 }
540
541 return 1;
542 }
543
544 /* Execute all the statements in a particular scope, and all statements in
545 scopes outer from that scope, but if a particular limiting scope is
546 reached, do not execute statements in that scope or in scopes outer
547 from it. More specific scopes need to take precedence over less
548 specific scopes, so we recursively traverse the scope list, executing
549 the most outer scope first. */
550
551 void execute_statements_in_scope (result, packet,
552 lease, client_state, in_options, out_options,
553 scope, group, limiting_group)
554 struct binding_value **result;
555 struct packet *packet;
556 struct lease *lease;
557 struct client_state *client_state;
558 struct option_state *in_options;
559 struct option_state *out_options;
560 struct binding_scope **scope;
561 struct group *group;
562 struct group *limiting_group;
563 {
564 struct group *limit;
565
566 /* If we've recursed as far as we can, return. */
567 if (!group)
568 return;
569
570 /* As soon as we get to a scope that is outer than the limiting
571 scope, we are done. This is so that if somebody does something
572 like this, it does the expected thing:
573
574 domain-name "fugue.com";
575 shared-network FOO {
576 host bar {
577 domain-name "othello.fugue.com";
578 fixed-address 10.20.30.40;
579 }
580 subnet 10.20.30.0 netmask 255.255.255.0 {
581 domain-name "manhattan.fugue.com";
582 }
583 }
584
585 The problem with the above arrangement is that the host's
586 group nesting will be host -> shared-network -> top-level,
587 and the limiting scope when we evaluate the host's scope
588 will be the subnet -> shared-network -> top-level, so we need
589 to know when we evaluate the host's scope to stop before we
590 evaluate the shared-networks scope, because it's outer than
591 the limiting scope, which means we've already evaluated it. */
592
593 for (limit = limiting_group; limit; limit = limit -> next) {
594 if (group == limit)
595 return;
596 }
597
598 if (group -> next)
599 execute_statements_in_scope (result, packet,
600 lease, client_state,
601 in_options, out_options, scope,
602 group -> next, limiting_group);
603 execute_statements (result, packet, lease, client_state, in_options,
604 out_options, scope, group -> statements);
605 }
606
607 /* Dereference or free any subexpressions of a statement being freed. */
608
609 int executable_statement_dereference (ptr, file, line)
610 struct executable_statement **ptr;
611 const char *file;
612 int line;
613 {
614 if (!ptr || !*ptr) {
615 log_error ("%s(%d): null pointer", file, line);
616 #if defined (POINTER_DEBUG)
617 abort ();
618 #else
619 return 0;
620 #endif
621 }
622
623 (*ptr) -> refcnt--;
624 rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
625 if ((*ptr) -> refcnt > 0) {
626 *ptr = (struct executable_statement *)0;
627 return 1;
628 }
629
630 if ((*ptr) -> refcnt < 0) {
631 log_error ("%s(%d): negative refcnt!", file, line);
632 #if defined (DEBUG_RC_HISTORY)
633 dump_rc_history (*ptr);
634 #endif
635 #if defined (POINTER_DEBUG)
636 abort ();
637 #else
638 return 0;
639 #endif
640 }
641
642 if ((*ptr) -> next)
643 executable_statement_dereference (&(*ptr) -> next, file, line);
644
645 switch ((*ptr) -> op) {
646 case statements_statement:
647 if ((*ptr) -> data.statements)
648 executable_statement_dereference
649 (&(*ptr) -> data.statements, file, line);
650 break;
651
652 case on_statement:
653 if ((*ptr) -> data.on.statements)
654 executable_statement_dereference
655 (&(*ptr) -> data.on.statements, file, line);
656 break;
657
658 case switch_statement:
659 if ((*ptr) -> data.s_switch.statements)
660 executable_statement_dereference
661 (&(*ptr) -> data.on.statements, file, line);
662 if ((*ptr) -> data.s_switch.expr)
663 expression_dereference (&(*ptr) -> data.s_switch.expr,
664 file, line);
665 break;
666
667 case case_statement:
668 if ((*ptr) -> data.s_switch.expr)
669 expression_dereference (&(*ptr) -> data.c_case,
670 file, line);
671 break;
672
673 case if_statement:
674 if ((*ptr) -> data.ie.expr)
675 expression_dereference (&(*ptr) -> data.ie.expr,
676 file, line);
677 if ((*ptr) -> data.ie.tc)
678 executable_statement_dereference
679 (&(*ptr) -> data.ie.tc, file, line);
680 if ((*ptr) -> data.ie.fc)
681 executable_statement_dereference
682 (&(*ptr) -> data.ie.fc, file, line);
683 break;
684
685 case eval_statement:
686 if ((*ptr) -> data.eval)
687 expression_dereference (&(*ptr) -> data.eval,
688 file, line);
689 break;
690
691 case return_statement:
692 if ((*ptr) -> data.eval)
693 expression_dereference (&(*ptr) -> data.eval,
694 file, line);
695 break;
696
697 case set_statement:
698 if ((*ptr)->data.set.name)
699 dfree ((*ptr)->data.set.name, file, line);
700 if ((*ptr)->data.set.expr)
701 expression_dereference (&(*ptr) -> data.set.expr,
702 file, line);
703 break;
704
705 case unset_statement:
706 if ((*ptr)->data.unset)
707 dfree ((*ptr)->data.unset, file, line);
708 break;
709
710 case execute_statement:
711 if ((*ptr)->data.execute.command)
712 dfree ((*ptr)->data.execute.command, file, line);
713 if ((*ptr)->data.execute.arglist)
714 expression_dereference (&(*ptr) -> data.execute.arglist,
715 file, line);
716 break;
717
718 case supersede_option_statement:
719 case send_option_statement:
720 case default_option_statement:
721 case append_option_statement:
722 case prepend_option_statement:
723 if ((*ptr) -> data.option)
724 option_cache_dereference (&(*ptr) -> data.option,
725 file, line);
726 break;
727
728 default:
729 /* Nothing to do. */
730 break;
731 }
732
733 dfree ((*ptr), file, line);
734 *ptr = (struct executable_statement *)0;
735 return 1;
736 }
737
738 void write_statements (file, statements, indent)
739 FILE *file;
740 struct executable_statement *statements;
741 int indent;
742 {
743 #if defined ENABLE_EXECUTE
744 struct expression *expr;
745 #endif
746 struct executable_statement *r, *x;
747 const char *s, *t, *dot;
748 int col;
749
750 if (!statements)
751 return;
752
753 for (r = statements; r; r = r -> next) {
754 switch (r -> op) {
755 case statements_statement:
756 write_statements (file, r -> data.statements, indent);
757 break;
758
759 case on_statement:
760 indent_spaces (file, indent);
761 fprintf (file, "on ");
762 s = "";
763 if (r -> data.on.evtypes & ON_EXPIRY) {
764 fprintf (file, "%sexpiry", s);
765 s = " or ";
766 }
767 if (r -> data.on.evtypes & ON_COMMIT) {
768 fprintf (file, "%scommit", s);
769 s = " or ";
770 }
771 if (r -> data.on.evtypes & ON_RELEASE) {
772 fprintf (file, "%srelease", s);
773 /* s = " or "; */
774 }
775 if (r -> data.on.statements) {
776 fprintf (file, " {");
777 write_statements (file,
778 r -> data.on.statements,
779 indent + 2);
780 indent_spaces (file, indent);
781 fprintf (file, "}");
782 } else {
783 fprintf (file, ";");
784 }
785 break;
786
787 case switch_statement:
788 indent_spaces (file, indent);
789 fprintf (file, "switch (");
790 col = write_expression (file,
791 r -> data.s_switch.expr,
792 indent + 7, indent + 7, 1);
793 col = token_print_indent (file, col, indent + 7,
794 "", "", ")");
795 token_print_indent (file,
796 col, indent, " ", "", "{");
797 write_statements (file, r -> data.s_switch.statements,
798 indent + 2);
799 indent_spaces (file, indent);
800 fprintf (file, "}");
801 break;
802
803 case case_statement:
804 indent_spaces (file, indent - 1);
805 fprintf (file, "case ");
806 col = write_expression (file,
807 r -> data.s_switch.expr,
808 indent + 5, indent + 5, 1);
809 token_print_indent (file, col, indent + 5,
810 "", "", ":");
811 break;
812
813 case default_statement:
814 indent_spaces (file, indent - 1);
815 fprintf (file, "default: ");
816 break;
817
818 case if_statement:
819 indent_spaces (file, indent);
820 fprintf (file, "if ");
821 x = r;
822 col = write_expression (file,
823 x -> data.ie.expr,
824 indent + 3, indent + 3, 1);
825 else_if:
826 token_print_indent (file, col, indent, " ", "", "{");
827 write_statements (file, x -> data.ie.tc, indent + 2);
828 if (x -> data.ie.fc &&
829 x -> data.ie.fc -> op == if_statement &&
830 !x -> data.ie.fc -> next) {
831 indent_spaces (file, indent);
832 fprintf (file, "} elsif ");
833 x = x -> data.ie.fc;
834 col = write_expression (file,
835 x -> data.ie.expr,
836 indent + 6,
837 indent + 6, 1);
838 goto else_if;
839 }
840 if (x -> data.ie.fc) {
841 indent_spaces (file, indent);
842 fprintf (file, "} else {");
843 write_statements (file, x -> data.ie.fc,
844 indent + 2);
845 }
846 indent_spaces (file, indent);
847 fprintf (file, "}");
848 break;
849
850 case eval_statement:
851 indent_spaces (file, indent);
852 fprintf (file, "eval ");
853 (void) write_expression (file, r -> data.eval,
854 indent + 5, indent + 5, 1);
855 fprintf (file, ";");
856 break;
857
858 case return_statement:
859 indent_spaces (file, indent);
860 fprintf (file, "return;");
861 break;
862
863 case add_statement:
864 indent_spaces (file, indent);
865 fprintf (file, "add \"%s\"", r -> data.add -> name);
866 break;
867
868 case break_statement:
869 indent_spaces (file, indent);
870 fprintf (file, "break;");
871 break;
872
873 case supersede_option_statement:
874 case send_option_statement:
875 s = "supersede";
876 goto option_statement;
877
878 case default_option_statement:
879 s = "default";
880 goto option_statement;
881
882 case append_option_statement:
883 s = "append";
884 goto option_statement;
885
886 case prepend_option_statement:
887 s = "prepend";
888 option_statement:
889 /* Note: the reason we don't try to pretty print
890 the option here is that the format of the option
891 may change in dhcpd.conf, and then when this
892 statement was read back, it would cause a syntax
893 error. */
894 if (r -> data.option -> option -> universe ==
895 &dhcp_universe) {
896 t = "";
897 dot = "";
898 } else {
899 t = (r -> data.option -> option ->
900 universe -> name);
901 dot = ".";
902 }
903 indent_spaces (file, indent);
904 fprintf (file, "%s %s%s%s = ", s, t, dot,
905 r -> data.option -> option -> name);
906 col = (indent + strlen (s) + strlen (t) +
907 strlen (dot) + strlen (r -> data.option ->
908 option -> name) + 4);
909 if (r -> data.option -> expression)
910 write_expression
911 (file,
912 r -> data.option -> expression,
913 col, indent + 8, 1);
914 else
915 token_indent_data_string
916 (file, col, indent + 8, "", "",
917 &r -> data.option -> data);
918
919 fprintf (file, ";"); /* XXX */
920 break;
921
922 case set_statement:
923 indent_spaces (file, indent);
924 fprintf (file, "set ");
925 col = token_print_indent (file, indent + 4, indent + 4,
926 "", "", r -> data.set.name);
927 (void) token_print_indent (file, col, indent + 4,
928 " ", " ", "=");
929 col = write_expression (file, r -> data.set.expr,
930 indent + 3, indent + 3, 0);
931 (void) token_print_indent (file, col, indent + 4,
932 " ", "", ";");
933 break;
934
935 case unset_statement:
936 indent_spaces (file, indent);
937 fprintf (file, "unset ");
938 col = token_print_indent (file, indent + 6, indent + 6,
939 "", "", r -> data.set.name);
940 (void) token_print_indent (file, col, indent + 6,
941 " ", "", ";");
942 break;
943
944 case log_statement:
945 indent_spaces (file, indent);
946 fprintf (file, "log ");
947 col = token_print_indent (file, indent + 4, indent + 4,
948 "", "", "(");
949 switch (r -> data.log.priority) {
950 case log_priority_fatal:
951 (void) token_print_indent
952 (file, col, indent + 4, "",
953 " ", "fatal,");
954 break;
955 case log_priority_error:
956 (void) token_print_indent
957 (file, col, indent + 4, "",
958 " ", "error,");
959 break;
960 case log_priority_debug:
961 (void) token_print_indent
962 (file, col, indent + 4, "",
963 " ", "debug,");
964 break;
965 case log_priority_info:
966 (void) token_print_indent
967 (file, col, indent + 4, "",
968 " ", "info,");
969 break;
970 }
971 col = write_expression (file, r -> data.log.expr,
972 indent + 4, indent + 4, 0);
973 (void) token_print_indent (file, col, indent + 4,
974 "", "", ");");
975
976 break;
977
978 case execute_statement:
979 #ifdef ENABLE_EXECUTE
980 indent_spaces (file, indent);
981 col = token_print_indent(file, indent + 4, indent + 4,
982 "", "", "execute");
983 col = token_print_indent(file, col, indent + 4, " ", "",
984 "(");
985 col = token_print_indent(file, col, indent + 4, "\"", "\"", r->data.execute.command);
986 for (expr = r->data.execute.arglist; expr; expr = expr->data.arg.next) {
987 col = token_print_indent(file, col, indent + 4, "", " ", ",");
988 col = write_expression (file, expr->data.arg.val, col, indent + 4, 0);
989 }
990 (void) token_print_indent(file, col, indent + 4, "", "", ");");
991 #else /* !ENABLE_EXECUTE */
992 log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE "
993 "is not defined).", MDL);
994 #endif /* ENABLE_EXECUTE */
995 break;
996
997 default:
998 log_fatal ("bogus statement type %d\n", r -> op);
999 }
1000 }
1001 }
1002
1003 /* Find a case statement in the sequence of executable statements that
1004 matches the expression, and if found, return the following statement.
1005 If no case statement matches, try to find a default statement and
1006 return that (the default statement can precede all the case statements).
1007 Otherwise, return the null statement. */
1008
1009 int find_matching_case (struct executable_statement **ep,
1010 struct packet *packet, struct lease *lease,
1011 struct client_state *client_state,
1012 struct option_state *in_options,
1013 struct option_state *out_options,
1014 struct binding_scope **scope,
1015 struct expression *expr,
1016 struct executable_statement *stmt)
1017 {
1018 int status, sub;
1019 struct executable_statement *s;
1020
1021 if (is_data_expression (expr)) {
1022 struct data_string cd, ds;
1023 memset (&ds, 0, sizeof ds);
1024 memset (&cd, 0, sizeof cd);
1025
1026 status = (evaluate_data_expression (&ds, packet, lease,
1027 client_state, in_options,
1028 out_options, scope, expr,
1029 MDL));
1030 if (status) {
1031 for (s = stmt; s; s = s -> next) {
1032 if (s -> op == case_statement) {
1033 sub = (evaluate_data_expression
1034 (&cd, packet, lease, client_state,
1035 in_options, out_options,
1036 scope, s -> data.c_case, MDL));
1037 if (sub && cd.len == ds.len &&
1038 !memcmp (cd.data, ds.data, cd.len))
1039 {
1040 data_string_forget (&cd, MDL);
1041 data_string_forget (&ds, MDL);
1042 executable_statement_reference
1043 (ep, s -> next, MDL);
1044 return 1;
1045 }
1046 data_string_forget (&cd, MDL);
1047 }
1048 }
1049 data_string_forget (&ds, MDL);
1050 }
1051 } else {
1052 unsigned long n, c;
1053 status = evaluate_numeric_expression (&n, packet, lease,
1054 client_state,
1055 in_options, out_options,
1056 scope, expr);
1057
1058 if (status) {
1059 for (s = stmt; s; s = s -> next) {
1060 if (s -> op == case_statement) {
1061 sub = (evaluate_numeric_expression
1062 (&c, packet, lease, client_state,
1063 in_options, out_options,
1064 scope, s -> data.c_case));
1065 if (sub && n == c) {
1066 executable_statement_reference
1067 (ep, s -> next, MDL);
1068 return 1;
1069 }
1070 }
1071 }
1072 }
1073 }
1074
1075 /* If we didn't find a matching case statement, look for a default
1076 statement and return the statement following it. */
1077 for (s = stmt; s; s = s -> next)
1078 if (s -> op == default_statement)
1079 break;
1080 if (s) {
1081 executable_statement_reference (ep, s -> next, MDL);
1082 return 1;
1083 }
1084 return 0;
1085 }
1086
1087 int executable_statement_foreach (struct executable_statement *stmt,
1088 int (*callback) (struct
1089 executable_statement *,
1090 void *, int),
1091 void *vp, int condp)
1092 {
1093 struct executable_statement *foo;
1094 int ok = 0;
1095
1096 for (foo = stmt; foo; foo = foo -> next) {
1097 if ((*callback) (foo, vp, condp) != 0)
1098 ok = 1;
1099 switch (foo -> op) {
1100 case null_statement:
1101 break;
1102 case if_statement:
1103 if (executable_statement_foreach (foo -> data.ie.tc,
1104 callback, vp, 1))
1105 ok = 1;
1106 if (executable_statement_foreach (foo -> data.ie.fc,
1107 callback, vp, 1))
1108 ok = 1;
1109 break;
1110 case add_statement:
1111 break;
1112 case eval_statement:
1113 break;
1114 case break_statement:
1115 break;
1116 case default_option_statement:
1117 break;
1118 case supersede_option_statement:
1119 break;
1120 case append_option_statement:
1121 break;
1122 case prepend_option_statement:
1123 break;
1124 case send_option_statement:
1125 break;
1126 case statements_statement:
1127 if ((executable_statement_foreach
1128 (foo -> data.statements, callback, vp, condp)))
1129 ok = 1;
1130 break;
1131 case on_statement:
1132 if ((executable_statement_foreach
1133 (foo -> data.on.statements, callback, vp, 1)))
1134 ok = 1;
1135 break;
1136 case switch_statement:
1137 if ((executable_statement_foreach
1138 (foo -> data.s_switch.statements, callback, vp, 1)))
1139 ok = 1;
1140 break;
1141 case case_statement:
1142 break;
1143 case default_statement:
1144 break;
1145 case set_statement:
1146 break;
1147 case unset_statement:
1148 break;
1149 case let_statement:
1150 if ((executable_statement_foreach
1151 (foo -> data.let.statements, callback, vp, 0)))
1152 ok = 1;
1153 break;
1154 case define_statement:
1155 break;
1156 case log_statement:
1157 case return_statement:
1158 case execute_statement:
1159 break;
1160 }
1161 }
1162 return ok;
1163 }