Added support for "<=" and ">=". Made the conf file parser a
authoraland <aland>
Thu, 14 Jun 2007 09:09:28 +0000 (09:09 +0000)
committeraland <aland>
Thu, 14 Jun 2007 09:09:28 +0000 (09:09 +0000)
little more careful, too

man/man5/unlang.5
src/main/conffile.c
src/main/evaluate.c
src/main/modcall.c

index 5983553..4731a94 100644 (file)
@@ -366,6 +366,26 @@ same name are already present in the list.
 Remove all matching attributes from the list.  Both the attribute name
 and value have to match in order for the attribute to be removed from
 the list.
+.IP <=
+Enforce that the integer value of the attribute is less than or equal
+to the value given here.  If there is no attribute of the same name in
+the list, the attribute is added with the given value, is with "+=".
+If an attribute in the list exists, and has value less than given
+here, it's value is unchanged.  If an attribute in the exists, and has
+value greater than given here, it's value is replaced with the value
+given here.
+
+This operator is valid only for attributes of integer type.
+.IP >=
+Enforce that the integer value of the attribute is greater than or
+equal to the value given here.  If there is no attribute of the same
+name in the list, the attribute is added with the given value, is with
+"+=".  If an attribute in the list exists, and has value greater than
+given here, it's value is unchanged.  If an attribute in the exists,
+and has value less than given here, it's value is replaced with the
+value given here.
+
+This operator is valid only for attributes of integer type.
 .RE
 .IP Values
 .br
index e9d5c69..f6c59c7 100644 (file)
@@ -336,7 +336,6 @@ void cf_section_free(CONF_SECTION **cs)
                        break;
 
                case CONF_ITEM_SECTION: {
-
                                CONF_SECTION *section = cf_itemtosection(ci);
                                cf_section_free(&section);
                        }
@@ -1249,11 +1248,21 @@ static int cf_section_read(const char *file, int *lineno, FILE *fp,
                case T_EOL:
                case T_HASH:
                        t2 = T_OP_EQ;
+                       goto do_set;
 
-               case T_OP_EQ:
                case T_OP_ADD:
                case T_OP_SUB:
+               case T_OP_LE:
+               case T_OP_GE:
+                       if (!this || (strcmp(this->name1, "update") != 0)) {
+                               radlog(L_ERR, "%s[%d]: Invalid operator in assignment",
+                                      file, *lineno);
+                               return -1;
+                       }
+
+               case T_OP_EQ:
                case T_OP_SET:
+               do_set:
                        t3 = getstring(&ptr, buf3, sizeof(buf3));
 
                        /*
index d8121bc..e9ec134 100644 (file)
@@ -771,7 +771,12 @@ static void my_pairmove(VALUE_PAIR **to, VALUE_PAIR *from)
                         *      Delete all matching attributes from
                         *      "to"
                         */
-                       if (from_list[i]->operator == T_OP_SUB) {
+                       if ((from_list[i]->operator == T_OP_SUB) ||
+                           (from_list[i]->operator == T_OP_LE) ||
+                           (from_list[i]->operator == T_OP_GE)) {
+                               int rcode;
+                               int old_op = from_list[i]->operator;
+
                                /*
                                 *      Check for equality.
                                 */
@@ -781,22 +786,51 @@ static void my_pairmove(VALUE_PAIR **to, VALUE_PAIR *from)
                                 *      If equal, delete the one in
                                 *      the "to" list.
                                 */
-                               if (radius_compare_vps(NULL, from_list[i],
-                                                      to_list[j]) == 0) {
-
-                                       DEBUG4("::: DELETING %s FROM %d TO %d",
-                                              from_list[i]->name, i, j);
-                                       pairfree(&to_list[j]);
-                                       to_list[j] = NULL;
-                               }
-
+                               rcode = radius_compare_vps(NULL, from_list[i],
+                                                          to_list[j]);
                                /*
                                 *      We may want to do more
                                 *      subtractions, so we re-set the
                                 *      operator back to it's original
                                 *      value.
                                 */
-                               from_list[i]->operator = T_OP_SUB;
+                               from_list[i]->operator = old_op;
+
+                               switch (old_op) {
+                               case T_OP_SUB:
+                                       if (rcode == 0) {
+                                               DEBUG4("::: DELETING %s FROM %d TO %d",
+                                                      from_list[i]->name, i, j);
+                                               pairfree(&to_list[j]);
+                                               to_list[j] = NULL;
+                                       }
+                                       break;
+
+                                       /*
+                                        *      Enforce <=.  If it's
+                                        *      >, replace it.
+                                        */
+                               case T_OP_LE:
+                                       if (rcode > 0) {
+                                               DEBUG4("::: REPLACING %s FROM %d TO %d",
+                                                      from_list[i]->name, i, j);
+                                               pairfree(&to_list[j]);
+                                               to_list[j] = from_list[i];
+                                               from_list[i] = NULL;
+                                       }
+                                       break;
+
+                               case T_OP_GE:
+                                       if (rcode < 0) {
+                                               DEBUG4("::: REPLACING %s FROM %d TO %d",
+                                                      from_list[i]->name, i, j);
+                                               pairfree(&to_list[j]);
+                                               to_list[j] = from_list[i];
+                                               from_list[i] = NULL;
+                                       }
+                                       break;
+                               }
+
                                continue;
                        }
 
@@ -810,6 +844,8 @@ static void my_pairmove(VALUE_PAIR **to, VALUE_PAIR *from)
                 */
                if (!found) {
                        if ((from_list[i]->operator == T_OP_EQ) ||
+                           (from_list[i]->operator == T_OP_LE) ||
+                           (from_list[i]->operator == T_OP_GE) ||
                            (from_list[i]->operator == T_OP_SET)) {
                        append:
                                DEBUG4("::: APPENDING %s FROM %d TO %d",
index 4a45ec3..f6afaa9 100644 (file)
@@ -1115,12 +1115,30 @@ static modcallable *do_compile_modupdate(modcallable *parent,
                if ((vp->operator != T_OP_EQ) &&
                    (vp->operator != T_OP_ADD) &&
                    (vp->operator != T_OP_SUB) &&
+                   (vp->operator != T_OP_LE) &&
+                   (vp->operator != T_OP_GE) &&
                    (vp->operator != T_OP_SET)) {
                        pairfree(&head);
                        radlog(L_ERR|L_CONS, "%s[%d]: Invalid operator for attribute",
                               filename, cf_pair_lineno(cp));
                        return NULL;
+               }
 
+               /*
+                *      A few more sanity checks.  The enforcement of
+                *      <= or >= can only happen for integer
+                *      attributes.
+                */
+               if ((vp->operator == T_OP_LE) ||
+                   (vp->operator == T_OP_GE)) {
+                       if ((vp->type != PW_TYPE_BYTE) &&
+                           (vp->type != PW_TYPE_SHORT) &&
+                           (vp->type != PW_TYPE_INTEGER)) {
+                               pairfree(&head);
+                               radlog(L_ERR|L_CONS, "%s[%d]: Enforcment of <= or >= is possible only for integer attributes",
+                                      filename, cf_pair_lineno(cp));
+                               return NULL;
+                       }
                }
 
                *tail = vp;
@@ -1165,7 +1183,14 @@ static modcallable *do_compile_modswitch(modcallable *parent,
 
        if (!cf_section_name2(cs)) {
                radlog(L_ERR|L_CONS,
-                      "%s[%d] Require variable to switch over for 'switch'.\n",
+                      "%s[%d] Require variable to switch over for 'switch'.",
+                      filename, lineno);
+               return NULL;
+       }
+
+       if (!cf_item_find_next(cs, NULL)) {
+               radlog(L_ERR|L_CONS,
+                      "%s[%d] 'switch' statments cannot be empty.",
                       filename, lineno);
                return NULL;
        }
@@ -1295,7 +1320,7 @@ static modcallable *do_compile_modsingle(modcallable *parent,
                } else  if (strcmp(modrefname, "if") == 0) {
                        if (!cf_section_name2(cs)) {
                                radlog(L_ERR|L_CONS,
-                                      "%s[%d]: 'if' without condition.\n",
+                                      "%s[%d]: 'if' without condition.",
                                       filename, lineno);
                                return NULL;
                        }
@@ -1322,14 +1347,14 @@ static modcallable *do_compile_modsingle(modcallable *parent,
                            ((parent->type == MOD_LOAD_BALANCE) ||
                             (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
                                radlog(L_ERR|L_CONS,
-                                      "%s[%d] 'elsif' cannot be used in this section section.\n",
+                                      "%s[%d] 'elsif' cannot be used in this section section.",
                                       filename, lineno);
                                return NULL;
                        }
 
                        if (!cf_section_name2(cs)) {
                                radlog(L_ERR|L_CONS,
-                                      "%s[%d] 'elsif' without condition.\n",
+                                      "%s[%d] 'elsif' without condition.",
                                       filename, lineno);
                                return NULL;
                        }
@@ -1356,14 +1381,14 @@ static modcallable *do_compile_modsingle(modcallable *parent,
                            ((parent->type == MOD_LOAD_BALANCE) ||
                             (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
                                radlog(L_ERR|L_CONS,
-                                      "%s[%d] 'else' cannot be used in this section section.\n",
+                                      "%s[%d] 'else' cannot be used in this section section.",
                                       filename, lineno);
                                return NULL;
                        }
 
                        if (cf_section_name2(cs)) {
                                radlog(L_ERR|L_CONS,
-                                      "%s[%d] Cannot have conditions on 'else'.\n",
+                                      "%s[%d] Cannot have conditions on 'else'.",
                                       filename, lineno);
                                return NULL;
                        }
@@ -1508,7 +1533,7 @@ static modcallable *do_compile_modsingle(modcallable *parent,
                        if (cf_item_is_section(ci)) {
                                radlog(L_ERR|L_CONS,
                                       "%s[%d] Subsection of module instance call "
-                                      "not allowed\n", filename,
+                                      "not allowed", filename,
                                       cf_section_lineno(cf_itemtosection(ci)));
                                modcallable_free(&csingle);
                                return NULL;
@@ -1616,7 +1641,7 @@ static modcallable *do_compile_modgroup(modcallable *parent,
                                                      grouptype, &junk);
                        if (!single) {
                                radlog(L_ERR|L_CONS,
-                                      "%s[%d] Failed to parse \"%s\" subsection.\n",
+                                      "%s[%d] Failed to parse \"%s\" subsection.",
                                       filename, lineno,
                                       cf_section_name1(subcs));
                                modcallable_free(&c);
@@ -1650,7 +1675,7 @@ static modcallable *do_compile_modgroup(modcallable *parent,
                                                              &junk);
                                if (!single) {
                                        radlog(L_ERR|L_CONS,
-                                              "%s[%d] Failed to parse \"%s\" entry.\n",
+                                              "%s[%d] Failed to parse \"%s\" entry.",
                                               filename, lineno, attr);
                                        modcallable_free(&c);
                                        return NULL;