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