]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Massive rototill to support some new DDNS features.
authorTed Lemon <source@isc.org>
Fri, 16 Jul 1999 21:34:14 +0000 (21:34 +0000)
committerTed Lemon <source@isc.org>
Fri, 16 Jul 1999 21:34:14 +0000 (21:34 +0000)
common/alloc.c
common/conflex.c
common/execute.c
common/parse.c
common/tree.c
includes/dhcpd.h
includes/dhctoken.h
includes/statement.h
includes/tree.h
server/confpars.c

index 84aabc2dbdc58ca08cc248fbc03d8a73ae2e1dfd..3eb73cbb955e2a13f0cf16f1bcb1d2facb4737aa 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: alloc.c,v 1.30 1999/05/27 12:38:05 mellon Exp $ Copyright (c) 1995, 1996, 1998 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: alloc.c,v 1.31 1999/07/16 21:33:57 mellon Exp $ Copyright (c) 1995, 1996, 1998 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -777,3 +777,69 @@ int option_state_dereference (ptr, name)
        dfree (options, name);
        return 1;
 }
+
+int executable_statement_allocate (ptr, name)
+       struct executable_statement **ptr;
+       char *name;
+{
+       struct executable_statement *bp;
+
+       bp = dmalloc (sizeof *bp, name);
+       if (!bp)
+               return 0;
+       memset (bp, 0, sizeof *bp);
+       bp -> refcnt = 0;
+       return executable_statement_reference (ptr, bp, name);
+}
+
+int executable_statement_reference (ptr, bp, name)
+       struct executable_statement **ptr;
+       struct executable_statement *bp;
+       char *name;
+{
+       if (!ptr) {
+               log_error ("Null ptr in executable_statement_reference: %s",
+                          name);
+#if defined (POINTER_DEBUG)
+               abort ();
+#else
+               return 0;
+#endif
+       }
+       if (*ptr) {
+               log_error ("Nonnull ptr in executable_statement_reference: %s",
+                          name);
+#if defined (POINTER_DEBUG)
+               abort ();
+#else
+               *ptr = (struct executable_statement *)0;
+#endif
+       }
+       *ptr = bp;
+       bp -> refcnt++;
+       return 1;
+}
+
+int executable_statement_dereference (ptr, name)
+       struct executable_statement **ptr;
+       char *name;
+{
+       struct executable_statement *bp;
+
+       if (!ptr || !*ptr) {
+               log_error ("Null ptr in executable_statement_dereference: %s",
+                          name);
+#if defined (POINTER_DEBUG)
+               abort ();
+#else
+               return 0;
+#endif
+       }
+
+       (*ptr) -> refcnt--;
+       if (!(*ptr) -> refcnt)
+               dfree ((*ptr), name);
+       *ptr = (struct executable_statement *)0;
+       return 1;
+}
+
index deb099b8c80fea190d5cd72641275968d0db93a6..1d88882a7c3774b53005c54f6064d42e1a585ba7 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: conflex.c,v 1.48 1999/07/06 20:41:22 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: conflex.c,v 1.49 1999/07/16 21:33:58 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -384,8 +384,12 @@ static enum dhcp_token intern (atom, dfv)
                        return BOOLEAN;
                break;
              case 'c':
+               if (!strcasecmp (atom + 1, "ommit"))
+                       return COMMIT;
                if (!strcasecmp (atom + 1, "ode"))
                        return CODE;
+               if (!strcasecmp (atom + 1, "onfig-option"))
+                       return CONFIG_OPTION;
                if (!strcasecmp (atom + 1, "heck"))
                        return CHECK;
                if (!strcasecmp (atom + 1, "lass"))
@@ -436,6 +440,8 @@ static enum dhcp_token intern (atom, dfv)
                }
                break;
              case 'e':
+               if (!strcasecmp (atom + 1, "xpiry"))
+                       return EXPIRY;
                if (isascii (atom [1]) && tolower (atom [1]) == 'x') {
                        if (!strcasecmp (atom + 2, "tract-int"))
                                return EXTRACT_INT;
@@ -477,6 +483,8 @@ static enum dhcp_token intern (atom, dfv)
              case 'h':
                if (!strcasecmp (atom + 1, "ost"))
                        return HOST;
+               if (!strcasecmp (atom + 1, "ost-decl-name"))
+                       return HOST_DECL_NAME;
                if (!strcasecmp (atom + 1, "ardware"))
                        return HARDWARE;
                if (!strcasecmp (atom + 1, "ostname"))
@@ -553,6 +561,8 @@ static enum dhcp_token intern (atom, dfv)
              case 'o':
                if (!strcasecmp (atom + 1, "r"))
                        return OR;
+               if (!strcasecmp (atom + 1, "n"))
+                       return ON;
                if (!strcasecmp (atom + 1, "ption"))
                        return OPTION;
                if (!strcasecmp (atom + 1, "ne-lease-per-client"))
@@ -583,6 +593,8 @@ static enum dhcp_token intern (atom, dfv)
                        return PORT;
                if (!strcasecmp (atom + 1, "otential-conflict"))
                        return POTENTIAL_CONFLICT;
+               if (!strcasecmp (atom + 1, "ick-first-value"))
+                       return PICK_FIRST_VALUE;
                break;
              case 'r':
                if (!strcasecmp (atom + 1, "ange"))
@@ -607,6 +619,8 @@ static enum dhcp_token intern (atom, dfv)
                        return REJECT;
                if (!strcasecmp (atom + 1, "everse"))
                        return REVERSE;
+               if (!strcasecmp (atom + 1, "elease"))
+                       return RELEASE;
                break;
              case 's':
                if (!strcasecmp (atom + 1, "igned"))
index 2c4eb8c4b65cb531c97532bd4754efc3a4aeec32..72e5245df91d55ed03ac8b26d9a0b0319bcfee88 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: execute.c,v 1.10 1999/07/02 20:57:24 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: execute.c,v 1.11 1999/07/16 21:33:58 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -43,6 +43,46 @@ int execute_statements (packet, lease, in_options, out_options, statements)
 
        for (r = statements; r; r = r -> next) {
                switch (r -> op) {
+                     case statements_statement:
+                       log_info ("exec: statements");
+                       if (!execute_statements (packet, lease,
+                                                in_options, out_options,
+                                                r -> data.statements.car))
+                               return 0;
+                       if (!execute_statements (packet, lease,
+                                                in_options, out_options,
+                                                r -> data.statements.cdr))
+                               return 0;
+                       break;
+
+                     case on_statement:
+                       if (lease) {
+                               struct executable_statement **d;
+                               switch (r -> data.on.evtype) {
+                                     case expiry:
+                                       d = &lease -> on_expiry;
+                                       break;
+                                     case commit:
+                                       d = &lease -> on_commit;
+                                       break;
+                                     case release:
+                                       d = &lease -> on_release;
+                                       break;
+                                     default:
+                                       log_fatal ("unknown event type %d %s",
+                                                  r -> data.on.evtype,
+                                                  "in on statement.");
+                                       break;
+                               }
+                               if (*d)
+                                       executable_statement_dereference
+                                               (d, "execute_statements");
+                               executable_statement_reference
+                                       (d, r -> data.on.statements,
+                                        "execute_statements");
+                       }
+                       break;
+
                      case if_statement:
                        status = evaluate_boolean_expression
                                (&result, packet,
index fe74b9ec67455025d3c3a63b8c6e95d55e5f172d..fed33e1342939654a9bb1d8e0625757ee1eb276c 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: parse.c,v 1.28 1999/07/06 20:41:22 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: parse.c,v 1.29 1999/07/16 21:33:59 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -1151,27 +1151,29 @@ int parse_cshl (data, cfile)
  *     APPEND option-parameter SEMI
  */
 
-struct executable_statement *parse_executable_statements (cfile, lose)
+int parse_executable_statements (statements, cfile, lose)
+       struct executable_statement **statements;
        FILE *cfile;
        int *lose;
 {
-       struct executable_statement *head, **next;
+       struct executable_statement **next;
 
-       next = &head;
-       while ((*next = parse_executable_statement (cfile, lose)))
+       next = statements;
+       while (parse_executable_statement (next, cfile, lose))
                next = &((*next) -> next);
        if (!*lose)
-               return head;
-       return (struct executable_statement *)0;
+               return 1;
+       return 0;
 }
 
-struct executable_statement *parse_executable_statement (cfile, lose)
+int parse_executable_statement (result, cfile, lose)
+       struct executable_statement **result;
        FILE *cfile;
        int *lose;
 {
        enum dhcp_token token;
        char *val;
-       struct executable_statement *stmt, base;
+       struct executable_statement base;
        struct class *cta;
        struct option *option;
        struct option_cache *cache;
@@ -1180,8 +1182,8 @@ struct executable_statement *parse_executable_statement (cfile, lose)
        switch (token) {
              case IF:
                next_token (&val, cfile);
-               stmt = parse_if_statement (cfile, lose);
-               return stmt;
+               return parse_if_statement (result, cfile, lose);
+
              case TOKEN_ADD:
                token = next_token (&val, cfile);
                token = next_token (&val, cfile);
@@ -1189,39 +1191,43 @@ struct executable_statement *parse_executable_statement (cfile, lose)
                        parse_warn ("expecting class name.");
                        skip_to_semi (cfile);
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       return 0;
                }
                cta = find_class (val);
                if (!cta) {
                        parse_warn ("unknown class %s.", val);
                        skip_to_semi (cfile);
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       return 0;
                }
                if (!parse_semi (cfile)) {
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       return 0;
                }
-               memset (&base, 0, sizeof base);
-               base.op = add_statement;
-               base.data.add = cta;
+               if (!executable_statement_allocate
+                   (result, "parse_executable_statement"))
+                       log_fatal ("no memory for new statement.");
+               (*result) -> op = add_statement;
+               (*result) -> data.add = cta;
                break;
 
              case BREAK:
                token = next_token (&val, cfile);
                if (!parse_semi (cfile)) {
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       return 0;
                }
-               memset (&base, 0, sizeof base);
-               base.op = break_statement;
+               if (!executable_statement_allocate
+                   (result, "parse_executable_statement"))
+                       log_fatal ("no memory for new statement.");
+               (*result) -> op = break_statement;
                break;
 
              case SEND:
                *lose = 1;
                parse_warn ("send not appropriate here.");
                skip_to_semi (cfile);
-               return (struct executable_statement *)0;
+               return 0;
 
              case SUPERSEDE:
              case OPTION:
@@ -1229,9 +1235,9 @@ struct executable_statement *parse_executable_statement (cfile, lose)
                option = parse_option_name (cfile, 0);
                if (!option) {
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       return 0;
                }
-               return parse_option_statement (cfile, 1, option,
+               return parse_option_statement (result, cfile, 1, option,
                                               supersede_option_statement);
 
              case ALLOW:
@@ -1240,10 +1246,12 @@ struct executable_statement *parse_executable_statement (cfile, lose)
                cache = (struct option_cache *)0;
                if (!parse_allow_deny (&cache, cfile,
                                       token == ALLOW ? 1 : 0))
-                       return (struct executable_statement *)0;
-               memset (&base, 0, sizeof base);
-               base.op = supersede_option_statement;
-               base.data.option = cache;
+                       return 0;
+               if (!executable_statement_allocate
+                   (result, "parse_executable_statement"))
+                       log_fatal ("no memory for new statement.");
+               (*result) -> op = supersede_option_statement;
+               (*result) -> data.option = cache;
                break;
 
              case DEFAULT:
@@ -1251,9 +1259,9 @@ struct executable_statement *parse_executable_statement (cfile, lose)
                option = parse_option_name (cfile, 0);
                if (!option) {
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       return 0;
                }
-               return parse_option_statement (cfile, 1, option,
+               return parse_option_statement (result, cfile, 1, option,
                                               default_option_statement);
 
              case PREPEND:
@@ -1261,9 +1269,9 @@ struct executable_statement *parse_executable_statement (cfile, lose)
                option = parse_option_name (cfile, 0);
                if (!option) {
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       return 0;
                }
-               return parse_option_statement (cfile, 1, option,
+               return parse_option_statement (result, cfile, 1, option,
                                               prepend_option_statement);
 
              case APPEND:
@@ -1271,23 +1279,96 @@ struct executable_statement *parse_executable_statement (cfile, lose)
                option = parse_option_name (cfile, 0);
                if (!option) {
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       return 0;
                }
-               return parse_option_statement (cfile, 1, option,
+               return parse_option_statement (result, cfile, 1, option,
                                               append_option_statement);
 
+             case ON:
+               token = next_token (&val, cfile);
+
+               return parse_on_statement (result, cfile, lose);
+                       
              default:
                *lose = 0;
-               return (struct executable_statement *)0;
+               return 0;
        }
 
-       stmt = ((struct executable_statement *)
-               dmalloc (sizeof (struct executable_statement),
-                        "parse_executable_statement"));
-       if (!stmt)
+       return 1;
+}
+
+/*
+ * on-statement :== event-type LBRACE executable-statements RBRACE
+ *
+ * event-type :== EXPIRY | COMMIT | RELEASE
+ */
+
+int parse_on_statement (result, cfile, lose)
+       struct executable_statement **result;
+       FILE *cfile;
+       int *lose;
+{
+       enum dhcp_token token;
+       char *val;
+
+       if (!executable_statement_allocate (result,
+                                           "parse_executable_statement"))
                log_fatal ("no memory for new statement.");
-       *stmt = base;
-       return stmt;
+
+       token = next_token (&val, cfile);
+       switch (token) {
+             case EXPIRY:
+               (*result) -> data.on.evtype = expiry;
+               break;
+               
+             case COMMIT:
+               (*result) -> data.on.evtype = expiry;
+               break;
+               
+             case RELEASE:
+               (*result) -> data.on.evtype = expiry;
+               break;
+               
+             default:
+               parse_warn ("expecting a lease event type");
+               skip_to_semi (cfile);
+               *lose = 1;
+               executable_statement_dereference
+                       (result, "parse_on_statement");
+               break;
+       }
+               
+       token = next_token (&val, cfile);
+       if (token != LBRACE) {
+               parse_warn ("left brace expected.");
+               skip_to_semi (cfile);
+               *lose = 1;
+               executable_statement_dereference (result,
+                                                 "parse_on_statement");
+               return 0;
+       }
+       if (!parse_executable_statements (&(*result) -> data.on.statements,
+                                         cfile, lose)) {
+               if (*lose) {
+                       /* Try to even things up. */
+                       do {
+                               token = next_token (&val, cfile);
+                       } while (token != EOF && token != RBRACE);
+                       executable_statement_dereference
+                               (result, "parse_on_statement");
+                       return 0;
+               }
+       }
+       token = next_token (&val, cfile);
+       if (token != RBRACE) {
+               parse_warn ("right brace expected.");
+               skip_to_semi (cfile);
+               *lose = 1;
+               executable_statement_dereference
+                       (result, "parse_on_statement");
+               return 0;
+       }
+       return 1;
 }
 
 /*
@@ -1300,21 +1381,26 @@ struct executable_statement *parse_executable_statement (cfile, lose)
  *                   ELSIF if-statement
  */
 
-struct executable_statement *parse_if_statement (cfile, lose)
+int parse_if_statement (result, cfile, lose)
+       struct executable_statement **result;
        FILE *cfile;
        int *lose;
 {
        enum dhcp_token token;
        char *val;
-       struct executable_statement *stmt;
-       struct expression *if_condition;
-       struct executable_statement *true, *false;
 
-       if_condition = (struct expression *)0;
-       if (!parse_boolean_expression (&if_condition, cfile, lose)) {
+       if (!executable_statement_allocate (result, "parse_if_statement"))
+               log_fatal ("no memory for if statement.");
+
+       (*result) -> op = if_statement;
+
+       if (!parse_boolean_expression (&(*result) -> data.ie.expr,
+                                      cfile, lose)) {
                if (!*lose)
                        parse_warn ("boolean expression expected.");
-               return (struct executable_statement *)0;
+               executable_statement_dereference (result,
+                                                 "parse_if_statement");
+               return 0;
        }
 #if defined (DEBUG_EXPRESSION_PARSE)
        print_expression ("if condition", if_condition);
@@ -1324,22 +1410,30 @@ struct executable_statement *parse_if_statement (cfile, lose)
                parse_warn ("left brace expected.");
                skip_to_semi (cfile);
                *lose = 1;
-               return (struct executable_statement *)0;
+               executable_statement_dereference (result,
+                                                 "parse_if_statement");
+               return 0;
        }
-       true = parse_executable_statements (cfile, lose);
-       token = next_token (&val, cfile);
-       if (*lose) {
-               /* Try to even things up. */
-               do {
-                       token = next_token (&val, cfile);
-               } while (token != EOF && token != RBRACE);
-               return (struct executable_statement *)0;
+       if (!parse_executable_statements (&(*result) -> data.ie.true,
+                                         cfile, lose)) {
+               if (*lose) {
+                       /* Try to even things up. */
+                       do {
+                               token = next_token (&val, cfile);
+                       } while (token != EOF && token != RBRACE);
+                       executable_statement_dereference
+                               (result, "parse_if_statement");
+                       return 0;
+               }
        }
+       token = next_token (&val, cfile);
        if (token != RBRACE) {
                parse_warn ("right brace expected.");
                skip_to_semi (cfile);
                *lose = 1;
-               return (struct executable_statement *)0;
+               executable_statement_dereference
+                       (result, "parse_if_statement");
+               return 0;
        }
        token = peek_token (&val, cfile);
        if (token == ELSE) {
@@ -1347,46 +1441,53 @@ struct executable_statement *parse_if_statement (cfile, lose)
                token = peek_token (&val, cfile);
                if (token == IF) {
                        token = next_token (&val, cfile);
-                       false = parse_if_statement (cfile, lose);
-                       if (*lose)
-                               return (struct executable_statement *)0;
+                       if (!parse_if_statement (&(*result) -> data.ie.false,
+                                                cfile, lose)) {
+                               if (*lose) {
+                                       return 0;
+                                       executable_statement_dereference
+                                               (result, "parse_if_statement");
+                               }
+                       }
                } else if (token != LBRACE) {
                        parse_warn ("left brace or if expected.");
                        skip_to_semi (cfile);
                        *lose = 1;
-                       return (struct executable_statement *)0;
+                       executable_statement_dereference
+                               (result, "parse_if_statement");
+                       return 0;
                } else {
                        token = next_token (&val, cfile);
-                       false = parse_executable_statements (cfile, lose);
-                       if (*lose)
-                               return (struct executable_statement *)0;
+                       if (!parse_if_statement (&(*result) -> data.ie.false,
+                                                cfile, lose)) {
+                               executable_statement_dereference
+                                       (result, "parse_if_statement");
+                               return 0;
+                       }
                        token = next_token (&val, cfile);
                        if (token != RBRACE) {
                                parse_warn ("right brace expected.");
                                skip_to_semi (cfile);
                                *lose = 1;
-                               return (struct executable_statement *)0;
+                               executable_statement_dereference
+                                       (result, "parse_if_statement");
+                               return 0;
                        }
                }
        } else if (token == ELSIF) {
                token = next_token (&val, cfile);
-               false = parse_if_statement (cfile, lose);
-               if (*lose)
-                       return (struct executable_statement *)0;
+               if (!parse_if_statement (&(*result) -> data.ie.false,
+                                        cfile, lose)) {
+                       if (*lose) {
+                               return 0;
+                               executable_statement_dereference
+                                       (result, "parse_if_statement");
+                       }
+               }
        } else
-               false = (struct executable_statement *)0;
+               (*result) -> data.ie.false = (struct executable_statement *)0;
        
-       stmt = ((struct executable_statement *)
-               dmalloc (sizeof (struct executable_statement),
-                        "parse_if_statement"));
-       if (!stmt)
-               log_fatal ("no memory for if statement.");
-       memset (stmt, 0, sizeof *stmt);
-       stmt -> op = if_statement;
-       stmt -> data.ie.expr = if_condition;
-       stmt -> data.ie.true = true;
-       stmt -> data.ie.false = false;
-       return stmt;
+       return 1;
 }
 
 /*
@@ -1486,6 +1587,7 @@ int parse_non_binary (expr, cfile, lose, context)
        char *val;
        struct collection *col;
        struct option *option;
+       struct expression *nexp;
 
        token = peek_token (&val, cfile);
 
@@ -1746,11 +1848,49 @@ int parse_non_binary (expr, cfile, lose, context)
                        goto norparen;
                break;
 
-             case OPTION:
+             case PICK_FIRST_VALUE:
+               /* pick (a, b, c) actually produces an internal representation
+                  that looks like pick (a, pick (b, pick (c, nil))). */
+               token = next_token (&val, cfile);
+               if (!(expression_allocate
+                     (expr, "parse_expression: PICK_FIRST_VALUE")))
+                       log_fatal ("can't allocate expression");
+               (*expr) -> op = expr_reverse;
+
                token = next_token (&val, cfile);
+               if (token != LPAREN)
+                       goto nolparen;
+
+               nexp = *expr;
+               do {
+                       struct expression *tmp = (struct expression *)0;
+                       if (!(parse_data_expression
+                             (&nexp -> data.pick_first_value.car,
+                              cfile, lose)))
+                               goto nodata;
+
+                       token = next_token (&val, cfile);
+                       if (token == COMMA) {
+                               if (!(expression_allocate
+                                     (&nexp -> data.pick_first_value.cdr,
+                                      "parse_expression: PICK_FIRST_VALUE")))
+                                       log_fatal ("can't allocate expr");
+                               nexp = nexp -> data.pick_first_value.cdr;
+                       }
+               } while (token == COMMA);
+
+               if (token != RPAREN)
+                       goto norparen;
+               break;
+
+             case OPTION:
+             case CONFIG_OPTION:
                if (!expression_allocate (expr, "parse_expression: OPTION"))
                        log_fatal ("can't allocate expression");
-               (*expr) -> op = expr_option;
+               (*expr) -> op = token == (OPTION
+                                         ? expr_option
+                                         : expr_config_option);
+               token = next_token (&val, cfile);
                (*expr) -> data.option = parse_option_name (cfile, 0);
                if (!(*expr) -> data.option) {
                        *lose = 1;
@@ -1775,6 +1915,14 @@ int parse_non_binary (expr, cfile, lose, context)
                (*expr) -> op = expr_leased_address;
                break;
 
+             case HOST_DECL_NAME:
+               token = next_token (&val, cfile);
+               if (!expression_allocate (expr,
+                                         "parse_expression: HOST_DECL_NAME"))
+                       log_fatal ("can't allocate expression");
+               (*expr) -> op = expr_host_decl_name;
+               break;
+
              case PACKET:
                token = next_token (&val, cfile);
                if (!expression_allocate (expr, "parse_expression: PACKET"))
@@ -2123,8 +2271,8 @@ int parse_expression (expr, cfile, lose, context, plhs, binop)
    would be painful to come up with BNF for it.   However, it always
    starts as above and ends in a SEMI. */
 
-struct executable_statement *parse_option_statement (cfile, lookups,
-                                                    option, op)
+int parse_option_statement (result, cfile, lookups, option, op)
+       struct executable_statement **result;
        FILE *cfile;
        int lookups;
        struct option *option;
@@ -2159,7 +2307,7 @@ struct executable_statement *parse_option_statement (cfile, lookups,
                                parse_warn ("expecting a data expression.");
                                skip_to_semi (cfile);
                        }
-                       return (struct executable_statement *)0;
+                       return 0;
                }
 
                /* We got a valid expression, so use it. */
@@ -2182,7 +2330,7 @@ struct executable_statement *parse_option_statement (cfile, lookups,
                                                 tmp, uniform, lookups)) {
                                expression_dereference
                                        (&tmp, "parse_option_statement");
-                               return (struct executable_statement *)0;
+                               return 0;
                        }
                        if (tmp)
                                expression_dereference
@@ -2200,15 +2348,14 @@ struct executable_statement *parse_option_statement (cfile, lookups,
 
       done:
        if (!parse_semi (cfile))
-               return (struct executable_statement *)0;
-       stmt = ((struct executable_statement *)
-               dmalloc (sizeof *stmt, "parse_option_statement"));
-       memset (stmt, 0, sizeof *stmt);
-       stmt -> op = op;
-       if (expr && !option_cache (&stmt -> data.option,
+               return 0;
+       if (!executable_statement_allocate (result, "parse_option_statement"))
+               log_fatal ("no memory for option statement.");
+       (*result) -> op = op;
+       if (expr && !option_cache (&(*result) -> data.option,
                                   (struct data_string *)0, expr, option))
                log_fatal ("no memory for option cache");
-       return stmt;
+       return 1;
 }
 
 int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
index 6a247fcaaee951df2fe865184e883d4dbecca0c8..466e4cbdfdbb26f24c294270012ddbb7dfe71ef7 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: tree.c,v 1.32 1999/07/13 18:00:12 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: tree.c,v 1.33 1999/07/16 21:33:59 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -538,6 +538,9 @@ int evaluate_boolean_expression (result, packet, options, lease, expr)
              case expr_encode_int32:
              case expr_binary_to_ascii:
              case expr_reverse:
+             case expr_pick_first_value:
+             case expr_host_decl_name:
+             case expr_config_option:
              case expr_leased_address:
                log_error ("Data opcode in evaluate_boolean_expression: %d",
                      expr -> op);
@@ -651,6 +654,7 @@ int evaluate_data_expression (result, packet, options, lease, expr)
 
                /* Extract an option. */
              case expr_option:
+             case expr_config_option:
                if (options)
                        s0 = ((*expr -> data.option -> universe -> get_func)
                              (result, expr -> data.option -> universe,
@@ -1098,7 +1102,53 @@ int evaluate_data_expression (result, packet, options, lease, expr)
 #endif
                return 1;
 
-               
+             case expr_pick_first_value:
+               memset (&data, 0, sizeof data);
+               if ((evaluate_data_expression
+                    (result, packet, options, lease,
+                     expr -> data.pick_first_value.car))) {
+#if defined (DEBUG_EXPRESSIONS)
+                       log_info ("data: pick_first_value (%s, ???)",
+                                 print_hex_1 (result -> len,
+                                              result -> data, 40));
+#endif
+                       return 1;
+               }
+               if ((evaluate_data_expression
+                    (result, packet, options, lease,
+                     expr -> data.pick_first_value.cdr))) {
+#if defined (DEBUG_EXPRESSIONS)
+                       log_info ("data: pick_first_value (NULL, %s)",
+                                 print_hex_1 (result -> len,
+                                              result -> data, 40));
+#endif
+                       return 1;
+               }
+
+#if defined (DEBUG_EXPRESSIONS)
+               log_info ("data: pick_first_value (NULL, NULL) = NULL");
+#endif
+               return 0;
+
+             case expr_host_decl_name:
+               if (!lease || !lease -> host) {
+                       log_error ("data: host_decl_name: not available");
+                       return 0;
+               }
+               result -> len = strlen (lease -> host -> name) + 1;
+               if (buffer_allocate (&result -> buffer, result -> len,
+                                    "host-decl-name")) {
+                       result -> data = &result -> buffer -> data [0];
+                       strcpy (&result -> data [0], lease -> host -> name);
+                       result -> terminated = 1;
+               } else {
+                       log_error ("data: host-decl-name: no memory.");
+                       return 0;
+               }
+#if defined (DEBUG_EXPRESSIONS)
+               log_info ("data: host-decl-name = %s", lease -> host -> name);
+#endif
+               return 1;
 
              case expr_check:
              case expr_equal:
@@ -1160,6 +1210,9 @@ int evaluate_numeric_expression (result, packet, options, lease, expr)
              case expr_encode_int32:
              case expr_binary_to_ascii:
              case expr_reverse:
+             case expr_pick_first_value:
+             case expr_host_decl_name:
+             case expr_config_option:
              case expr_leased_address:
                log_error ("Data opcode in evaluate_numeric_expression: %d",
                      expr -> op);
@@ -1411,6 +1464,15 @@ void expression_dereference (eptr, name)
                                                name);
                break;
 
+             case expr_pick_first_value:
+               if (expr -> data.pick_first_value.car)
+                       expression_dereference
+                               (&expr -> data.pick_first_value.car, name);
+               if (expr -> data.pick_first_value.cdr)
+                       expression_dereference
+                               (&expr -> data.pick_first_value.cdr, name);
+               break;
+
              case expr_reverse:
                if (expr -> data.reverse.width)
                        expression_dereference (&expr -> data.reverse.width,
@@ -1547,6 +1609,9 @@ static int op_val (op)
              case expr_known:
              case expr_binary_to_ascii:
              case expr_reverse:
+             case expr_pick_first_value:
+             case expr_host_decl_name:
+             case expr_config_option:
              case expr_leased_address:
                return 100;
 
@@ -1599,6 +1664,9 @@ enum expression_context op_context (op)
              case expr_known:
              case expr_binary_to_ascii:
              case expr_reverse:
+             case expr_pick_first_value:
+             case expr_host_decl_name:
+             case expr_config_option:
              case expr_leased_address:
                return context_any;
 
index b1fd6c7e85706186e481489909f019527170c98f..6edf89412f4842bd30bd5b478ad7008ee7e297c9 100644 (file)
@@ -186,6 +186,10 @@ struct lease {
        struct class *billing_class;
        struct hardware hardware_addr;
 
+       struct executable_statement *on_expiry;
+       struct executable_statement *on_commit;
+       struct executable_statement *on_release;
+
        int flags;
 #       define STATIC_LEASE            1
 #       define BOOTP_LEASE             2
@@ -902,11 +906,12 @@ struct option *parse_option_name PROTO ((FILE *, int));
 void parse_option_space_decl PROTO ((FILE *));
 int parse_option_code_definition PROTO ((FILE *, struct option *));
 int parse_cshl PROTO ((struct data_string *, FILE *));
-struct executable_statement *parse_executable_statement PROTO ((FILE *,
-                                                               int *));
-struct executable_statement *parse_executable_statements PROTO ((FILE *,
-                                                                int *));
-struct executable_statement *parse_if_statement PROTO ((FILE *, int *));
+int parse_executable_statement PROTO ((struct executable_statement **,
+                                      FILE *, int *));
+int parse_executable_statements PROTO ((struct executable_statement **,
+                                       FILE *, int *));
+int parse_on_statement PROTO ((struct executable_statement **, FILE *, int *));
+int parse_if_statement PROTO ((struct executable_statement **, FILE *, int *));
 int parse_boolean_expression PROTO ((struct expression **, FILE *, int *));
 int parse_data_expression PROTO ((struct expression **, FILE *, int *));
 int parse_numeric_expression PROTO ((struct expression **, FILE *, int *));
@@ -915,10 +920,8 @@ int parse_non_binary PROTO ((struct expression **, FILE *, int *,
 int parse_expression PROTO ((struct expression **, FILE *, int *,
                             enum expression_context,
                             struct expression **, enum expr_op));
-struct executable_statement *parse_option_statement PROTO ((FILE *, int,
-                                                           struct option *,
-                                                           enum statement_op)
-                                                          );
+int parse_option_statement PROTO ((struct executable_statement **, FILE *, int,
+                                  struct option *, enum statement_op));
 int parse_option_token PROTO ((struct expression **, FILE *, char *,
                               struct expression *, int, int));
 int parse_allow_deny PROTO ((struct option_cache **, FILE *, int));
@@ -1095,6 +1098,13 @@ int option_state_allocate PROTO ((struct option_state **, char *));
 int option_state_reference PROTO ((struct option_state **,
                                   struct option_state *, char *));
 int option_state_dereference PROTO ((struct option_state **, char *));
+int executable_statement_allocate PROTO ((struct executable_statement **,
+                                         char *));
+int executable_statement_reference PROTO ((struct executable_statement **,
+                                          struct executable_statement *,
+                                          char *));
+int executable_statement_dereference PROTO ((struct executable_statement **,
+                                            char *));
 
 /* print.c */
 char *print_hw_addr PROTO ((int, int, unsigned char *));
index b1e78a64a3bdc96e7ddbafd6a1e27b7b50a29388..203526cd5308a30a548ebd1a9de50a7f0945b29a 100644 (file)
@@ -184,6 +184,13 @@ enum dhcp_token {
        REVERSE = 402,
        LEASED_ADDRESS = 403,
        BINARY_TO_ASCII = 404,
+       PICK_FIRST_VALUE = 405,
+       CONFIG_OPTION = 406,
+       HOST_DECL_NAME = 407,
+       ON = 408,
+       EXPIRY = 409,
+       RELEASE = 410,
+       COMMIT = 411,
 };
 
 #define is_identifier(x)       ((x) >= FIRST_TOKEN &&  \
index 1240e691d0ac208c2b978c282401d09a16b49bb4..f9c1660b188790d3b46588f22cf8ea07ef2f4581 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 struct executable_statement {
+       int refcnt;
        struct executable_statement *next;
        enum statement_op {
                if_statement,
@@ -32,6 +33,8 @@ struct executable_statement {
                append_option_statement,
                prepend_option_statement,
                send_option_statement,
+               statements_statement,
+               on_statement,
        } op;
        union {
                struct {
@@ -44,6 +47,11 @@ struct executable_statement {
                struct option_cache *supersede;
                struct option_cache *prepend;
                struct option_cache *append;
+               struct executable_statement *statements;
+               struct {
+                       enum { expiry, commit, release } evtype;
+                       struct executable_statement *statements;
+               } on;
        } data;
 };
 
index 964565bd939cc1045bb3b7324584b389e6400650..b80066b4cb9974c316fd8ede291105c17023f19d 100644 (file)
@@ -86,6 +86,9 @@ enum expr_op {
        expr_reverse,
        expr_leased_address,
        expr_binary_to_ascii,
+       expr_config_option,
+       expr_host_decl_name,
+       expr_pick_first_value,
 };
 
 struct expression {
@@ -107,6 +110,7 @@ struct expression {
                        struct expression *len;
                } suffix;
                struct option *option;
+               struct option *config_option;
                struct {
                        struct expression *offset;
                        struct expression *len;
@@ -129,6 +133,10 @@ struct expression {
                        struct expression *width;
                        struct expression *buffer;
                } reverse;
+               struct {
+                       struct expression *car;
+                       struct expression *cdr;
+               } pick_first_value;
        } data;
        int flags;
 #      define EXPR_EPHEMERAL   1
index 5322260a0b4f9b35cd20b826b67afdeb673207ae..6ee60900b61cd9a662d6ef19d037988bb1f35e56 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: confpars.c,v 1.74 1999/07/12 22:44:16 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: confpars.c,v 1.75 1999/07/16 21:34:14 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -426,10 +426,10 @@ int parse_statement (cfile, group, type, host_decl, declaration)
                        }
 
                      finish_option:
-                       et = parse_option_statement
-                               (cfile, 1, option,
-                                supersede_option_statement);
-                       if (!et)
+                       et = (struct executable_statement *)0;
+                       if (!parse_option_statement
+                               (&et, cfile, 1, option,
+                                supersede_option_statement))
                                return declaration;
                        goto insert_statement;
                } else
@@ -451,18 +451,16 @@ int parse_statement (cfile, group, type, host_decl, declaration)
                                               (unsigned char *)val, 0));
                        if (option) {
                                token = next_token (&val, cfile);
-                               et = parse_option_statement
-                                       (cfile, 1, option,
-                                        supersede_option_statement);
-                               if (!et)
+                               if (!parse_option_statement
+                                       (&et, cfile, 1, option,
+                                        supersede_option_statement))
                                        return declaration;
                        }
                }
 
                if (!et) {
                        lose = 0;
-                       et = parse_executable_statement (cfile, &lose);
-                       if (!et) {
+                       if (!parse_executable_statement (&et, cfile, &lose)) {
                                if (!lose) {
                                        if (declaration)
                                                parse_warn ("expecting a %s.",
@@ -483,13 +481,41 @@ int parse_statement (cfile, group, type, host_decl, declaration)
                }
              insert_statement:
                if (group -> statements) {
+                       int multi = 0;
+
+                       /* If this set of statements is only referenced
+                          by this group, just add the current statement
+                          to the end of the chain. */
                        for (ep = group -> statements; ep -> next;
                             ep = ep -> next)
-                               ;
-                       ep -> next = et;
+                               if (ep -> refcnt > 1) /* XXX */
+                                       multi = 1;
+                       if (!multi) {
+                               executable_statement_reference
+                                       (&ep -> next, et, "parse_statement");
+                               return declaration;
+                       }
 
+                       /* Otherwise, make a parent chain, and put the
+                          current group statements first and the new
+                          statement in the next pointer. */
+                       ep = (struct executable_statement *)0;
+                       if (!executable_statement_allocate
+                           (&ep, "parse_statement"))
+                               log_fatal ("No memory for statements.");
+                       ep -> op = statements_statement;
+                       executable_statement_reference
+                               (&ep -> data.statements,
+                                group -> statements, "parse_statement");
+                       executable_statement_reference
+                               (&ep -> next, et, "parse_statement");
+                       executable_statement_dereference
+                               (&group -> statements, "parse_statement");
+                       executable_statement_reference
+                               (&group -> statements, ep, "parse_statements");
                } else
-                       group -> statements = et;
+                       executable_statement_reference
+                               (&group -> statements, et, "parse_statements");
                return declaration;
        }