Browse code

- configuration variables can be declared in the script: <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>");
}
...
}

Miklos Tirpak authored on 24/01/2008 15:36:56
Showing 10 changed files
... ...
@@ -74,6 +74,7 @@
74 74
  *  2007-10-10  added DNS_SEARCH_FMATCH (mma)
75 75
  *  2007-11-28  added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
76 76
  *              LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
77
+ *  2008-01-24  added CFG_DESCRIPTION used by cfg_var (Miklos)
77 78
 */
78 79
 
79 80
 
... ...
@@ -340,6 +341,8 @@ STUN_REFRESH_INTERVAL "stun_refresh_interval"
340 340
 STUN_ALLOW_STUN "stun_allow_stun"
341 341
 STUN_ALLOW_FP "stun_allow_fp"
342 342
 
343
+CFG_DESCRIPTION		"description"|"descr"|"desc"
344
+
343 345
 LOADMODULE	loadmodule
344 346
 MODPARAM        modparam
345 347
 
... ...
@@ -642,6 +645,7 @@ EAT_ABLE	[\ \t\b\r]
642 642
 									return PMTU_DISCOVERY; }
643 643
 <INITIAL>{KILL_TIMEOUT}			{	count(); yylval.strval=yytext;
644 644
 									return KILL_TIMEOUT; }
645
+<INITIAL>{CFG_DESCRIPTION}	{ count(); yylval.strval=yytext; return CFG_DESCRIPTION; }
645 646
 <INITIAL>{LOADMODULE}	{ count(); yylval.strval=yytext; return LOADMODULE; }
646 647
 <INITIAL>{MODPARAM}     { count(); yylval.strval=yytext; return MODPARAM; }
647 648
 
... ...
@@ -87,6 +87,7 @@
87 87
  * 2007-10-10  added DNS_SEARCH_FMATCH (mma)
88 88
  * 2007-11-28  added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
89 89
  *              LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
90
+ * 2008-01-24  added cfg_var definition (Miklos)
90 91
 */
91 92
 
92 93
 %{
... ...
@@ -118,6 +119,7 @@
118 118
 
119 119
 #include "config.h"
120 120
 #include "cfg_core.h"
121
+#include "cfg/cfg.h"
121 122
 #ifdef CORE_TLS
122 123
 #include "tls/tls_config.h"
123 124
 #endif
... ...
@@ -380,6 +382,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
380 380
 %token TOS
381 381
 %token PMTU_DISCOVERY
382 382
 %token KILL_TIMEOUT
383
+%token CFG_DESCRIPTION
383 384
 
384 385
 %token FLAGS_DECL
385 386
 %token AVPFLAGS_DECL
... ...
@@ -1102,8 +1105,24 @@ assign_stm:
1102 1102
 	| STUN_ALLOW_STUN EQUAL error{ yyerror("number expected"); }
1103 1103
 	| STUN_ALLOW_FP EQUAL NUMBER { IF_STUN(stun_allow_fp=$3) ; }
1104 1104
 	| STUN_ALLOW_FP EQUAL error{ yyerror("number expected"); }
1105
+	| cfg_var
1105 1106
 	| error EQUAL { yyerror("unknown config variable"); }
1106 1107
 	;
1108
+cfg_var:
1109
+	ID DOT ID EQUAL NUMBER {
1110
+		cfg_declare_int($1, $3, $5, NULL);
1111
+	}
1112
+	| ID DOT ID EQUAL STRING {
1113
+		cfg_declare_str($1, $3, $5, NULL);
1114
+	}
1115
+	| ID DOT ID EQUAL NUMBER CFG_DESCRIPTION STRING {
1116
+		cfg_declare_int($1, $3, $5, $7);
1117
+	}
1118
+	| ID DOT ID EQUAL STRING CFG_DESCRIPTION STRING {
1119
+		cfg_declare_str($1, $3, $5, $7);
1120
+	}
1121
+	| ID DOT ID EQUAL error { yyerror("number or string expected"); }
1122
+	;
1107 1123
 module_stm:
1108 1124
 	LOADMODULE STRING {
1109 1125
 		DBG("loading module %s\n", $2);
... ...
@@ -35,6 +35,7 @@
35 35
 #include "../mem/mem.h"
36 36
 #include "cfg_struct.h"
37 37
 #include "cfg_ctx.h"
38
+#include "cfg_script.h"
38 39
 #include "cfg.h"
39 40
 
40 41
 /* declares a new cfg group
... ...
@@ -44,7 +45,7 @@
44 44
 int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
45 45
 			void **handle)
46 46
 {
47
-	int	i, num, size;
47
+	int	i, num, size, group_name_len;
48 48
 	cfg_mapping_t	*mapping = NULL;
49 49
 
50 50
 	/* 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,
120 120
 		goto error;
121 121
 	}
122 122
 
123
+	group_name_len = strlen(group_name);
123 124
 	/* create a new group
124 125
 	I will allocate memory in shm mem for the variables later in a single block,
125 126
 	when we know the size of all the registered groups. */
126
-	if (cfg_new_group(group_name, num, mapping, values, size, handle))
127
+	if (!cfg_new_group(group_name, group_name_len, num, mapping, values, size, handle))
127 128
 		goto error;
128 129
 
129 130
 	/* 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,
133 133
 	*handle = values;
134 134
 
135 135
 	/* notify the drivers about the new config definition */
136
-	cfg_notify_drivers(group_name, def);
136
+	cfg_notify_drivers(group_name, group_name_len, def);
137 137
 
138 138
 	LOG(L_DBG, "DEBUG: register_cfg_def(): "
139 139
 		"new config group has been registered: '%s' (num=%d, size=%d)\n",
140 140
 		group_name, num, size);
141 141
 
142
-	/* TODO: inform the drivers about the new definition */
143
-
144 142
 	return 0;
145 143
 
146 144
 error:
... ...
@@ -150,3 +150,42 @@ error:
150 150
 
151 151
 	return -1;
152 152
 }
153
+
154
+/* declares a single variable with integer type */
155
+int cfg_declare_int(char *group_name, char *var_name, int val, char *descr)
156
+{
157
+	cfg_script_var_t	*var;
158
+
159
+	if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_INT, descr)) == NULL)
160
+		return -1;
161
+
162
+	var->val.i = val;
163
+
164
+	return 0;
165
+}
166
+
167
+/* declares a single variable with str type */
168
+int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr)
169
+{
170
+	cfg_script_var_t	*var;
171
+	int	len;
172
+
173
+	if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_STR, descr)) == NULL)
174
+		return -1;
175
+
176
+	if (val) {
177
+		len = strlen(val);
178
+		var->val.s.s = (char *)pkg_malloc(sizeof(char) * (len + 1));
179
+		if (!var->val.s.s) {
180
+			LOG(L_ERR, "ERROR: cfg_declare_str(): not enough memory\n");
181
+			return -1;
182
+		}
183
+		memcpy(var->val.s.s, val, len + 1);
184
+		var->val.s.len = len;
185
+	} else {	
186
+		var->val.s.s = NULL;
187
+		var->val.s.len = 0;
188
+	}
189
+
190
+	return 0;
191
+}
... ...
@@ -49,7 +49,7 @@
49 49
 typedef int (*cfg_on_change)(void *, str *, void **);
50 50
 typedef void (*cfg_on_set_child)(str *);
51 51
 
52
-/* strutrure to be used buy the module interface */
52
+/* strutrure to be used by the module interface */
53 53
 typedef struct _cfg_def {
54 54
 	char	*name;
55 55
 	unsigned int	type;
... ...
@@ -73,4 +73,10 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
73 73
 #define cfg_get(gname, handle, var) \
74 74
 	((struct cfg_group_##gname *)handle)->var
75 75
 
76
+/* declares a single variable with integer type */
77
+int cfg_declare_int(char *group_name, char *var_name, int val, char *descr);
78
+
79
+/* declares a single variable with str type */
80
+int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr);
81
+
76 82
 #endif /* _CFG_H */
... ...
@@ -73,6 +73,10 @@ cfg_ctx_t *cfg_register_ctx(cfg_on_declare on_declare_cb)
73 73
 			group;
74 74
 			group = group->next
75 75
 		) {
76
+			/* dynamic groups are not ready, the callback
77
+			will be called later when the group is fixed-up */
78
+			if (group->dynamic) continue;
79
+
76 80
 			gname.s = group->name;
77 81
 			gname.len = group->name_len;
78 82
 			on_declare_cb(&gname, group->mapping->def);
... ...
@@ -98,13 +102,13 @@ void cfg_ctx_destroy(void)
98 98
 }
99 99
 
100 100
 /* notify the drivers about the new config definition */
101
-void cfg_notify_drivers(char *group_name, cfg_def_t *def)
101
+void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def)
102 102
 {
103 103
 	cfg_ctx_t	*ctx;
104 104
 	str		gname;
105 105
 
106 106
 	gname.s = group_name;
107
-	gname.len = strlen(group_name);
107
+	gname.len = group_name_len;
108 108
 
109 109
 	for (	ctx = cfg_ctx_list;
110 110
 		ctx;
... ...
@@ -227,8 +231,10 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
227 227
 
228 228
 		p = block->vars+group->offset+var->offset;
229 229
 	} else {
230
-		/* we are allowed to rewrite the value on-the-fly */
231
-		p = group->vars + var->offset;
230
+		/* we are allowed to rewrite the value on-the-fly
231
+		The handle either points to group->vars, or to the
232
+		shared memory block (dynamic group) */
233
+		p = *(group->handle) + var->offset;
232 234
 	}
233 235
 
234 236
 	/* set the new value */
... ...
@@ -277,6 +283,10 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
277 277
 		cfg_install_global(block, replaced, child_cb, child_cb);
278 278
 		CFG_WRITER_UNLOCK();
279 279
 	} else {
280
+		/* cfg_set() may be called more than once before forking */
281
+		if (old_string && (var->flag & cfg_var_shmized))
282
+			shm_free(old_string);
283
+
280 284
 		/* flag the variable because there is no need
281 285
 		to shmize it again */
282 286
 		var->flag |= cfg_var_shmized;
... ...
@@ -104,7 +104,7 @@ int cfg_help(cfg_ctx_t *ctx, str *group_name, str *var_name,
104 104
 			char **ch, unsigned int *input_type);
105 105
 
106 106
 /* notify the drivers about the new config definition */
107
-void cfg_notify_drivers(char *group_name, cfg_def_t *def);
107
+void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def);
108 108
 
109 109
 /* initialize the handle for cfg_get_group_next() */
110 110
 #define cfg_get_group_init(handle) \
111 111
new file mode 100644
... ...
@@ -0,0 +1,274 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2008 iptelorg GmbH
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ *
26
+ * History
27
+ * -------
28
+ *  2008-01-24	dynamic groups are introduced in order to make
29
+ *		variable declaration possible in the script (Miklos)
30
+ */
31
+
32
+#include <string.h>
33
+
34
+#include "../mem/mem.h"
35
+#include "../ut.h"
36
+#include "cfg_struct.h"
37
+#include "cfg_script.h"
38
+
39
+/* allocates memory for a new config script variable
40
+ * The value of the variable is not set!
41
+ */
42
+cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type,
43
+					char *descr)
44
+{
45
+	cfg_group_t	*group;
46
+	cfg_script_var_t	*var;
47
+	int	gname_len, vname_len, descr_len;
48
+
49
+	LOG(L_DBG, "DEBUG: new_cfg_script_var(): declaring %s.%s\n", gname, vname);
50
+
51
+	if (cfg_shmized) {
52
+		LOG(L_ERR, "ERROR: new_cfg_script_var(): too late variable declaration, "
53
+			"the config has been already shmized\n");
54
+		return NULL;
55
+	}
56
+
57
+	gname_len = strlen(gname);
58
+	/* the group may have been already declared */
59
+	for (	group = cfg_group;
60
+		group;
61
+		group = group->next
62
+	) {
63
+		if ((group->name_len == gname_len) &&
64
+		(memcmp(group->name, gname, gname_len) == 0)) {
65
+			if (group->dynamic == 0) {
66
+				/* the group has been already declared by a module or by the core */
67
+				LOG(L_ERR, "ERROR: new_cfg_script_var(): "
68
+					"configuration group has been already declared: %s\n",
69
+					gname);
70
+				return NULL;
71
+			}
72
+			/* the dynamic group is found */
73
+			break;
74
+		}
75
+	}
76
+
77
+	if (!group) {
78
+		/* create a new group with NULL values, we will fix it later,
79
+		when all the variables are known */
80
+		group = cfg_new_group(gname, gname_len,
81
+					0 /* num */, NULL /* mapping */,
82
+					NULL /* vars */, 0 /* size */, NULL /* handle */);
83
+					
84
+		if (!group) goto error;
85
+		group->dynamic = 1;
86
+	}
87
+
88
+	/* verify that the variable does not exist */
89
+	vname_len = strlen(vname);
90
+
91
+	for (	var = (cfg_script_var_t *)group->vars;
92
+		var;
93
+		var = var->next
94
+	) {
95
+		if ((var->name_len == vname_len) &&
96
+		(memcmp(var->name, vname, vname_len) == 0)) {
97
+			LOG(L_ERR, "ERROR: new_cfg_script_var(): variable already exists: %s.%s\n",
98
+					gname, vname);
99
+			return NULL;
100
+		}
101
+	}
102
+
103
+	switch (type) {
104
+	case CFG_VAR_INT:
105
+		group->size = ROUND_INT(group->size);
106
+		group->size += sizeof(int);
107
+		break;
108
+
109
+	case CFG_VAR_STR:
110
+		group->size = ROUND_POINTER(group->size);
111
+		group->size += sizeof(str);
112
+		break;
113
+
114
+	default:
115
+		LOG(L_ERR, "ERROR: new_cfg_script_var(): unsupported variable type\n");
116
+		return NULL;
117
+	}
118
+	group->num++;
119
+
120
+	var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t));
121
+	if (!var) goto error;
122
+	memset(var, sizeof(cfg_script_var_t), 0);
123
+	var->type = type;
124
+
125
+	/* add the variable to the group */
126
+	var->next = (cfg_script_var_t *)(void *)group->vars;
127
+	group->vars = (char *)(void *)var;
128
+
129
+	/* clone the name of the variable */
130
+	var->name = (char *)pkg_malloc(sizeof(char) * (vname_len + 1));
131
+	if (!var->name) goto error;
132
+	memcpy(var->name, vname, vname_len + 1);
133
+	var->name_len = vname_len;
134
+
135
+	if (descr) {
136
+		/* save the description */
137
+		descr_len = strlen(descr);
138
+		var->descr = (char *)pkg_malloc(sizeof(char) * (descr_len + 1));
139
+		if (!var->descr) goto error;
140
+		memcpy(var->descr, descr, descr_len + 1);
141
+	}
142
+
143
+	return var;
144
+
145
+error:
146
+	LOG(L_ERR, "ERROR: new_cfg_script_var(): not enough memory\n");
147
+	return NULL;
148
+}
149
+
150
+/* fix-up the dynamically declared group:
151
+ *  - allocate memory for the arrays
152
+ *  - set the values within the memory block
153
+ *  - notify the drivers about the new group
154
+ */
155
+int cfg_script_fixup(cfg_group_t *group, unsigned char *block)
156
+{
157
+	cfg_mapping_t		*mapping = NULL;
158
+	cfg_def_t		*def = NULL;
159
+	void			**handle = NULL;
160
+	int			i, offset;
161
+	cfg_script_var_t	*script_var, *script_var2;
162
+	str			s;
163
+
164
+	mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*group->num);
165
+	if (!mapping) goto error;
166
+	memset(mapping, 0, sizeof(cfg_mapping_t)*group->num);
167
+
168
+	/* The variable definition array must look like as if it was declared
169
+	 * in C code, thus, add an additional slot at the end with NULL values */
170
+	def = (cfg_def_t *)pkg_malloc(sizeof(cfg_def_t)*(group->num + 1));
171
+	if (!def) goto error;
172
+	memset(def, 0, sizeof(cfg_def_t)*(group->num + 1));
173
+
174
+	/* fill the definition and the mapping arrays */
175
+	offset = 0;
176
+	for (	i = 0, script_var = (cfg_script_var_t *)group->vars;
177
+		script_var;
178
+		i++, script_var = script_var->next
179
+	) {
180
+		/* there has been already memory allocated for the name */
181
+		def[i].name = script_var->name;
182
+		def[i].type = script_var->type | (script_var->type << 3);
183
+		def[i].descr = script_var->descr;
184
+
185
+		mapping[i].def = &(def[i]);
186
+		mapping[i].name_len = script_var->name_len;
187
+
188
+		switch (script_var->type) {
189
+		case CFG_VAR_INT:
190
+			offset = ROUND_INT(offset);
191
+			mapping[i].offset = offset;
192
+
193
+			memcpy(block + offset, &script_var->val.i, sizeof(int));
194
+
195
+			offset += sizeof(int);
196
+			break;
197
+
198
+		case CFG_VAR_STR:
199
+			offset = ROUND_POINTER(offset);
200
+			mapping[i].offset = offset;
201
+
202
+			if (!(s.s = cfg_clone_str(script_var->val.s))) goto error;
203
+			s.len = script_var->val.s.len;
204
+			memcpy(block + offset, &s, sizeof(str));
205
+			mapping[i].flag |= cfg_var_shmized;
206
+
207
+			offset += sizeof(str);
208
+			break;
209
+		}
210
+	}
211
+
212
+	/* allocate a handle even if it will not be used to
213
+	directly access the variable, like handle->variable
214
+	cfg_get_* functions access the memory block via the handle
215
+	to make sure that it is always safe, thus, it must be created */
216
+	handle = (void **)pkg_malloc(sizeof(void *));
217
+	if (!handle) goto error;
218
+	*handle = NULL;
219
+	group->handle = handle;
220
+
221
+	group->mapping = mapping;
222
+
223
+	/* everything went fine, we can free the temporary list */
224
+	script_var = (cfg_script_var_t *)group->vars;
225
+	group->vars = NULL;
226
+	while (script_var) {
227
+		script_var2 = script_var->next;
228
+		if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s)
229
+			pkg_free(script_var->val.s.s);
230
+		pkg_free(script_var);
231
+		script_var = script_var2;
232
+	}
233
+
234
+	return 0;
235
+
236
+error:
237
+	if (mapping) pkg_free(mapping);
238
+	if (def) pkg_free(def);
239
+	if (handle) pkg_free(handle);
240
+
241
+	LOG(L_ERR, "ERROR: cfg_script_fixup(): not enough memory\n");
242
+	return -1;
243
+}
244
+
245
+/* destory a dynamically allocated group definition */
246
+void cfg_script_destroy(cfg_group_t *group)
247
+{
248
+	int	i;
249
+	cfg_script_var_t	*script_var, *script_var2;
250
+
251
+	if (group->mapping && group->mapping->def) {
252
+		for (i=0; i<group->num; i++) {
253
+			if (group->mapping->def[i].name)
254
+				pkg_free(group->mapping->def[i].name);
255
+			if (group->mapping->def[i].descr)
256
+				pkg_free(group->mapping->def[i].descr);
257
+		}
258
+		pkg_free(group->mapping->def);
259
+	}
260
+	if (group->mapping) pkg_free(group->mapping);
261
+	if (group->handle) pkg_free(group->handle);
262
+
263
+	/* it may happen that the the temporary var list
264
+	still exists because the fixup failed and did not complete */
265
+	script_var = (cfg_script_var_t *)group->vars;
266
+	while (script_var) {
267
+		script_var2 = script_var->next;
268
+		if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s) 
269
+			pkg_free(script_var->val.s.s);
270
+		pkg_free(script_var);
271
+		script_var = script_var2;
272
+	}
273
+}
0 274
new file mode 100644
... ...
@@ -0,0 +1,64 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2008 iptelorg GmbH
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ *
26
+ * History
27
+ * -------
28
+ *  2008-01-24	dynamic groups are introduced in order to make
29
+ *		variable declaration possible in the script (Miklos)
30
+ */
31
+
32
+#ifndef _CFG_SCRIPT_H
33
+#define _CFG_SCRIPT_H
34
+
35
+#include "../str.h"
36
+
37
+/* structure used for temporary storing the variables
38
+ * which are declared in the script */
39
+typedef struct _cfg_script_var {
40
+	unsigned int	type;
41
+	union {
42
+		str	s;
43
+		int	i;
44
+	} val;
45
+	struct _cfg_script_var	*next;
46
+	int	name_len;
47
+	char	*name;
48
+	char	*descr;
49
+} cfg_script_var_t;
50
+
51
+/* allocates memory for a new config script variable
52
+ * The value of the variable is not set!
53
+ */
54
+cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type,
55
+					char *descr);
56
+
57
+/* fix-up the dynamically declared group */
58
+int cfg_script_fixup(cfg_group_t *group, unsigned char *block);
59
+
60
+/* destory a dynamically allocated group definition */
61
+void cfg_script_destroy(cfg_group_t *group);
62
+
63
+#endif /* _CFG_SCRIPT_H */
... ...
@@ -27,6 +27,8 @@
27 27
  * History
28 28
  * -------
29 29
  *  2007-12-03	Initial version (Miklos)
30
+ *  2008-01-24	dynamic groups are introduced in order to make
31
+ *		variable declaration possible in the script (Miklos)
30 32
  */
31 33
 
32 34
 #include <string.h>
... ...
@@ -36,6 +38,7 @@
36 36
 #include "../ut.h"
37 37
 #include "../locking.h"
38 38
 #include "cfg_ctx.h"
39
+#include "cfg_script.h"
39 40
 #include "cfg_struct.h"
40 41
 
41 42
 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 */
58 58
 cfg_child_cb_t	*cfg_child_cb = NULL;	/* pointer to the previously executed cb */	
59 59
 
60 60
 /* creates a new cfg group, and adds it to the linked list */
61
-int cfg_new_group(char *name, int num, cfg_mapping_t *mapping,
61
+cfg_group_t *cfg_new_group(char *name, int name_len,
62
+		int num, cfg_mapping_t *mapping,
62 63
 		char *vars, int size, void **handle)
63 64
 {
64 65
 	cfg_group_t	*group;
65
-	int		len;
66 66
 
67 67
 	if (cfg_shmized) {
68 68
 		LOG(L_ERR, "ERROR: cfg_new_group(): too late config declaration\n");
69
-		return -1;
69
+		return NULL;
70 70
 	}
71 71
 
72
-	len = strlen(name);
73
-	group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+len-1);
72
+	group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+name_len-1);
74 73
 	if (!group) {
75 74
 		LOG(L_ERR, "ERROR: cfg_new_group(): not enough memory\n");
76
-		return -1;
75
+		return NULL;
77 76
 	}
78
-	memset(group, 0, sizeof(cfg_group_t)+len-1);
77
+	memset(group, 0, sizeof(cfg_group_t)+name_len-1);
79 78
 
80 79
 	group->num = num;
81 80
 	group->mapping = mapping;
82 81
 	group->vars = vars;
83 82
 	group->size = size;
84 83
 	group->handle = handle;
85
-	group->name_len = len;
86
-	memcpy(&group->name, name, len);
84
+	group->name_len = name_len;
85
+	memcpy(&group->name, name, name_len);
87 86
 
88 87
 	/* add the new group to the beginning of the list */
89 88
 	group->next = cfg_group;
90 89
 	cfg_group = group;
91 90
 
92
-	return 0;
91
+	return group;
93 92
 }
94 93
 
95 94
 /* clones a string to shared memory */
... ...
@@ -174,13 +176,26 @@ int cfg_shmize(void)
174 174
 		group;
175 175
 		group=group->next
176 176
 	) {
177
-		/* clone the strings to shm mem */
178
-		if (cfg_shmize_strings(group)) goto error;
179
-
180
-		/* copy the values to the new block,
181
-		and update the module's handle */
182
-		memcpy(block->vars+group->offset, group->vars, group->size);
183
-		*(group->handle) = block->vars+group->offset;
177
+		if (group->dynamic == 0) {
178
+			/* clone the strings to shm mem */
179
+			if (cfg_shmize_strings(group)) goto error;
180
+
181
+			/* copy the values to the new block,
182
+			and update the module's handle */
183
+			memcpy(block->vars+group->offset, group->vars, group->size);
184
+			*(group->handle) = block->vars+group->offset;
185
+		} else {
186
+			/* The group was declared with NULL values,
187
+			 * we have to fix it up.
188
+			 * The fixup function takes care about the values,
189
+			 * it fills up the block */
190
+			if (cfg_script_fixup(group, block->vars+group->offset)) goto error;
191
+			*(group->handle) = block->vars+group->offset;
192
+
193
+			/* notify the drivers about the new config definition */
194
+			cfg_notify_drivers(group->name, group->name_len,
195
+					group->mapping->def);
196
+		}
184 197
 	}
185 198
 
186 199
 	/* install the new config */
... ...
@@ -194,6 +209,48 @@ error:
194 194
 	return -1;
195 195
 }
196 196
 
197
+/* deallocate the list of groups, and the shmized strings */
198
+static void cfg_destory_groups(unsigned char *block)
199
+{
200
+	cfg_group_t	*group, *group2;
201
+	cfg_mapping_t	*mapping;
202
+	cfg_def_t	*def;
203
+	void		*old_string;
204
+	int		i;
205
+
206
+	group = cfg_group;
207
+	while(group) {
208
+		mapping = group->mapping;
209
+		def = mapping ? mapping->def : NULL;
210
+
211
+		/* destory the shmized strings in the block */
212
+		if (block && def)
213
+			for (i=0; i<group->num; i++)
214
+				if (((CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) ||
215
+				(CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR)) &&
216
+					mapping[i].flag & cfg_var_shmized) {
217
+
218
+						memcpy(	&old_string,
219
+							block + group->offset + mapping[i].offset,
220
+							sizeof(char *));
221
+						shm_free(old_string);
222
+				}
223
+
224
+		if (group->dynamic) {
225
+			/* the group was dynamically allocated */
226
+			cfg_script_destroy(group);
227
+		} else {
228
+			/* only the mapping was allocated, all the other
229
+			pointers are just set to static variables */
230
+			if (mapping) pkg_free(mapping);
231
+		}
232
+
233
+		group2 = group->next;
234
+		pkg_free(group);
235
+		group = group2;
236
+	}
237
+}
238
+
197 239
 /* initiate the cfg framework */
198 240
 int cfg_init(void)
199 241
 {
... ...
@@ -264,6 +321,9 @@ void cfg_destroy(void)
264 264
 	/* free the contexts */
265 265
 	cfg_ctx_destroy();
266 266
 
267
+	/* free the list of groups */
268
+	cfg_destory_groups(cfg_global ? (*cfg_global)->vars : NULL);
269
+
267 270
 	if (cfg_child_cb_first) {
268 271
 		if (*cfg_child_cb_first) cfg_child_cb_free(*cfg_child_cb_first);
269 272
 		shm_free(cfg_child_cb_first);
... ...
@@ -27,6 +27,8 @@
27 27
  * History
28 28
  * -------
29 29
  *  2007-12-03	Initial version (Miklos)
30
+ *  2008-01-24	dynamic groups are introduced in order to make
31
+ *		variable declaration possible in the script (Miklos)
30 32
  */
31 33
 
32 34
 #ifndef _CFG_STRUCT_H
... ...
@@ -69,6 +71,8 @@ typedef struct _cfg_group {
69 69
 					It is registered when the group is created,
70 70
 					and updated every time the block is replaced */
71 71
 
72
+	unsigned char	dynamic;	/* indicates whether the variables within the group
73
+					are dynamically	allocated or not */
72 74
 	struct _cfg_group	*next;
73 75
 	int		name_len;	
74 76
 	char		name[1];
... ...
@@ -134,7 +138,8 @@ int cfg_child_init(void);
134 134
 void cfg_child_destroy(void);
135 135
 
136 136
 /* creates a new cfg group, and adds it to the linked list */
137
-int cfg_new_group(char *name, int num, cfg_mapping_t *mapping,
137
+cfg_group_t *cfg_new_group(char *name, int name_len,
138
+		int num, cfg_mapping_t *mapping,
138 139
 		char *vars, int size, void **handle);
139 140
 
140 141
 /* copy the variables to shm mem */