common/execute.c

Go to the documentation of this file.
00001 /* execute.c
00002 
00003    Support for executable statements. */
00004 
00005 /*
00006  * Copyright (c) 2009,2013,2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 1998-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
00027  *
00028  */
00029 
00030 #include "dhcpd.h"
00031 #include <omapip/omapip_p.h>
00032 #include <sys/types.h>
00033 #include <sys/wait.h>
00034 
00035 int execute_statements (result, packet, lease, client_state,
00036                         in_options, out_options, scope, statements,
00037                         on_star)
00038         struct binding_value **result;
00039         struct packet *packet;
00040         struct lease *lease;
00041         struct client_state *client_state;
00042         struct option_state *in_options;
00043         struct option_state *out_options;
00044         struct binding_scope **scope;
00045         struct executable_statement *statements;
00046         struct on_star *on_star;
00047 {
00048         struct executable_statement *r, *e, *next;
00049         int rc;
00050         int status;
00051         struct binding *binding;
00052         struct data_string ds;
00053         struct binding_scope *ns;
00054 
00055         if (!statements)
00056                 return 1;
00057 
00058         r = NULL;
00059         next = NULL;
00060         e = NULL;
00061         executable_statement_reference (&r, statements, MDL);
00062         while (r && !(result && *result)) {
00063                 if (r->next)
00064                         executable_statement_reference (&next, r->next, MDL);
00065                 switch (r->op) {
00066                       case statements_statement:
00067 #if defined (DEBUG_EXPRESSIONS)
00068                         log_debug ("exec: statements");
00069 #endif
00070                         status = execute_statements (result, packet, lease,
00071                                                      client_state, in_options,
00072                                                      out_options, scope,
00073                                                      r->data.statements,
00074                                                      on_star);
00075 #if defined (DEBUG_EXPRESSIONS)
00076                         log_debug ("exec: statements returns %d", status);
00077 #endif
00078                         if (!status)
00079                                 return 0;
00080                         break;
00081 
00082                       case on_statement:
00083                         /*
00084                          * if we haven't been passed an on_star block but
00085                          * do have a lease, use the one from the lease
00086                          * This handles the previous v4 calls.
00087                          */
00088                         if ((on_star == NULL) && (lease != NULL))
00089                             on_star = &lease->on_star;
00090 
00091                         if (on_star != NULL) {
00092                             if (r->data.on.evtypes & ON_EXPIRY) {
00093 #if defined (DEBUG_EXPRESSIONS)
00094                                     log_debug ("exec: on expiry");
00095 #endif
00096                                 if (on_star->on_expiry)
00097                                         executable_statement_dereference
00098                                                 (&on_star->on_expiry, MDL);
00099                                 if (r->data.on.statements)
00100                                         executable_statement_reference
00101                                                 (&on_star->on_expiry,
00102                                                  r->data.on.statements, MDL);
00103                             }
00104                             if (r->data.on.evtypes & ON_RELEASE) {
00105 #if defined (DEBUG_EXPRESSIONS)
00106                                     log_debug ("exec: on release");
00107 #endif
00108                                 if (on_star->on_release)
00109                                         executable_statement_dereference
00110                                                 (&on_star->on_release, MDL);
00111                                 if (r->data.on.statements)
00112                                         executable_statement_reference
00113                                                 (&on_star->on_release,
00114                                                  r->data.on.statements, MDL);
00115                             }
00116                             if (r->data.on.evtypes & ON_COMMIT) {
00117 #if defined (DEBUG_EXPRESSIONS)
00118                                     log_debug ("exec: on commit");
00119 #endif
00120                                 if (on_star->on_commit)
00121                                         executable_statement_dereference
00122                                                 (&on_star->on_commit, MDL);
00123                                 if (r->data.on.statements)
00124                                         executable_statement_reference
00125                                                 (&on_star->on_commit,
00126                                                  r->data.on.statements, MDL);
00127                             }
00128                         }
00129                         break;
00130 
00131                       case switch_statement:
00132 #if defined (DEBUG_EXPRESSIONS)
00133                         log_debug ("exec: switch");
00134 #endif
00135                         status = (find_matching_case
00136                                   (&e, packet, lease, client_state,
00137                                    in_options, out_options, scope,
00138                                    r->data.s_switch.expr,
00139                                    r->data.s_switch.statements));
00140 #if defined (DEBUG_EXPRESSIONS)
00141                         log_debug ("exec: switch: case %lx", (unsigned long)e);
00142 #endif
00143                         if (status) {
00144                                 if (!(execute_statements
00145                                       (result, packet, lease, client_state,
00146                                        in_options, out_options, scope, e,
00147                                        on_star))) {
00148                                         executable_statement_dereference
00149                                                 (&e, MDL);
00150                                         return 0;
00151                                 }
00152                                 executable_statement_dereference (&e, MDL);
00153                         }
00154                         break;
00155 
00156                         /* These have no effect when executed. */
00157                       case case_statement:
00158                       case default_statement:
00159                         break;
00160 
00161                       case if_statement:
00162                         status = (evaluate_boolean_expression
00163                                   (&rc, packet,
00164                                    lease, client_state, in_options,
00165                                    out_options, scope, r->data.ie.expr));
00166                         
00167 #if defined (DEBUG_EXPRESSIONS)
00168                         log_debug ("exec: if %s", (status
00169                                               ? (rc ? "true" : "false")
00170                                               : "NULL"));
00171 #endif
00172                         /* XXX Treat NULL as false */
00173                         if (!status)
00174                                 rc = 0;
00175                         if (!execute_statements
00176                             (result, packet, lease, client_state,
00177                              in_options, out_options, scope,
00178                              rc ? r->data.ie.tc : r->data.ie.fc,
00179                              on_star))
00180                                 return 0;
00181                         break;
00182 
00183                       case eval_statement:
00184                         status = evaluate_expression
00185                                 (NULL, packet, lease, client_state, in_options,
00186                                  out_options, scope, r->data.eval, MDL);
00187 #if defined (DEBUG_EXPRESSIONS)
00188                         log_debug ("exec: evaluate: %s",
00189                                    (status ? "succeeded" : "failed"));
00190 #else
00191                         POST(status);
00192 #endif
00193                         break;
00194 
00195                       case execute_statement: {
00196 #ifdef ENABLE_EXECUTE
00197                         struct expression *expr;
00198                         char **argv;
00199                         int i, argc = r->data.execute.argc;
00200                         pid_t p;
00201 
00202                         /* save room for the command and the NULL terminator */
00203                         argv = dmalloc((argc + 2) * sizeof(*argv), MDL);
00204                         if (!argv)
00205                                 break;
00206 
00207                         argv[0] = dmalloc(strlen(r->data.execute.command) + 1,
00208                                           MDL);
00209                         if (argv[0]) {
00210                                 strcpy(argv[0], r->data.execute.command);
00211                         } else {
00212                                 goto execute_out;
00213                         }
00214 
00215                         log_debug("execute_statement argv[0] = %s", argv[0]);
00216  
00217                         for (i = 1, expr = r->data.execute.arglist; expr;
00218                              expr = expr->data.arg.next, i++) {
00219                                 memset (&ds, 0, sizeof(ds));
00220                                 status = (evaluate_data_expression
00221                                           (&ds, packet,
00222                                            lease, client_state, in_options,
00223                                            out_options, scope,
00224                                            expr->data.arg.val, MDL));
00225                                 if (status) {
00226                                         argv[i] = dmalloc(ds.len + 1, MDL);
00227                                         if (argv[i]) {
00228                                                 memcpy(argv[i], ds.data,
00229                                                        ds.len);
00230                                                 argv[i][ds.len] = 0;
00231                                                 log_debug("execute_statement argv[%d] = %s", i, argv[i]);
00232                                         }
00233                                         data_string_forget (&ds, MDL);
00234                                         if (!argv[i]) {
00235                                                 log_debug("execute_statement failed argv[%d]", i);
00236                                                 goto execute_out;
00237                                         }
00238                                 } else {
00239                                         log_debug("execute: bad arg %d", i);
00240                                         goto execute_out;
00241                                 }
00242                         }
00243                         argv[i] = NULL;
00244 
00245                         if ((p = fork()) > 0) {
00246                                 int status;
00247                                 waitpid(p, &status, 0);
00248 
00249                                 if (status) {
00250                                         log_error("execute: %s exit status %d",
00251                                                    argv[0], status);
00252                                 }
00253                         } else if (p == 0) {
00254                                execvp(argv[0], argv);
00255                                log_error("Unable to execute %s: %m", argv[0]);
00256                                _exit(127);
00257                         } else {
00258                                 log_error("execute: fork() failed");
00259                         }
00260 
00261                       execute_out:
00262                         for (i = 0; i <= argc; i++) {
00263                                 if(argv[i])
00264                                         dfree(argv[i], MDL);
00265                         }
00266 
00267                         dfree(argv, MDL);
00268 #else /* !ENABLE_EXECUTE */
00269                         log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE "
00270                                   "is not defined).", MDL);
00271 #endif /* ENABLE_EXECUTE */
00272                         break;
00273                       }
00274 
00275                       case return_statement:
00276                         status = evaluate_expression
00277                                 (result, packet,
00278                                  lease, client_state, in_options,
00279                                  out_options, scope, r -> data.retval, MDL);
00280 #if defined (DEBUG_EXPRESSIONS)
00281                         log_debug ("exec: return: %s",
00282                                    (status ? "succeeded" : "failed"));
00283 #else
00284                         POST(status);
00285 #endif
00286                         break;
00287 
00288                       case add_statement:
00289 #if defined (DEBUG_EXPRESSIONS)
00290                         log_debug ("exec: add %s", (r->data.add->name
00291                                                ? r->data.add->name
00292                                                : "<unnamed class>"));
00293 #endif
00294                         classify (packet, r->data.add);
00295                         break;
00296 
00297                       case break_statement:
00298 #if defined (DEBUG_EXPRESSIONS)
00299                         log_debug ("exec: break");
00300 #endif
00301                         return 1;
00302 
00303                       case supersede_option_statement:
00304                       case send_option_statement:
00305 #if defined (DEBUG_EXPRESSIONS)
00306                         log_debug ("exec: %s option %s.%s",
00307                               (r->op == supersede_option_statement
00308                                ? "supersede" : "send"),
00309                               r->data.option->option->universe->name,
00310                               r->data.option->option->name);
00311                         goto option_statement;
00312 #endif
00313                       case default_option_statement:
00314 #if defined (DEBUG_EXPRESSIONS)
00315                         log_debug ("exec: default option %s.%s",
00316                               r->data.option->option->universe->name,
00317                               r->data.option->option->name);
00318                         goto option_statement;
00319 #endif
00320                       case append_option_statement:
00321 #if defined (DEBUG_EXPRESSIONS)
00322                         log_debug ("exec: append option %s.%s",
00323                               r->data.option->option->universe->name,
00324                               r->data.option->option->name);
00325                         goto option_statement;
00326 #endif
00327                       case prepend_option_statement:
00328 #if defined (DEBUG_EXPRESSIONS)
00329                         log_debug ("exec: prepend option %s.%s",
00330                               r->data.option->option->universe->name,
00331                               r->data.option->option->name);
00332                       option_statement:
00333 #endif
00334                         set_option (r->data.option->option->universe,
00335                                     out_options, r->data.option, r->op);
00336                         break;
00337 
00338                       case set_statement:
00339                       case define_statement:
00340                         status = 1;
00341                         if (!scope) {
00342                                 log_error("set %s: no scope",
00343                                            r->data.set.name);
00344                                 break;
00345                         }
00346                         if (!*scope) {
00347                             if (!binding_scope_allocate(scope, MDL)) {
00348                                 log_error("set %s: can't allocate scope",
00349                                           r->data.set.name);
00350                                 break;
00351                             }
00352                         }
00353                         binding = find_binding(*scope, r->data.set.name);
00354 #if defined (DEBUG_EXPRESSIONS)
00355                         log_debug("exec: set %s", r->data.set.name);
00356 #else
00357                         POST(status);
00358 #endif
00359                         if (binding == NULL) {
00360                                 binding = dmalloc(sizeof(*binding), MDL);
00361                                 if (binding != NULL) {
00362                                     memset(binding, 0, sizeof(*binding));
00363                                     binding->name =
00364                                             dmalloc(strlen
00365                                                     (r->data.set.name) + 1,
00366                                                     MDL);
00367                                     if (binding->name != NULL) {
00368                                         strcpy(binding->name, r->data.set.name);
00369                                         binding->next = (*scope)->bindings;
00370                                         (*scope)->bindings = binding;
00371                                     } else {
00372                                         dfree(binding, MDL);
00373                                         binding = NULL;
00374                                     }
00375                                 }
00376                         }
00377                         if (binding != NULL) {
00378                                 if (binding->value != NULL)
00379                                         binding_value_dereference
00380                                                 (&binding->value, MDL);
00381                                 if (r->op == set_statement) {
00382                                         status = (evaluate_expression
00383                                                   (&binding->value, packet,
00384                                                    lease, client_state,
00385                                                    in_options, out_options,
00386                                                    scope, r->data.set.expr,
00387                                                    MDL));
00388                                 } else {
00389                                     if (!(binding_value_allocate
00390                                           (&binding->value, MDL))) {
00391                                             dfree(binding, MDL);
00392                                             binding = NULL;
00393                                     }
00394                                     if ((binding != NULL) &&
00395                                         (binding->value != NULL)) {
00396                                             binding->value->type =
00397                                                     binding_function;
00398                                             (fundef_reference
00399                                              (&binding->value->value.fundef,
00400                                               r->data.set.expr->data.func,
00401                                               MDL));
00402                                     }
00403                                 }
00404                         }
00405 #if defined (DEBUG_EXPRESSIONS)
00406                         log_debug ("exec: set %s%s", r -> data.set.name,
00407                                    (binding && status ? "" : " (failed)"));
00408 #else
00409                         POST(status);
00410 #endif
00411                         break;
00412 
00413                       case unset_statement:
00414                         if (!scope || !*scope)
00415                                 break;
00416                         binding = find_binding (*scope, r->data.unset);
00417                         if (binding) {
00418                                 if (binding->value)
00419                                         binding_value_dereference
00420                                                 (&binding->value, MDL);
00421                                 status = 1;
00422                         } else
00423                                 status = 0;
00424 #if defined (DEBUG_EXPRESSIONS)
00425                         log_debug ("exec: unset %s: %s", r->data.unset,
00426                                    (status ? "found" : "not found"));
00427 #else
00428                         POST(status);
00429 #endif
00430                         break;
00431 
00432                       case let_statement:
00433 #if defined (DEBUG_EXPRESSIONS)
00434                         log_debug("exec: let %s", r->data.let.name);
00435 #endif
00436                         status = 0;
00437                         ns = NULL;
00438                         binding_scope_allocate (&ns, MDL);
00439                         e = r;
00440 
00441                       next_let:
00442                         if (ns) {
00443                                 binding = dmalloc(sizeof(*binding), MDL);
00444                                 memset(binding, 0, sizeof(*binding));
00445                                 if (!binding) {
00446                                    blb:
00447                                     binding_scope_dereference(&ns, MDL);
00448                                 } else {
00449                                     binding->name =
00450                                             dmalloc(strlen
00451                                                     (e->data.let.name + 1),
00452                                                     MDL);
00453                                     if (binding->name)
00454                                         strcpy(binding->name,
00455                                                e->data.let.name);
00456                                     else {
00457                                         dfree(binding, MDL);
00458                                         binding = NULL;
00459                                         goto blb;
00460                                     }
00461                                 }
00462                         } else
00463                                 binding = NULL;
00464 
00465                         if (ns && binding) {
00466                                 status = (evaluate_expression
00467                                           (&binding->value, packet, lease,
00468                                            client_state,
00469                                            in_options, out_options,
00470                                            scope, e->data.set.expr, MDL));
00471                                 binding->next = ns->bindings;
00472                                 ns->bindings = binding;
00473                         }
00474 
00475 #if defined (DEBUG_EXPRESSIONS)
00476                         log_debug("exec: let %s%s", e->data.let.name,
00477                                   (binding && status ? "" : "failed"));
00478 #else
00479                         POST(status);
00480 #endif
00481                         if (!e->data.let.statements) {
00482                         } else if (e->data.let.statements->op ==
00483                                    let_statement) {
00484                                 e = e->data.let.statements;
00485                                 goto next_let;
00486                         } else if (ns) {
00487                                 if (scope && *scope)
00488                                         binding_scope_reference(&ns->outer,
00489                                                                 *scope, MDL);
00490                                 execute_statements
00491                                       (result, packet, lease, client_state,
00492                                        in_options, out_options,
00493                                        &ns, e->data.let.statements, on_star);
00494                         }
00495                         if (ns)
00496                                 binding_scope_dereference(&ns, MDL);
00497                         break;
00498 
00499                       case log_statement:
00500                         memset (&ds, 0, sizeof ds);
00501                         status = (evaluate_data_expression
00502                                   (&ds, packet,
00503                                    lease, client_state, in_options,
00504                                    out_options, scope, r->data.log.expr, MDL));
00505                         
00506 #if defined (DEBUG_EXPRESSIONS)
00507                         log_debug ("exec: log");
00508 #endif
00509 
00510                         if (status) {
00511                                 switch (r->data.log.priority) {
00512                                 case log_priority_fatal:
00513                                         log_fatal ("%.*s", (int)ds.len,
00514                                                 ds.data);
00515                                         break;
00516                                 case log_priority_error:
00517                                         log_error ("%.*s", (int)ds.len,
00518                                                 ds.data);
00519                                         break;
00520                                 case log_priority_debug:
00521                                         log_debug ("%.*s", (int)ds.len,
00522                                                 ds.data);
00523                                         break;
00524                                 case log_priority_info:
00525                                         log_info ("%.*s", (int)ds.len,
00526                                                 ds.data);
00527                                         break;
00528                                 }
00529                                 data_string_forget (&ds, MDL);
00530                         }
00531 
00532                         break;
00533 
00534                       default:
00535                         log_error ("bogus statement type %d", r -> op);
00536                         break;
00537                 }
00538                 executable_statement_dereference (&r, MDL);
00539                 if (next) {
00540                         executable_statement_reference (&r, next, MDL);
00541                         executable_statement_dereference (&next, MDL);
00542                 }
00543         }
00544 
00545         return 1;
00546 }
00547 
00548 /* Execute all the statements in a particular scope, and all statements in
00549    scopes outer from that scope, but if a particular limiting scope is
00550    reached, do not execute statements in that scope or in scopes outer
00551    from it.   More specific scopes need to take precedence over less
00552    specific scopes, so we recursively traverse the scope list, executing
00553    the most outer scope first. */
00554 
00555 void execute_statements_in_scope (result, packet,
00556                                   lease, client_state, in_options, out_options,
00557                                   scope, group, limiting_group, on_star)
00558         struct binding_value **result;
00559         struct packet *packet;
00560         struct lease *lease;
00561         struct client_state *client_state;
00562         struct option_state *in_options;
00563         struct option_state *out_options;
00564         struct binding_scope **scope;
00565         struct group *group;
00566         struct group *limiting_group;
00567         struct on_star *on_star;
00568 {
00569         struct group *limit;
00570 
00571         /* If we've recursed as far as we can, return. */
00572         if (!group)
00573                 return;
00574 
00575         /* As soon as we get to a scope that is outer than the limiting
00576            scope, we are done.   This is so that if somebody does something
00577            like this, it does the expected thing:
00578 
00579                 domain-name "fugue.com";
00580                 shared-network FOO {
00581                         host bar {
00582                                 domain-name "othello.fugue.com";
00583                                 fixed-address 10.20.30.40;
00584                         }
00585                         subnet 10.20.30.0 netmask 255.255.255.0 {
00586                                 domain-name "manhattan.fugue.com";
00587                         }
00588                 }
00589 
00590            The problem with the above arrangement is that the host's
00591            group nesting will be host -> shared-network -> top-level,
00592            and the limiting scope when we evaluate the host's scope
00593            will be the subnet -> shared-network -> top-level, so we need
00594            to know when we evaluate the host's scope to stop before we
00595            evaluate the shared-networks scope, because it's outer than
00596            the limiting scope, which means we've already evaluated it. */
00597 
00598         for (limit = limiting_group; limit; limit = limit -> next) {
00599                 if (group == limit)
00600                         return;
00601         }
00602 
00603         if (group -> next)
00604                 execute_statements_in_scope (result, packet,
00605                                              lease, client_state,
00606                                              in_options, out_options, scope,
00607                                              group->next, limiting_group,
00608                                              on_star);
00609         execute_statements (result, packet, lease, client_state, in_options,
00610                             out_options, scope, group->statements, on_star);
00611 }
00612 
00613 /* Dereference or free any subexpressions of a statement being freed. */
00614 
00615 int executable_statement_dereference (ptr, file, line)
00616         struct executable_statement **ptr;
00617         const char *file;
00618         int line;
00619 {
00620         if (!ptr || !*ptr) {
00621                 log_error ("%s(%d): null pointer", file, line);
00622 #if defined (POINTER_DEBUG)
00623                 abort ();
00624 #else
00625                 return 0;
00626 #endif
00627         }
00628 
00629         (*ptr) -> refcnt--;
00630         rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
00631         if ((*ptr) -> refcnt > 0) {
00632                 *ptr = (struct executable_statement *)0;
00633                 return 1;
00634         }
00635 
00636         if ((*ptr) -> refcnt < 0) {
00637                 log_error ("%s(%d): negative refcnt!", file, line);
00638 #if defined (DEBUG_RC_HISTORY)
00639                 dump_rc_history (*ptr);
00640 #endif
00641 #if defined (POINTER_DEBUG)
00642                 abort ();
00643 #else
00644                 return 0;
00645 #endif
00646         }
00647 
00648         if ((*ptr) -> next)
00649                 executable_statement_dereference (&(*ptr) -> next, file, line);
00650 
00651         switch ((*ptr) -> op) {
00652               case statements_statement:
00653                 if ((*ptr) -> data.statements)
00654                         executable_statement_dereference
00655                                 (&(*ptr) -> data.statements, file, line);
00656                 break;
00657 
00658               case on_statement:
00659                 if ((*ptr) -> data.on.statements)
00660                         executable_statement_dereference
00661                                 (&(*ptr) -> data.on.statements, file, line);
00662                 break;
00663 
00664               case switch_statement:
00665                 if ((*ptr) -> data.s_switch.statements)
00666                         executable_statement_dereference
00667                                 (&(*ptr) -> data.on.statements, file, line);
00668                 if ((*ptr) -> data.s_switch.expr)
00669                         expression_dereference (&(*ptr) -> data.s_switch.expr,
00670                                                 file, line);
00671                 break;
00672 
00673               case case_statement:
00674                 if ((*ptr) -> data.s_switch.expr)
00675                         expression_dereference (&(*ptr) -> data.c_case,
00676                                                 file, line);
00677                 break;
00678 
00679               case if_statement:
00680                 if ((*ptr) -> data.ie.expr)
00681                         expression_dereference (&(*ptr) -> data.ie.expr,
00682                                                 file, line);
00683                 if ((*ptr) -> data.ie.tc)
00684                         executable_statement_dereference
00685                                 (&(*ptr) -> data.ie.tc, file, line);
00686                 if ((*ptr) -> data.ie.fc)
00687                         executable_statement_dereference
00688                                 (&(*ptr) -> data.ie.fc, file, line);
00689                 break;
00690 
00691               case eval_statement:
00692                 if ((*ptr) -> data.eval)
00693                         expression_dereference (&(*ptr) -> data.eval,
00694                                                 file, line);
00695                 break;
00696 
00697               case return_statement:
00698                 if ((*ptr) -> data.eval)
00699                         expression_dereference (&(*ptr) -> data.eval,
00700                                                 file, line);
00701                 break;
00702 
00703               case set_statement:
00704                 if ((*ptr)->data.set.name)
00705                         dfree ((*ptr)->data.set.name, file, line);
00706                 if ((*ptr)->data.set.expr)
00707                         expression_dereference (&(*ptr) -> data.set.expr,
00708                                                 file, line);
00709                 break;
00710 
00711               case unset_statement:
00712                 if ((*ptr)->data.unset)
00713                         dfree ((*ptr)->data.unset, file, line);
00714                 break;
00715 
00716               case execute_statement:
00717                 if ((*ptr)->data.execute.command)
00718                         dfree ((*ptr)->data.execute.command, file, line);
00719                 if ((*ptr)->data.execute.arglist)
00720                         expression_dereference (&(*ptr) -> data.execute.arglist,
00721                                                 file, line);
00722                 break;
00723 
00724               case supersede_option_statement:
00725               case send_option_statement:
00726               case default_option_statement:
00727               case append_option_statement:
00728               case prepend_option_statement:
00729                 if ((*ptr) -> data.option)
00730                         option_cache_dereference (&(*ptr) -> data.option,
00731                                                   file, line);
00732                 break;
00733 
00734               default:
00735                 /* Nothing to do. */
00736                 break;
00737         }
00738 
00739         dfree ((*ptr), file, line);
00740         *ptr = (struct executable_statement *)0;
00741         return 1;
00742 }
00743 
00744 void write_statements (file, statements, indent)
00745         FILE *file;
00746         struct executable_statement *statements;
00747         int indent;
00748 {
00749 #if defined ENABLE_EXECUTE
00750         struct expression *expr;
00751 #endif
00752         struct executable_statement *r, *x;
00753         const char *s, *t, *dot;
00754         int col;
00755 
00756         if (!statements)
00757                 return;
00758 
00759         for (r = statements; r; r = r -> next) {
00760                 switch (r -> op) {
00761                       case statements_statement:
00762                         write_statements (file, r -> data.statements, indent);
00763                         break;
00764 
00765                       case on_statement:
00766                         indent_spaces (file, indent);
00767                         fprintf (file, "on ");
00768                         s = "";
00769                         if (r -> data.on.evtypes & ON_EXPIRY) {
00770                                 fprintf (file, "%sexpiry", s);
00771                                 s = " or ";
00772                         }
00773                         if (r -> data.on.evtypes & ON_COMMIT) {
00774                                 fprintf (file, "%scommit", s);
00775                                 s = " or ";
00776                         }
00777                         if (r -> data.on.evtypes & ON_RELEASE) {
00778                                 fprintf (file, "%srelease", s);
00779                                 /* s = " or "; */
00780                         }
00781                         if (r -> data.on.statements) {
00782                                 fprintf (file, " {");
00783                                 write_statements (file,
00784                                                   r -> data.on.statements,
00785                                                   indent + 2);
00786                                 indent_spaces (file, indent);
00787                                 fprintf (file, "}");
00788                         } else {
00789                                 fprintf (file, ";");
00790                         }
00791                         break;
00792 
00793                       case switch_statement:
00794                         indent_spaces (file, indent);
00795                         fprintf (file, "switch (");
00796                         col = write_expression (file,
00797                                                 r -> data.s_switch.expr,
00798                                                 indent + 7, indent + 7, 1);
00799                         col = token_print_indent (file, col, indent + 7,
00800                                                   "", "", ")");
00801                         token_print_indent (file,
00802                                             col, indent, " ", "", "{");
00803                         write_statements (file, r -> data.s_switch.statements,
00804                                           indent + 2);
00805                         indent_spaces (file, indent);
00806                         fprintf (file, "}");
00807                         break;
00808 
00809                       case case_statement:
00810                         indent_spaces (file, indent - 1);
00811                         fprintf (file, "case ");
00812                         col = write_expression (file,
00813                                                 r -> data.s_switch.expr,
00814                                                 indent + 5, indent + 5, 1);
00815                         token_print_indent (file, col, indent + 5,
00816                                             "", "", ":");
00817                         break;
00818 
00819                       case default_statement:
00820                         indent_spaces (file, indent - 1);
00821                         fprintf (file, "default: ");
00822                         break;
00823 
00824                       case if_statement:
00825                         indent_spaces (file, indent);
00826                         fprintf (file, "if ");
00827                         x = r;
00828                         col = write_expression (file,
00829                                                 x -> data.ie.expr,
00830                                                 indent + 3, indent + 3, 1);
00831                       else_if:
00832                         token_print_indent (file, col, indent, " ", "", "{");
00833                         write_statements (file, x -> data.ie.tc, indent + 2);
00834                         if (x -> data.ie.fc &&
00835                             x -> data.ie.fc -> op == if_statement &&
00836                             !x -> data.ie.fc -> next) {
00837                                 indent_spaces (file, indent);
00838                                 fprintf (file, "} elsif ");
00839                                 x = x -> data.ie.fc;
00840                                 col = write_expression (file,
00841                                                         x -> data.ie.expr,
00842                                                         indent + 6,
00843                                                         indent + 6, 1);
00844                                 goto else_if;
00845                         }
00846                         if (x -> data.ie.fc) {
00847                                 indent_spaces (file, indent);
00848                                 fprintf (file, "} else {");
00849                                 write_statements (file, x -> data.ie.fc,
00850                                                   indent + 2);
00851                         }
00852                         indent_spaces (file, indent);
00853                         fprintf (file, "}");
00854                         break;
00855 
00856                       case eval_statement:
00857                         indent_spaces (file, indent);
00858                         fprintf (file, "eval ");
00859                         (void) write_expression (file, r -> data.eval,
00860                                                 indent + 5, indent + 5, 1);
00861                         fprintf (file, ";");
00862                         break;
00863 
00864                       case return_statement:
00865                         indent_spaces (file, indent);
00866                         fprintf (file, "return;");
00867                         break;
00868 
00869                       case add_statement:
00870                         indent_spaces (file, indent);
00871                         fprintf (file, "add \"%s\"", r -> data.add -> name);
00872                         break;
00873 
00874                       case break_statement:
00875                         indent_spaces (file, indent);
00876                         fprintf (file, "break;");
00877                         break;
00878 
00879                       case supersede_option_statement:
00880                       case send_option_statement:
00881                         s = "supersede";
00882                         goto option_statement;
00883 
00884                       case default_option_statement:
00885                         s = "default";
00886                         goto option_statement;
00887 
00888                       case append_option_statement:
00889                         s = "append";
00890                         goto option_statement;
00891 
00892                       case prepend_option_statement:
00893                         s = "prepend";
00894                       option_statement:
00895                         /* Note: the reason we don't try to pretty print
00896                            the option here is that the format of the option
00897                            may change in dhcpd.conf, and then when this
00898                            statement was read back, it would cause a syntax
00899                            error. */
00900                         if (r -> data.option -> option -> universe ==
00901                             &dhcp_universe) {
00902                                 t = "";
00903                                 dot = "";
00904                         } else {
00905                                 t = (r -> data.option -> option ->
00906                                      universe -> name);
00907                                 dot = ".";
00908                         }
00909                         indent_spaces (file, indent);
00910                         fprintf (file, "%s %s%s%s = ", s, t, dot,
00911                                  r -> data.option -> option -> name);
00912                         col = (indent + strlen (s) + strlen (t) +
00913                                strlen (dot) + strlen (r -> data.option ->
00914                                                       option -> name) + 4);
00915                         if (r -> data.option -> expression)
00916                                 write_expression
00917                                         (file,
00918                                          r -> data.option -> expression,
00919                                          col, indent + 8, 1);
00920                         else
00921                                 token_indent_data_string
00922                                         (file, col, indent + 8, "", "",
00923                                          &r -> data.option -> data);
00924                                          
00925                         fprintf (file, ";"); /* XXX */
00926                         break;
00927 
00928                       case set_statement:
00929                         indent_spaces (file, indent);
00930                         fprintf (file, "set ");
00931                         col = token_print_indent (file, indent + 4, indent + 4,
00932                                                   "", "", r -> data.set.name);
00933                         (void) token_print_indent (file, col, indent + 4,
00934                                                   " ", " ", "=");
00935                         col = write_expression (file, r -> data.set.expr,
00936                                                 indent + 3, indent + 3, 0);
00937                         (void) token_print_indent (file, col, indent + 4,
00938                                                   " ", "", ";");
00939                         break;
00940                         
00941                       case unset_statement:
00942                         indent_spaces (file, indent);
00943                         fprintf (file, "unset ");
00944                         col = token_print_indent (file, indent + 6, indent + 6,
00945                                                   "", "", r -> data.set.name);
00946                         (void) token_print_indent (file, col, indent + 6,
00947                                                   " ", "", ";");
00948                         break;
00949 
00950                       case log_statement:
00951                         indent_spaces (file, indent);
00952                         fprintf (file, "log ");
00953                         col = token_print_indent (file, indent + 4, indent + 4,
00954                                                   "", "", "(");
00955                         switch (r -> data.log.priority) {
00956                         case log_priority_fatal:
00957                                 (void) token_print_indent
00958                                         (file, col, indent + 4, "",
00959                                          " ", "fatal,");
00960                                 break;
00961                         case log_priority_error:
00962                                 (void) token_print_indent
00963                                         (file, col, indent + 4, "",
00964                                          " ", "error,");
00965                                 break;
00966                         case log_priority_debug:
00967                                 (void) token_print_indent
00968                                         (file, col, indent + 4, "",
00969                                          " ", "debug,");
00970                                 break;
00971                         case log_priority_info:
00972                                 (void) token_print_indent
00973                                         (file, col, indent + 4, "",
00974                                          " ", "info,");
00975                                 break;
00976                         }
00977                         col = write_expression (file, r -> data.log.expr,
00978                                                 indent + 4, indent + 4, 0);
00979                         (void) token_print_indent (file, col, indent + 4,
00980                                                   "", "", ");");
00981 
00982                         break;
00983 
00984                       case execute_statement:
00985 #ifdef ENABLE_EXECUTE
00986                         indent_spaces (file, indent);
00987                         col = token_print_indent(file, indent + 4, indent + 4,
00988                                                  "", "", "execute");
00989                         col = token_print_indent(file, col, indent + 4, " ", "",
00990                                                  "(");
00991                         col = token_print_indent(file, col, indent + 4, "\"", "\"", r->data.execute.command);
00992                         for (expr = r->data.execute.arglist; expr; expr = expr->data.arg.next) {
00993                                 col = token_print_indent(file, col, indent + 4, "", " ", ",");
00994                                 col = write_expression (file, expr->data.arg.val, col, indent + 4, 0);
00995                         }
00996                         (void) token_print_indent(file, col, indent + 4, "", "", ");");
00997 #else /* !ENABLE_EXECUTE */
00998                         log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE "
00999                                   "is not defined).", MDL);
01000 #endif /* ENABLE_EXECUTE */
01001                         break;
01002                         
01003                       default:
01004                         log_fatal ("bogus statement type %d\n", r -> op);
01005                 }
01006         }
01007 }
01008 
01009 /* Find a case statement in the sequence of executable statements that
01010    matches the expression, and if found, return the following statement.
01011    If no case statement matches, try to find a default statement and
01012    return that (the default statement can precede all the case statements).
01013    Otherwise, return the null statement. */
01014 
01015 int find_matching_case (struct executable_statement **ep,
01016                         struct packet *packet, struct lease *lease,
01017                         struct client_state *client_state,
01018                         struct option_state *in_options,
01019                         struct option_state *out_options,
01020                         struct binding_scope **scope,
01021                         struct expression *expr,
01022                         struct executable_statement *stmt)
01023 {
01024         int status, sub;
01025         struct executable_statement *s;
01026 
01027         if (is_data_expression (expr)) {
01028                 struct data_string cd, ds;
01029                 memset (&ds, 0, sizeof ds);
01030                 memset (&cd, 0, sizeof cd);
01031 
01032                 status = (evaluate_data_expression (&ds, packet, lease,
01033                                                     client_state, in_options,
01034                                                     out_options, scope, expr,
01035                                                     MDL));
01036                 if (status) {
01037                     for (s = stmt; s; s = s -> next) {
01038                         if (s -> op == case_statement) {
01039                                 sub = (evaluate_data_expression
01040                                        (&cd, packet, lease, client_state,
01041                                         in_options, out_options,
01042                                         scope, s->data.c_case, MDL));
01043                                 if (sub && cd.len == ds.len &&
01044                                     !memcmp (cd.data, ds.data, cd.len))
01045                                 {
01046                                         data_string_forget (&cd, MDL);
01047                                         data_string_forget (&ds, MDL);
01048                                         executable_statement_reference
01049                                                 (ep, s->next, MDL);
01050                                         return 1;
01051                                 }
01052                                 data_string_forget (&cd, MDL);
01053                         }
01054                     }
01055                     data_string_forget (&ds, MDL);
01056                 }
01057         } else {
01058                 unsigned long n, c;
01059                 status = evaluate_numeric_expression (&n, packet, lease,
01060                                                       client_state,
01061                                                       in_options, out_options,
01062                                                       scope, expr);
01063 
01064                 if (status) {
01065                     for (s = stmt; s; s = s->next) {
01066                         if (s -> op == case_statement) {
01067                                 sub = (evaluate_numeric_expression
01068                                        (&c, packet, lease, client_state,
01069                                         in_options, out_options,
01070                                         scope, s->data.c_case));
01071                                 if (sub && n == c) {
01072                                         executable_statement_reference
01073                                                 (ep, s->next, MDL);
01074                                         return 1;
01075                                 }
01076                         }
01077                     }
01078                 }
01079         }
01080 
01081         /* If we didn't find a matching case statement, look for a default
01082            statement and return the statement following it. */
01083         for (s = stmt; s; s = s->next)
01084                 if (s->op == default_statement)
01085                         break;
01086         if (s) {
01087                 executable_statement_reference (ep, s->next, MDL);
01088                 return 1;
01089         }
01090         return 0;
01091 }
01092 
01093 int executable_statement_foreach (struct executable_statement *stmt,
01094                                   int (*callback) (struct
01095                                                    executable_statement *,
01096                                                    void *, int),
01097                                   void *vp, int condp)
01098 {
01099         struct executable_statement *foo;
01100         int ok = 0;
01101 
01102         for (foo = stmt; foo; foo = foo->next) {
01103             if ((*callback) (foo, vp, condp) != 0)
01104                 ok = 1;
01105             switch (foo->op) {
01106               case null_statement:
01107                 break;
01108               case if_statement:
01109                 if (executable_statement_foreach (foo->data.ie.tc,
01110                                                   callback, vp, 1))
01111                         ok = 1;
01112                 if (executable_statement_foreach (foo->data.ie.fc,
01113                                                   callback, vp, 1))
01114                         ok = 1;
01115                 break;
01116               case add_statement:
01117                 break;
01118               case eval_statement:
01119                 break;
01120               case break_statement:
01121                 break;
01122               case default_option_statement:
01123                 break;
01124               case supersede_option_statement:
01125                 break;
01126               case append_option_statement:
01127                 break;
01128               case prepend_option_statement:
01129                 break;
01130               case send_option_statement:
01131                 break;
01132               case statements_statement:
01133                 if ((executable_statement_foreach
01134                      (foo->data.statements, callback, vp, condp)))
01135                         ok = 1;
01136                 break;
01137               case on_statement:
01138                 if ((executable_statement_foreach
01139                      (foo->data.on.statements, callback, vp, 1)))
01140                         ok = 1;
01141                 break;
01142               case switch_statement:
01143                 if ((executable_statement_foreach
01144                      (foo->data.s_switch.statements, callback, vp, 1)))
01145                         ok = 1;
01146                 break;
01147               case case_statement:
01148                 break;
01149               case default_statement:
01150                 break;
01151               case set_statement:
01152                 break;
01153               case unset_statement:
01154                 break;
01155               case let_statement:
01156                 if ((executable_statement_foreach
01157                      (foo->data.let.statements, callback, vp, 0)))
01158                         ok = 1;
01159                 break;
01160               case define_statement:
01161                 break;
01162               case log_statement:
01163               case return_statement:
01164               case execute_statement:
01165                 break;
01166             }
01167         }
01168         return ok;
01169 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1