File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / execute.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: /* execute.c
    2: 
    3:    Support for executable statements. */
    4: 
    5: /*
    6:  * Copyright (c) 2009,2012 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: #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) {
  331: 				log_error("set %s: no scope",
  332: 					   r->data.set.name);
  333: 				status = 0;
  334: 				break;
  335: 			}
  336: 			if (!*scope) {
  337: 			    if (!binding_scope_allocate(scope, MDL)) {
  338: 				log_error("set %s: can't allocate scope",
  339: 					  r->data.set.name);
  340: 				status = 0;
  341: 				break;
  342: 			    }
  343: 			}
  344: 			binding = find_binding(*scope, r->data.set.name);
  345: #if defined (DEBUG_EXPRESSIONS)
  346: 			log_debug("exec: set %s", r->data.set.name);
  347: #endif
  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;
  360: 				    } else {
  361: 					dfree(binding, MDL);
  362: 					binding = NULL;
  363: 				    }
  364: 				}
  365: 			}
  366: 			if (binding != NULL) {
  367: 				if (binding->value != NULL)
  368: 					binding_value_dereference
  369: 						(&binding->value, MDL);
  370: 				if (r->op == set_statement) {
  371: 					status = (evaluate_expression
  372: 						  (&binding->value, packet,
  373: 						   lease, client_state,
  374: 						   in_options, out_options,
  375: 						   scope, r->data.set.expr,
  376: 						   MDL));
  377: 				} else {
  378: 				    if (!(binding_value_allocate
  379: 					  (&binding->value, MDL))) {
  380: 					    dfree(binding, MDL);
  381: 					    binding = NULL;
  382: 				    }
  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));
  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>