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