- configuration variables can be declared in the script:
authorMiklos Tirpak <miklos@iptel.org>
Thu, 24 Jan 2008 15:36:56 +0000 (15:36 +0000)
committerMiklos Tirpak <miklos@iptel.org>
Thu, 24 Jan 2008 15:36:56 +0000 (15:36 +0000)
<group_name>.<var_name> = <value> [descr <description>]
- free the list of cfg groups during exit

It is possible to declare new config variables in the script,
and retrieve them via select calls. The variables behave the same
way as the core or module variables, they are constant during
message processing, and they can be modified by the cfg drivers,
for example via RPC calls.

gateway.destination = "127.0.0.1" descr "IP addr of the gateway"
gateway.enabled = 1 descr "enable/disable the gateway"

route[0] {
...
if (@cfg_get.gateway.enabled == 1) {
xlset_destination("<sip:%@cfg_get.gateway.destination>");
}
...
}

cfg.lex
cfg.y
cfg/cfg.c
cfg/cfg.h
cfg/cfg_ctx.c
cfg/cfg_ctx.h
cfg/cfg_script.c [new file with mode: 0644]
cfg/cfg_script.h [new file with mode: 0644]
cfg/cfg_struct.c
cfg/cfg_struct.h

diff --git a/cfg.lex b/cfg.lex
index 2718325..b1f90d8 100644 (file)
--- a/cfg.lex
+++ b/cfg.lex
@@ -74,6 +74,7 @@
  *  2007-10-10  added DNS_SEARCH_FMATCH (mma)
  *  2007-11-28  added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
  *              LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
+ *  2008-01-24  added CFG_DESCRIPTION used by cfg_var (Miklos)
 */
 
 
@@ -340,6 +341,8 @@ STUN_REFRESH_INTERVAL "stun_refresh_interval"
 STUN_ALLOW_STUN "stun_allow_stun"
 STUN_ALLOW_FP "stun_allow_fp"
 
+CFG_DESCRIPTION                "description"|"descr"|"desc"
+
 LOADMODULE     loadmodule
 MODPARAM        modparam
 
@@ -642,6 +645,7 @@ EAT_ABLE    [\ \t\b\r]
                                                                        return PMTU_DISCOVERY; }
 <INITIAL>{KILL_TIMEOUT}                        {       count(); yylval.strval=yytext;
                                                                        return KILL_TIMEOUT; }
+<INITIAL>{CFG_DESCRIPTION}     { count(); yylval.strval=yytext; return CFG_DESCRIPTION; }
 <INITIAL>{LOADMODULE}  { count(); yylval.strval=yytext; return LOADMODULE; }
 <INITIAL>{MODPARAM}     { count(); yylval.strval=yytext; return MODPARAM; }
 
diff --git a/cfg.y b/cfg.y
index 45d9766..b423f1d 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -87,6 +87,7 @@
  * 2007-10-10  added DNS_SEARCH_FMATCH (mma)
  * 2007-11-28  added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
  *              LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
+ * 2008-01-24  added cfg_var definition (Miklos)
 */
 
 %{
 
 #include "config.h"
 #include "cfg_core.h"
+#include "cfg/cfg.h"
 #ifdef CORE_TLS
 #include "tls/tls_config.h"
 #endif
@@ -380,6 +382,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token TOS
 %token PMTU_DISCOVERY
 %token KILL_TIMEOUT
+%token CFG_DESCRIPTION
 
 %token FLAGS_DECL
 %token AVPFLAGS_DECL
@@ -1102,8 +1105,24 @@ assign_stm:
        | STUN_ALLOW_STUN EQUAL error{ yyerror("number expected"); }
        | STUN_ALLOW_FP EQUAL NUMBER { IF_STUN(stun_allow_fp=$3) ; }
        | STUN_ALLOW_FP EQUAL error{ yyerror("number expected"); }
+       | cfg_var
        | error EQUAL { yyerror("unknown config variable"); }
        ;
+cfg_var:
+       ID DOT ID EQUAL NUMBER {
+               cfg_declare_int($1, $3, $5, NULL);
+       }
+       | ID DOT ID EQUAL STRING {
+               cfg_declare_str($1, $3, $5, NULL);
+       }
+       | ID DOT ID EQUAL NUMBER CFG_DESCRIPTION STRING {
+               cfg_declare_int($1, $3, $5, $7);
+       }
+       | ID DOT ID EQUAL STRING CFG_DESCRIPTION STRING {
+               cfg_declare_str($1, $3, $5, $7);
+       }
+       | ID DOT ID EQUAL error { yyerror("number or string expected"); }
+       ;
 module_stm:
        LOADMODULE STRING {
                DBG("loading module %s\n", $2);
index ffb7b82..67fcd8d 100644 (file)
--- a/cfg/cfg.c
+++ b/cfg/cfg.c
@@ -35,6 +35,7 @@
 #include "../mem/mem.h"
 #include "cfg_struct.h"
 #include "cfg_ctx.h"
+#include "cfg_script.h"
 #include "cfg.h"
 
 /* declares a new cfg group
@@ -44,7 +45,7 @@
 int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
                        void **handle)
 {
-       int     i, num, size;
+       int     i, num, size, group_name_len;
        cfg_mapping_t   *mapping = NULL;
 
        /* check the number of the variables */
@@ -120,10 +121,11 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
                goto error;
        }
 
+       group_name_len = strlen(group_name);
        /* create a new group
        I will allocate memory in shm mem for the variables later in a single block,
        when we know the size of all the registered groups. */
-       if (cfg_new_group(group_name, num, mapping, values, size, handle))
+       if (!cfg_new_group(group_name, group_name_len, num, mapping, values, size, handle))
                goto error;
 
        /* The cfg variables are ready to use, let us set the handle
@@ -133,14 +135,12 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
        *handle = values;
 
        /* notify the drivers about the new config definition */
-       cfg_notify_drivers(group_name, def);
+       cfg_notify_drivers(group_name, group_name_len, def);
 
        LOG(L_DBG, "DEBUG: register_cfg_def(): "
                "new config group has been registered: '%s' (num=%d, size=%d)\n",
                group_name, num, size);
 
-       /* TODO: inform the drivers about the new definition */
-
        return 0;
 
 error:
@@ -150,3 +150,42 @@ error:
 
        return -1;
 }
+
+/* declares a single variable with integer type */
+int cfg_declare_int(char *group_name, char *var_name, int val, char *descr)
+{
+       cfg_script_var_t        *var;
+
+       if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_INT, descr)) == NULL)
+               return -1;
+
+       var->val.i = val;
+
+       return 0;
+}
+
+/* declares a single variable with str type */
+int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr)
+{
+       cfg_script_var_t        *var;
+       int     len;
+
+       if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_STR, descr)) == NULL)
+               return -1;
+
+       if (val) {
+               len = strlen(val);
+               var->val.s.s = (char *)pkg_malloc(sizeof(char) * (len + 1));
+               if (!var->val.s.s) {
+                       LOG(L_ERR, "ERROR: cfg_declare_str(): not enough memory\n");
+                       return -1;
+               }
+               memcpy(var->val.s.s, val, len + 1);
+               var->val.s.len = len;
+       } else {        
+               var->val.s.s = NULL;
+               var->val.s.len = 0;
+       }
+
+       return 0;
+}
index a828bb9..0ad6938 100644 (file)
--- a/cfg/cfg.h
+++ b/cfg/cfg.h
@@ -49,7 +49,7 @@
 typedef int (*cfg_on_change)(void *, str *, void **);
 typedef void (*cfg_on_set_child)(str *);
 
-/* strutrure to be used buy the module interface */
+/* strutrure to be used by the module interface */
 typedef struct _cfg_def {
        char    *name;
        unsigned int    type;
@@ -73,4 +73,10 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
 #define cfg_get(gname, handle, var) \
        ((struct cfg_group_##gname *)handle)->var
 
+/* declares a single variable with integer type */
+int cfg_declare_int(char *group_name, char *var_name, int val, char *descr);
+
+/* declares a single variable with str type */
+int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr);
+
 #endif /* _CFG_H */
index 73f38c8..e19e65a 100644 (file)
@@ -73,6 +73,10 @@ cfg_ctx_t *cfg_register_ctx(cfg_on_declare on_declare_cb)
                        group;
                        group = group->next
                ) {
+                       /* dynamic groups are not ready, the callback
+                       will be called later when the group is fixed-up */
+                       if (group->dynamic) continue;
+
                        gname.s = group->name;
                        gname.len = group->name_len;
                        on_declare_cb(&gname, group->mapping->def);
@@ -98,13 +102,13 @@ void cfg_ctx_destroy(void)
 }
 
 /* notify the drivers about the new config definition */
-void cfg_notify_drivers(char *group_name, cfg_def_t *def)
+void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def)
 {
        cfg_ctx_t       *ctx;
        str             gname;
 
        gname.s = group_name;
-       gname.len = strlen(group_name);
+       gname.len = group_name_len;
 
        for (   ctx = cfg_ctx_list;
                ctx;
@@ -227,8 +231,10 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
 
                p = block->vars+group->offset+var->offset;
        } else {
-               /* we are allowed to rewrite the value on-the-fly */
-               p = group->vars + var->offset;
+               /* we are allowed to rewrite the value on-the-fly
+               The handle either points to group->vars, or to the
+               shared memory block (dynamic group) */
+               p = *(group->handle) + var->offset;
        }
 
        /* set the new value */
@@ -277,6 +283,10 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
                cfg_install_global(block, replaced, child_cb, child_cb);
                CFG_WRITER_UNLOCK();
        } else {
+               /* cfg_set() may be called more than once before forking */
+               if (old_string && (var->flag & cfg_var_shmized))
+                       shm_free(old_string);
+
                /* flag the variable because there is no need
                to shmize it again */
                var->flag |= cfg_var_shmized;
index 6dc62cd..9f49cde 100644 (file)
@@ -104,7 +104,7 @@ int cfg_help(cfg_ctx_t *ctx, str *group_name, str *var_name,
                        char **ch, unsigned int *input_type);
 
 /* notify the drivers about the new config definition */
-void cfg_notify_drivers(char *group_name, cfg_def_t *def);
+void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def);
 
 /* initialize the handle for cfg_get_group_next() */
 #define cfg_get_group_init(handle) \
diff --git a/cfg/cfg_script.c b/cfg/cfg_script.c
new file mode 100644 (file)
index 0000000..c1ef459
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    info@iptel.org
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History
+ * -------
+ *  2008-01-24 dynamic groups are introduced in order to make
+ *             variable declaration possible in the script (Miklos)
+ */
+
+#include <string.h>
+
+#include "../mem/mem.h"
+#include "../ut.h"
+#include "cfg_struct.h"
+#include "cfg_script.h"
+
+/* allocates memory for a new config script variable
+ * The value of the variable is not set!
+ */
+cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type,
+                                       char *descr)
+{
+       cfg_group_t     *group;
+       cfg_script_var_t        *var;
+       int     gname_len, vname_len, descr_len;
+
+       LOG(L_DBG, "DEBUG: new_cfg_script_var(): declaring %s.%s\n", gname, vname);
+
+       if (cfg_shmized) {
+               LOG(L_ERR, "ERROR: new_cfg_script_var(): too late variable declaration, "
+                       "the config has been already shmized\n");
+               return NULL;
+       }
+
+       gname_len = strlen(gname);
+       /* the group may have been already declared */
+       for (   group = cfg_group;
+               group;
+               group = group->next
+       ) {
+               if ((group->name_len == gname_len) &&
+               (memcmp(group->name, gname, gname_len) == 0)) {
+                       if (group->dynamic == 0) {
+                               /* the group has been already declared by a module or by the core */
+                               LOG(L_ERR, "ERROR: new_cfg_script_var(): "
+                                       "configuration group has been already declared: %s\n",
+                                       gname);
+                               return NULL;
+                       }
+                       /* the dynamic group is found */
+                       break;
+               }
+       }
+
+       if (!group) {
+               /* create a new group with NULL values, we will fix it later,
+               when all the variables are known */
+               group = cfg_new_group(gname, gname_len,
+                                       0 /* num */, NULL /* mapping */,
+                                       NULL /* vars */, 0 /* size */, NULL /* handle */);
+                                       
+               if (!group) goto error;
+               group->dynamic = 1;
+       }
+
+       /* verify that the variable does not exist */
+       vname_len = strlen(vname);
+
+       for (   var = (cfg_script_var_t *)group->vars;
+               var;
+               var = var->next
+       ) {
+               if ((var->name_len == vname_len) &&
+               (memcmp(var->name, vname, vname_len) == 0)) {
+                       LOG(L_ERR, "ERROR: new_cfg_script_var(): variable already exists: %s.%s\n",
+                                       gname, vname);
+                       return NULL;
+               }
+       }
+
+       switch (type) {
+       case CFG_VAR_INT:
+               group->size = ROUND_INT(group->size);
+               group->size += sizeof(int);
+               break;
+
+       case CFG_VAR_STR:
+               group->size = ROUND_POINTER(group->size);
+               group->size += sizeof(str);
+               break;
+
+       default:
+               LOG(L_ERR, "ERROR: new_cfg_script_var(): unsupported variable type\n");
+               return NULL;
+       }
+       group->num++;
+
+       var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t));
+       if (!var) goto error;
+       memset(var, sizeof(cfg_script_var_t), 0);
+       var->type = type;
+
+       /* add the variable to the group */
+       var->next = (cfg_script_var_t *)(void *)group->vars;
+       group->vars = (char *)(void *)var;
+
+       /* clone the name of the variable */
+       var->name = (char *)pkg_malloc(sizeof(char) * (vname_len + 1));
+       if (!var->name) goto error;
+       memcpy(var->name, vname, vname_len + 1);
+       var->name_len = vname_len;
+
+       if (descr) {
+               /* save the description */
+               descr_len = strlen(descr);
+               var->descr = (char *)pkg_malloc(sizeof(char) * (descr_len + 1));
+               if (!var->descr) goto error;
+               memcpy(var->descr, descr, descr_len + 1);
+       }
+
+       return var;
+
+error:
+       LOG(L_ERR, "ERROR: new_cfg_script_var(): not enough memory\n");
+       return NULL;
+}
+
+/* fix-up the dynamically declared group:
+ *  - allocate memory for the arrays
+ *  - set the values within the memory block
+ *  - notify the drivers about the new group
+ */
+int cfg_script_fixup(cfg_group_t *group, unsigned char *block)
+{
+       cfg_mapping_t           *mapping = NULL;
+       cfg_def_t               *def = NULL;
+       void                    **handle = NULL;
+       int                     i, offset;
+       cfg_script_var_t        *script_var, *script_var2;
+       str                     s;
+
+       mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*group->num);
+       if (!mapping) goto error;
+       memset(mapping, 0, sizeof(cfg_mapping_t)*group->num);
+
+       /* The variable definition array must look like as if it was declared
+        * in C code, thus, add an additional slot at the end with NULL values */
+       def = (cfg_def_t *)pkg_malloc(sizeof(cfg_def_t)*(group->num + 1));
+       if (!def) goto error;
+       memset(def, 0, sizeof(cfg_def_t)*(group->num + 1));
+
+       /* fill the definition and the mapping arrays */
+       offset = 0;
+       for (   i = 0, script_var = (cfg_script_var_t *)group->vars;
+               script_var;
+               i++, script_var = script_var->next
+       ) {
+               /* there has been already memory allocated for the name */
+               def[i].name = script_var->name;
+               def[i].type = script_var->type | (script_var->type << 3);
+               def[i].descr = script_var->descr;
+
+               mapping[i].def = &(def[i]);
+               mapping[i].name_len = script_var->name_len;
+
+               switch (script_var->type) {
+               case CFG_VAR_INT:
+                       offset = ROUND_INT(offset);
+                       mapping[i].offset = offset;
+
+                       memcpy(block + offset, &script_var->val.i, sizeof(int));
+
+                       offset += sizeof(int);
+                       break;
+
+               case CFG_VAR_STR:
+                       offset = ROUND_POINTER(offset);
+                       mapping[i].offset = offset;
+
+                       if (!(s.s = cfg_clone_str(script_var->val.s))) goto error;
+                       s.len = script_var->val.s.len;
+                       memcpy(block + offset, &s, sizeof(str));
+                       mapping[i].flag |= cfg_var_shmized;
+
+                       offset += sizeof(str);
+                       break;
+               }
+       }
+
+       /* allocate a handle even if it will not be used to
+       directly access the variable, like handle->variable
+       cfg_get_* functions access the memory block via the handle
+       to make sure that it is always safe, thus, it must be created */
+       handle = (void **)pkg_malloc(sizeof(void *));
+       if (!handle) goto error;
+       *handle = NULL;
+       group->handle = handle;
+
+       group->mapping = mapping;
+
+       /* everything went fine, we can free the temporary list */
+       script_var = (cfg_script_var_t *)group->vars;
+       group->vars = NULL;
+       while (script_var) {
+               script_var2 = script_var->next;
+               if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s)
+                       pkg_free(script_var->val.s.s);
+               pkg_free(script_var);
+               script_var = script_var2;
+       }
+
+       return 0;
+
+error:
+       if (mapping) pkg_free(mapping);
+       if (def) pkg_free(def);
+       if (handle) pkg_free(handle);
+
+       LOG(L_ERR, "ERROR: cfg_script_fixup(): not enough memory\n");
+       return -1;
+}
+
+/* destory a dynamically allocated group definition */
+void cfg_script_destroy(cfg_group_t *group)
+{
+       int     i;
+       cfg_script_var_t        *script_var, *script_var2;
+
+       if (group->mapping && group->mapping->def) {
+               for (i=0; i<group->num; i++) {
+                       if (group->mapping->def[i].name)
+                               pkg_free(group->mapping->def[i].name);
+                       if (group->mapping->def[i].descr)
+                               pkg_free(group->mapping->def[i].descr);
+               }
+               pkg_free(group->mapping->def);
+       }
+       if (group->mapping) pkg_free(group->mapping);
+       if (group->handle) pkg_free(group->handle);
+
+       /* it may happen that the the temporary var list
+       still exists because the fixup failed and did not complete */
+       script_var = (cfg_script_var_t *)group->vars;
+       while (script_var) {
+               script_var2 = script_var->next;
+               if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s) 
+                       pkg_free(script_var->val.s.s);
+               pkg_free(script_var);
+               script_var = script_var2;
+       }
+}
diff --git a/cfg/cfg_script.h b/cfg/cfg_script.h
new file mode 100644 (file)
index 0000000..1bdb3aa
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    info@iptel.org
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History
+ * -------
+ *  2008-01-24 dynamic groups are introduced in order to make
+ *             variable declaration possible in the script (Miklos)
+ */
+
+#ifndef _CFG_SCRIPT_H
+#define _CFG_SCRIPT_H
+
+#include "../str.h"
+
+/* structure used for temporary storing the variables
+ * which are declared in the script */
+typedef struct _cfg_script_var {
+       unsigned int    type;
+       union {
+               str     s;
+               int     i;
+       } val;
+       struct _cfg_script_var  *next;
+       int     name_len;
+       char    *name;
+       char    *descr;
+} cfg_script_var_t;
+
+/* allocates memory for a new config script variable
+ * The value of the variable is not set!
+ */
+cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type,
+                                       char *descr);
+
+/* fix-up the dynamically declared group */
+int cfg_script_fixup(cfg_group_t *group, unsigned char *block);
+
+/* destory a dynamically allocated group definition */
+void cfg_script_destroy(cfg_group_t *group);
+
+#endif /* _CFG_SCRIPT_H */
index dee9ee2..fcb60f2 100644 (file)
@@ -27,6 +27,8 @@
  * History
  * -------
  *  2007-12-03 Initial version (Miklos)
+ *  2008-01-24 dynamic groups are introduced in order to make
+ *             variable declaration possible in the script (Miklos)
  */
 
 #include <string.h>
@@ -36,6 +38,7 @@
 #include "../ut.h"
 #include "../locking.h"
 #include "cfg_ctx.h"
+#include "cfg_script.h"
 #include "cfg_struct.h"
 
 cfg_group_t    *cfg_group = NULL;      /* linked list of registered cfg groups */
@@ -58,38 +61,37 @@ cfg_child_cb_t      **cfg_child_cb_last = NULL;     /* last item of the above list */
 cfg_child_cb_t *cfg_child_cb = NULL;   /* pointer to the previously executed cb */     
 
 /* creates a new cfg group, and adds it to the linked list */
-int cfg_new_group(char *name, int num, cfg_mapping_t *mapping,
+cfg_group_t *cfg_new_group(char *name, int name_len,
+               int num, cfg_mapping_t *mapping,
                char *vars, int size, void **handle)
 {
        cfg_group_t     *group;
-       int             len;
 
        if (cfg_shmized) {
                LOG(L_ERR, "ERROR: cfg_new_group(): too late config declaration\n");
-               return -1;
+               return NULL;
        }
 
-       len = strlen(name);
-       group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+len-1);
+       group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+name_len-1);
        if (!group) {
                LOG(L_ERR, "ERROR: cfg_new_group(): not enough memory\n");
-               return -1;
+               return NULL;
        }
-       memset(group, 0, sizeof(cfg_group_t)+len-1);
+       memset(group, 0, sizeof(cfg_group_t)+name_len-1);
 
        group->num = num;
        group->mapping = mapping;
        group->vars = vars;
        group->size = size;
        group->handle = handle;
-       group->name_len = len;
-       memcpy(&group->name, name, len);
+       group->name_len = name_len;
+       memcpy(&group->name, name, name_len);
 
        /* add the new group to the beginning of the list */
        group->next = cfg_group;
        cfg_group = group;
 
-       return 0;
+       return group;
 }
 
 /* clones a string to shared memory */
@@ -174,13 +176,26 @@ int cfg_shmize(void)
                group;
                group=group->next
        ) {
-               /* clone the strings to shm mem */
-               if (cfg_shmize_strings(group)) goto error;
-
-               /* copy the values to the new block,
-               and update the module's handle */
-               memcpy(block->vars+group->offset, group->vars, group->size);
-               *(group->handle) = block->vars+group->offset;
+               if (group->dynamic == 0) {
+                       /* clone the strings to shm mem */
+                       if (cfg_shmize_strings(group)) goto error;
+
+                       /* copy the values to the new block,
+                       and update the module's handle */
+                       memcpy(block->vars+group->offset, group->vars, group->size);
+                       *(group->handle) = block->vars+group->offset;
+               } else {
+                       /* The group was declared with NULL values,
+                        * we have to fix it up.
+                        * The fixup function takes care about the values,
+                        * it fills up the block */
+                       if (cfg_script_fixup(group, block->vars+group->offset)) goto error;
+                       *(group->handle) = block->vars+group->offset;
+
+                       /* notify the drivers about the new config definition */
+                       cfg_notify_drivers(group->name, group->name_len,
+                                       group->mapping->def);
+               }
        }
 
        /* install the new config */
@@ -194,6 +209,48 @@ error:
        return -1;
 }
 
+/* deallocate the list of groups, and the shmized strings */
+static void cfg_destory_groups(unsigned char *block)
+{
+       cfg_group_t     *group, *group2;
+       cfg_mapping_t   *mapping;
+       cfg_def_t       *def;
+       void            *old_string;
+       int             i;
+
+       group = cfg_group;
+       while(group) {
+               mapping = group->mapping;
+               def = mapping ? mapping->def : NULL;
+
+               /* destory the shmized strings in the block */
+               if (block && def)
+                       for (i=0; i<group->num; i++)
+                               if (((CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) ||
+                               (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR)) &&
+                                       mapping[i].flag & cfg_var_shmized) {
+
+                                               memcpy( &old_string,
+                                                       block + group->offset + mapping[i].offset,
+                                                       sizeof(char *));
+                                               shm_free(old_string);
+                               }
+
+               if (group->dynamic) {
+                       /* the group was dynamically allocated */
+                       cfg_script_destroy(group);
+               } else {
+                       /* only the mapping was allocated, all the other
+                       pointers are just set to static variables */
+                       if (mapping) pkg_free(mapping);
+               }
+
+               group2 = group->next;
+               pkg_free(group);
+               group = group2;
+       }
+}
+
 /* initiate the cfg framework */
 int cfg_init(void)
 {
@@ -264,6 +321,9 @@ void cfg_destroy(void)
        /* free the contexts */
        cfg_ctx_destroy();
 
+       /* free the list of groups */
+       cfg_destory_groups(cfg_global ? (*cfg_global)->vars : NULL);
+
        if (cfg_child_cb_first) {
                if (*cfg_child_cb_first) cfg_child_cb_free(*cfg_child_cb_first);
                shm_free(cfg_child_cb_first);
index e194854..6fbfb15 100644 (file)
@@ -27,6 +27,8 @@
  * History
  * -------
  *  2007-12-03 Initial version (Miklos)
+ *  2008-01-24 dynamic groups are introduced in order to make
+ *             variable declaration possible in the script (Miklos)
  */
 
 #ifndef _CFG_STRUCT_H
@@ -69,6 +71,8 @@ typedef struct _cfg_group {
                                        It is registered when the group is created,
                                        and updated every time the block is replaced */
 
+       unsigned char   dynamic;        /* indicates whether the variables within the group
+                                       are dynamically allocated or not */
        struct _cfg_group       *next;
        int             name_len;       
        char            name[1];
@@ -134,7 +138,8 @@ int cfg_child_init(void);
 void cfg_child_destroy(void);
 
 /* creates a new cfg group, and adds it to the linked list */
-int cfg_new_group(char *name, int num, cfg_mapping_t *mapping,
+cfg_group_t *cfg_new_group(char *name, int name_len,
+               int num, cfg_mapping_t *mapping,
                char *vars, int size, void **handle);
 
 /* copy the variables to shm mem */