]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Support variable scoping, let, unset, event ganging, eval, new malloc debug.
authorTed Lemon <source@isc.org>
Tue, 25 Jan 2000 01:07:00 +0000 (01:07 +0000)
committerTed Lemon <source@isc.org>
Tue, 25 Jan 2000 01:07:00 +0000 (01:07 +0000)
common/execute.c

index 9afe1a7c60faffaec7fcca68081142b5859dbd58..cb35bf8c4ce5a5275f2136d69f8fcc7eeb2c227f 100644 (file)
 
 #ifndef lint
 static char copyright[] =
-"$Id: execute.c,v 1.22 2000/01/08 01:30:29 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: execute.c,v 1.23 2000/01/25 01:07:00 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
 
-int execute_statements (packet, lease, in_options, out_options, statements)
+int execute_statements (packet, lease, in_options, out_options, scope,
+                       statements)
        struct packet *packet;
        struct lease *lease;
        struct option_state *in_options;
        struct option_state *out_options;
+       struct binding_scope *scope;
        struct executable_statement *statements;
 {
        struct executable_statement *r, *e;
        int result;
        int status;
+       unsigned long num;
+       struct binding_scope *outer;
        struct binding *binding;
        struct data_string ds;
+       struct binding_scope *ns;
 
        if (!statements)
                return 1;
@@ -49,8 +54,8 @@ int execute_statements (packet, lease, in_options, out_options, statements)
 #if defined (DEBUG_EXPRESSIONS)
                        log_debug ("exec: statements");
 #endif
-                       status = execute_statements (packet, lease,
-                                                    in_options, out_options,
+                       status = execute_statements (packet, lease, in_options,
+                                                    out_options, scope,
                                                     r -> data.statements);
 #if defined (DEBUG_EXPRESSIONS)
                        log_debug ("exec: statements returns %d", status);
@@ -66,42 +71,45 @@ int execute_statements (packet, lease, in_options, out_options, statements)
                                        executable_statement_dereference
                                                (&lease -> on_expiry,
                                                 "execute_statements");
-                               executable_statement_reference
-                                       (&lease -> on_expiry,
-                                        r -> data.on.statements,
-                                        "execute_statements");
+                               if (r -> data.on.statements)
+                                       executable_statement_reference
+                                               (&lease -> on_expiry,
+                                                r -> data.on.statements,
+                                                "execute_statements");
                            }
                            if (r -> data.on.evtypes & ON_RELEASE) {
                                if (lease -> on_release)
                                        executable_statement_dereference
                                                (&lease -> on_release,
                                                 "execute_statements");
-                               executable_statement_reference
-                                       (&lease -> on_release,
-                                        r -> data.on.statements,
-                                        "execute_statements");
+                               if (r -> data.on.statements)
+                                       executable_statement_reference
+                                               (&lease -> on_release,
+                                                r -> data.on.statements,
+                                                "execute_statements");
                            }
                            if (r -> data.on.evtypes & ON_COMMIT) {
                                if (lease -> on_commit)
                                        executable_statement_dereference
                                                (&lease -> on_commit,
                                                 "execute_statements");
-                               executable_statement_reference
-                                       (&lease -> on_commit,
-                                        r -> data.on.statements,
-                                        "execute_statements");
+                               if (r -> data.on.statements)
+                                       executable_statement_reference
+                                               (&lease -> on_commit,
+                                                r -> data.on.statements,
+                                                "execute_statements");
                            }
                        }
                        break;
 
                      case switch_statement:
                        e = find_matching_case (packet, lease,
-                                               in_options, out_options,
+                                               in_options, out_options, scope,
                                                r -> data.s_switch.expr,
                                                r -> data.s_switch.statements);
                        if (e && !execute_statements (packet, lease,
                                                      in_options, out_options,
-                                                     e))
+                                                     scope, e))
                                return 0;
 
                        /* These have no effect when executed. */
@@ -111,8 +119,8 @@ int execute_statements (packet, lease, in_options, out_options, statements)
 
                      case if_statement:
                        status = evaluate_boolean_expression
-                               (&result, packet, lease,
-                                in_options, out_options, r -> data.ie.expr);
+                               (&result, packet, lease, in_options,
+                                out_options, scope, r -> data.ie.expr);
                        
 #if defined (DEBUG_EXPRESSIONS)
                        log_debug ("exec: if %s", (status
@@ -123,19 +131,60 @@ int execute_statements (packet, lease, in_options, out_options, statements)
                        if (!status)
                                result = 0;
                        if (!execute_statements
-                           (packet, lease, in_options, out_options,
+                           (packet, lease, in_options, out_options, scope,
                             result ? r -> data.ie.true : r -> data.ie.false))
                                return 0;
                        break;
 
                      case eval_statement:
-                       status = evaluate_boolean_expression
-                               (&result, packet, lease,
-                                in_options, out_options, r -> data.eval);
+                       if (is_boolean_expression (r -> data.eval)) {
+                               status = (evaluate_boolean_expression
+                                         (&result, packet, lease, in_options,
+                                          out_options, scope,
+                                          r -> data.eval));
+                       } else if (is_numeric_expression (r -> data.eval)) {
+                               status = (evaluate_numeric_expression
+                                         (&num, packet, lease, in_options,
+                                          out_options, scope,
+                                          r -> data.eval));
+                       } else if (is_data_expression  (r -> data.eval)) {
+                               memset (&ds, 0, sizeof ds);
+                               status = (evaluate_data_expression
+                                         (&ds, packet, lease, in_options,
+                                          out_options, scope,
+                                          r -> data.eval));
+                               if (status && ds.data)
+                                       data_string_forget
+                                               (&ds, "execute_statements");
+                       } else if (is_dns_expression (r -> data.eval)) {
+                               ns_updrec *nut;
+                               nut = 0;
+                               status = (evaluate_dns_expression
+                                         (&nut, packet, lease, in_options,
+                                          out_options, scope,
+                                          r -> data.eval));
+                               if (status) {
+                                       if (nut -> r_data) {
+                                               dfree (nut -> r_data,
+                                                      "execute_statements");
+                                               nut -> r_data = (char *)0;
+                                       }
+                                       if (nut -> r_dname) {
+                                               dfree (nut -> r_dname,
+                                                      "execute_statements");
+                                               nut -> r_dname = (char *)0;
+                                       }
+                                       res_freeupdrec (nut);
+                               }
+                       } else {
+                               log_error ("%s: invalid expression type: %d",
+                                          "execute_statements",
+                                          r -> data.eval -> op);
+                       }
+
 #if defined (DEBUG_EXPRESSIONS)
                        log_debug ("exec: evaluate: %s",
-                             (status
-                              ? (result ? "true" : "false") : "NULL"));
+                                  (status "succeeded" : "failed"));
 #endif
                        break;
 
@@ -191,26 +240,12 @@ int execute_statements (packet, lease, in_options, out_options, statements)
                        break;
 
                      case set_statement:
-                       if (!lease) {
-#if defined (DEBUG_EXPRESSIONS)
-                               log_debug ("exec: set %s = NULL",
-                                          r -> data.set.name);
-#endif
-                               break;
-                       }
-
                        memset (&ds, 0, sizeof ds);
                        status = (evaluate_data_expression
                                  (&ds, packet, lease, in_options, out_options,
-                                  r -> data.set.expr));
-
-                       for (binding = lease -> bindings;
-                            binding; binding = binding -> next) {
-                               if (!(strcasecmp
-                                     (lease -> bindings -> name,
-                                      r -> data.set.name)))
-                                       break;
-                       }
+                                  scope, r -> data.set.expr));
+
+                       binding = find_binding (scope, r -> data.set.name);
                        if (!binding && status) {
                                binding = dmalloc (sizeof *binding,
                                                   "execute_statements");
@@ -219,36 +254,124 @@ int execute_statements (packet, lease, in_options, out_options, statements)
                                            dmalloc (strlen
                                                     (r -> data.set.name + 1),
                                                     "execute_statements");
-                                   if (binding -> name)
+                                   if (binding -> name) {
                                        strcpy (binding -> name,
                                                r -> data.set.name);
-                                   else
-                                       dfree (binding,
-                                              "execute_statements");
-                                   binding -> next = lease -> bindings;
-                                   lease -> bindings = binding;
-                               } else
-                                   status = 0;
+                                       if (lease) {
+                                           binding -> next =
+                                                   lease -> scope.bindings;
+                                           lease -> scope.bindings = binding;
+                                       } else {
+                                           binding -> next =
+                                                   global_scope.bindings;
+                                           global_scope.bindings = binding;
+                                       }
+                                   } else {
+                                      badalloc:
+                                       dfree (binding, "execute_statements");
+                                       binding = (struct binding *)0;
+                                   }
+                               }
                        }
                        if (binding) {
-                               data_string_forget (&binding -> value,
-                                                   "execute_statements");
+                               if (binding -> value.data)
+                                   data_string_forget (&binding -> value,
+                                                       "execute_statements");
                                if (status)
-                                       data_string_copy
-                                               (&binding -> value, &ds,
-                                                "execute_statements");
+                                   data_string_copy (&binding -> value, &ds,
+                                                     "execute_statements");
                        }
                        if (status)
                            data_string_forget (&ds, "execute_statements");
 #if defined (DEBUG_EXPRESSIONS)
                        log_debug ("exec: set %s = %s", r -> data.set.name,
-                                  (status
+                                  (status && binding
                                    ? print_hex_1 (binding -> value.len,
                                                   binding -> value.data, 50)
                                    : "NULL"));
 #endif
                        break;
 
+                     case unset_statement:
+                       binding = find_binding (scope, r -> data.unset);
+                       if (binding) {
+                               if (binding -> value.data)
+                                       data_string_forget
+                                               (&binding -> value,
+                                                "execute_statements");
+                               status = 1;
+                       } else
+                               status = 0;
+#if defined (DEBUG_EXPRESSIONS)
+                       log_debug ("exec: unset %s: %s", r -> data.unset,
+                                  (status ? "found" : "NULL"));
+#endif
+                       break;
+
+                     case let_statement:
+                       memset (&ds, 0, sizeof ds);
+                       status = (evaluate_data_expression
+                                 (&ds, packet, lease, in_options, out_options,
+                                  scope, r -> data.let.expr));
+
+                       ns = (struct binding_scope *)0;
+                       binding_scope_allocate (&ns, "execute_statements");
+
+                     next_let:
+                       if (ns) {
+                               binding = dmalloc (sizeof *binding,
+                                                  "execute_statements");
+                               if (!binding) {
+                                  blb:
+                                   binding_scope_dereference
+                                               (&ns, "execute_statements");
+                               } else {
+                                   binding -> name =
+                                           dmalloc (strlen
+                                                    (r -> data.let.name + 1),
+                                                    "execute_statements");
+                                   if (binding -> name)
+                                       strcpy (binding -> name,
+                                               r -> data.let.name);
+                                   else {
+                                       dfree (binding, "execute_statements");
+                                       binding = (struct binding *)0;
+                                       goto blb;
+                                   }
+                               }
+                       }
+                       if (ns && binding && status) {
+                               data_string_copy (&binding -> value, &ds,
+                                                 "execute_statements");
+                               binding -> next = ns -> bindings;
+                               ns -> bindings = binding;
+                       }
+
+                       if (status)
+                           data_string_forget (&ds, "execute_statements");
+#if defined (DEBUG_EXPRESSIONS)
+                       log_debug ("exec: let %s = %s", r -> data.let.name,
+                                  (status && binding
+                                   ? print_hex_1 (binding -> value.len,
+                                                  binding -> value.data, 50)
+                                   : "NULL"));
+#endif
+                       if (!r -> data.let.statements) {
+                       } else if (r -> data.let.statements -> op ==
+                                  let_statement) {
+                               r = r -> data.let.statements;
+                               goto next_let;
+                       } else if (ns) {
+                               ns -> outer = scope;
+                               execute_statements
+                                     (packet, lease, in_options, out_options,
+                                      ns, r -> data.let.statements);
+                       }
+                       if (ns)
+                               binding_scope_dereference
+                                       (&ns, "execute_statements");
+                       break;
+
                      default:
                        log_fatal ("bogus statement type %d\n", r -> op);
                }
@@ -265,15 +388,15 @@ int execute_statements (packet, lease, in_options, out_options, statements)
    the most outer scope first. */
 
 void execute_statements_in_scope (packet, lease, in_options, out_options,
-                                 group, limiting_group)
+                                 scope, group, limiting_group)
        struct packet *packet;
        struct lease *lease;
        struct option_state *in_options;
        struct option_state *out_options;
+       struct binding_scope *scope;
        struct group *group;
        struct group *limiting_group;
 {
-       struct group *scope;
        struct group *limit;
 
        /* If we've recursed as far as we can, return. */
@@ -310,10 +433,10 @@ void execute_statements_in_scope (packet, lease, in_options, out_options,
 
        if (group -> next)
                execute_statements_in_scope (packet, lease,
-                                            in_options, out_options,
+                                            in_options, out_options, scope,
                                             group -> next, limiting_group);
-       execute_statements (packet, lease,
-                           in_options, out_options, group -> statements);
+       execute_statements (packet, lease, in_options, out_options, scope,
+                           group -> statements);
 }
 
 /* Dereference or free any subexpressions of a statement being freed. */
@@ -335,11 +458,24 @@ int executable_statement_dereference (ptr, name)
        }
 
        (*ptr) -> refcnt--;
-       if ((*ptr) -> refcnt) {
+       rc_register (file, line, (*ptr), (*ptr) -> refcnt);
+       if ((*ptr) -> refcnt > 0) {
                *ptr = (struct executable_statement *)0;
                return 1;
        }
 
+       if ((*ptr) -> refcnt < 0) {
+               log_error ("option_state_dereference: negative refcnt!");
+#if defined (DEBUG_RC_HISTORY)
+               dump_rc_history ();
+#endif
+#if defined (POINTER_DEBUG)
+               abort ();
+#else
+               return 0;
+#endif
+       }
+
        if ((*ptr) -> next)
                executable_statement_dereference
                        (&(*ptr) -> next, name);
@@ -396,6 +532,11 @@ int executable_statement_dereference (ptr, name)
                                                name);
                break;
 
+             case unset_statement:
+               if ((*ptr)->data.unset)
+                       dfree ((*ptr)->data.unset, name);
+               break;
+
              case supersede_option_statement:
              case default_option_statement:
              case append_option_statement:
@@ -440,21 +581,27 @@ void write_statements (file, statements, indent)
                        fprintf (file, "on ");
                        s = "";
                        if (r -> data.on.evtypes & ON_EXPIRY) {
-                               fprintf (file, "expiry");
-                               s = "or";
+                               fprintf (file, "%sexpiry", s);
+                               s = " or ";
                        }
                        if (r -> data.on.evtypes & ON_COMMIT) {
-                               fprintf (file, "commit");
+                               fprintf (file, "%scommit", s);
                                s = "or";
                        }
                        if (r -> data.on.evtypes & ON_RELEASE) {
-                               fprintf (file, "release");
+                               fprintf (file, "%srelease", s);
                                s = "or";
                        }
-                       write_statements (file, r -> data.on.statements,
-                                         indent + 2);
-                       indent_spaces (file, indent);
-                       fprintf (file, "}");
+                       if (r -> data.on.statements) {
+                               fprintf (file, " {");
+                               write_statements (file,
+                                                 r -> data.on.statements,
+                                                 indent + 2);
+                               indent_spaces (file, indent);
+                               fprintf (file, "}");
+                       } else {
+                               fprintf (file, ";");
+                       }
                        break;
 
                      case switch_statement:
@@ -599,6 +746,15 @@ void write_statements (file, statements, indent)
                                                  " ", "", ";");
                        break;
                        
+                     case unset_statement:
+                       indent_spaces (file, indent);
+                       fprintf (file, "unset ");
+                       col = token_print_indent (file, indent + 6, indent + 6,
+                                                 "", "", r -> data.set.name);
+                       col = token_print_indent (file, col, indent + 6,
+                                                 " ", "", ";");
+                       break;
+                       
                      default:
                        log_fatal ("bogus statement type %d\n", r -> op);
                }
@@ -611,13 +767,14 @@ void write_statements (file, statements, indent)
    return that (the default statement can precede all the case statements).
    Otherwise, return the null statement. */
 
-struct executable_statement *find_matching_case (packet, lease,
-                                                in_options, out_options,
+struct executable_statement *find_matching_case (packet, lease, in_options,
+                                                out_options, scope,
                                                 expr, stmt)
        struct packet *packet;
        struct lease *lease;
        struct option_state *in_options;
        struct option_state *out_options;
+       struct binding_scope *scope;
        struct expression *expr;
        struct executable_statement *stmt;
 {
@@ -631,14 +788,15 @@ struct executable_statement *find_matching_case (packet, lease,
                memset (&ds, 0, sizeof ds);
                memset (&cd, 0, sizeof cd);
 
-               status = (evaluate_data_expression
-                         (&ds, packet, lease, in_options, out_options, expr));
+               status = (evaluate_data_expression (&ds, packet, lease,
+                                                   in_options, out_options,
+                                                   scope, expr));
                if (status) {
                    for (s = stmt; s; s = s -> next) {
                        if (s -> op == case_statement) {
                                sub = (evaluate_data_expression
                                       (&cd, packet, lease, in_options,
-                                       out_options, s -> data.c_case));
+                                       out_options, scope, s -> data.c_case));
                                if (sub && cd.len == ds.len &&
                                    !memcmp (cd.data, ds.data, cd.len))
                                {
@@ -655,15 +813,16 @@ struct executable_statement *find_matching_case (packet, lease,
                }
        } else {
                unsigned long n, c;
-               status = (evaluate_numeric_expression
-                         (&n, packet, lease, in_options, out_options, expr));
+               status = evaluate_numeric_expression (&n, packet, lease,
+                                                     in_options, out_options,
+                                                     scope, expr);
 
                if (status) {
                    for (s = stmt; s; s = s -> next) {
                        if (s -> op == case_statement) {
                                sub = (evaluate_numeric_expression
                                       (&c, packet, lease, in_options,
-                                       out_options, s -> data.c_case));
+                                       out_options, scope, s -> data.c_case));
                                if (sub && n == c)
                                        return s -> next;
                        }