Browse code

Merge remote branch 'origin/tirpi/cfg_framework_multivalue'

* origin/tirpi/cfg_framework_multivalue: (33 commits)
cfg framework: fix uninitialized group_inst pointers
xmlrpc: scan resets the error code
cfg_rpc: group can be specified for cfg.list
cfg_rpc: cfg.set and cfg.set_delayed commands added
ctl: rpc->scan does not immediately send out errors
cfg_rpc: documentation update - group instances
cfg framework: multiple group instances is documented
cfg framework: timer must reset the handles more frequently
cfg framework: cfg_select() and cfg_reset() added
cfg framework: group handle can be moved runtime
cfg framework: group instance support in the script
cfg framework: apply the values in the order they are set
cfg framework: translate_pointer bugfix
cfg framework: apply additional var list bugfix
cfg framework: apply the additional variable list
cfg framework: group instance support before forking
cfg framework: CFG_GROUP_UNKNOWN group type
cfg framework: cfg_commit() log message fixes
cfg_db: updated to the cfg framework changes
cfg_db: updated to the cfg framework changes
...

Miklos Tirpak authored on 27/10/2010 11:03:59
Showing 23 changed files
... ...
@@ -93,6 +93,7 @@
93 93
 #endif
94 94
 #include "switch.h"
95 95
 #include "events.h"
96
+#include "cfg/cfg_struct.h"
96 97
 
97 98
 #include <sys/types.h>
98 99
 #include <sys/socket.h>
... ...
@@ -1492,6 +1493,40 @@ match_cleanup:
1492 1493
 			msg->rpl_send_flags.f|= SND_F_CON_CLOSE;
1493 1494
 			ret=1; /* continue processing */
1494 1495
 			break;
1496
+		case CFG_SELECT_T:
1497
+			if (a->val[0].type != CFG_GROUP_ST) {
1498
+				BUG("unsupported parameter in CFG_SELECT_T: %d\n",
1499
+						a->val[0].type);
1500
+				ret=-1;
1501
+				goto error;
1502
+			}
1503
+			switch(a->val[1].type) {
1504
+				case NUMBER_ST:
1505
+					v=(int)a->val[1].u.number;
1506
+					break;
1507
+				case RVE_ST:
1508
+					if (rval_expr_eval_int(h, msg, &v, (struct rval_expr*)a->val[1].u.data) < 0) {
1509
+						ret=-1;
1510
+						goto error;
1511
+					}
1512
+					break;
1513
+				default:
1514
+					BUG("unsupported group id type in CFG_SELECT_T: %d\n",
1515
+							a->val[1].type);
1516
+					ret=-1;
1517
+					goto error;
1518
+			}
1519
+			ret=(cfg_select((cfg_group_t*)a->val[0].u.data, v) == 0) ? 1 : -1;
1520
+			break;
1521
+		case CFG_RESET_T:
1522
+			if (a->val[0].type != CFG_GROUP_ST) {
1523
+				BUG("unsupported parameter in CFG_RESET_T: %d\n",
1524
+						a->val[0].type);
1525
+				ret=-1;
1526
+				goto error;
1527
+			}
1528
+			ret=(cfg_reset((cfg_group_t*)a->val[0].u.data) == 0) ? 1 : -1;
1529
+			break;
1495 1530
 /*
1496 1531
 		default:
1497 1532
 			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
... ...
@@ -251,6 +251,9 @@ WHILE			"while"
251 251
 
252 252
 INCLUDEFILE     "include_file"
253 253
 
254
+CFG_SELECT	"cfg_select"
255
+CFG_RESET	"cfg_reset"
256
+
254 257
 /*ACTION LVALUES*/
255 258
 URIHOST			"uri:host"
256 259
 URIPORT			"uri:port"
... ...
@@ -635,6 +638,9 @@ SUBST       subst
635 638
 
636 639
 <INITIAL>{INCLUDEFILE}  { count(); BEGIN(INCLF); }
637 640
 
641
+<INITIAL>{CFG_SELECT}	{ count(); yylval.strval=yytext; return CFG_SELECT; }
642
+<INITIAL>{CFG_RESET}	{ count(); yylval.strval=yytext; return CFG_RESET; }
643
+
638 644
 <INITIAL>{URIHOST}	{ count(); yylval.strval=yytext; return URIHOST; }
639 645
 <INITIAL>{URIPORT}	{ count(); yylval.strval=yytext; return URIPORT; }
640 646
 
... ...
@@ -101,7 +101,7 @@
101 101
  * 2010-02-17  added blacklist imask (DST_BLST_*_IMASK) support (andrei)
102 102
 */
103 103
 
104
-%expect 5
104
+%expect 6
105 105
 
106 106
 %{
107 107
 
... ...
@@ -347,6 +347,8 @@ extern char *finame;
347 347
 %token CASE
348 348
 %token DEFAULT
349 349
 %token WHILE
350
+%token CFG_SELECT
351
+%token CFG_RESET
350 352
 %token URIHOST
351 353
 %token URIPORT
352 354
 %token MAX_LEN
... ...
@@ -1632,6 +1634,16 @@ cfg_var:
1632 1634
 	| cfg_var_id DOT cfg_var_id EQUAL error { 
1633 1635
 		yyerror("number or string expected"); 
1634 1636
 	}
1637
+	| cfg_var_id LBRACK NUMBER RBRACK DOT cfg_var_id EQUAL NUMBER {
1638
+		if (cfg_ginst_var_int($1, $3, $6, $8)) {
1639
+			yyerror("variable cannot be added to the group instance");
1640
+		}
1641
+	}
1642
+	| cfg_var_id LBRACK NUMBER RBRACK DOT cfg_var_id EQUAL STRING {
1643
+		if (cfg_ginst_var_string($1, $3, $6, $8)) {
1644
+			yyerror("variable cannot be added to the group instance");
1645
+		}
1646
+	}
1635 1647
 	;
1636 1648
 
1637 1649
 module_stm:
... ...
@@ -3261,6 +3273,19 @@ cmd:
3261 3273
 	| SET_RPL_CLOSE	{
3262 3274
 		$$=mk_action(SET_RPL_CLOSE_T, 0); set_cfg_pos($$);
3263 3275
 	}
3276
+	| CFG_SELECT LPAREN STRING COMMA NUMBER RPAREN {
3277
+		$$=mk_action(CFG_SELECT_T, 2, STRING_ST, $3, NUMBER_ST, (void*)$5); set_cfg_pos($$);
3278
+	}
3279
+	| CFG_SELECT LPAREN STRING COMMA rval_expr RPAREN {
3280
+		$$=mk_action(CFG_SELECT_T, 2, STRING_ST, $3, RVE_ST, $5); set_cfg_pos($$);
3281
+	}
3282
+	| CFG_SELECT error { $$=0; yyerror("missing '(' or ')' ?"); }
3283
+	| CFG_SELECT LPAREN error RPAREN { $$=0; yyerror("bad arguments, string and number expected"); }
3284
+	| CFG_RESET LPAREN STRING RPAREN {
3285
+		$$=mk_action(CFG_RESET_T, 1, STRING_ST, $3); set_cfg_pos($$);
3286
+	}
3287
+	| CFG_RESET error { $$=0; yyerror("missing '(' or ')' ?"); }
3288
+	| CFG_RESET LPAREN error RPAREN { $$=0; yyerror("bad arguments, string expected"); }
3264 3289
 	| ID {mod_func_action = mk_action(MODULE0_T, 2, MODEXP_ST, NULL, NUMBER_ST,
3265 3290
 			0); } LPAREN func_params RPAREN	{
3266 3291
 		mod_func_action->val[0].u.data =
... ...
@@ -43,6 +43,7 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
43 43
 {
44 44
 	int	i, num, size, group_name_len;
45 45
 	cfg_mapping_t	*mapping = NULL;
46
+	cfg_group_t	*group;
46 47
 	int types;
47 48
 
48 49
 	/* check the number of the variables */
... ...
@@ -61,6 +62,7 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
61 62
 	for (i=0, size=0; i<num; i++) {
62 63
 		mapping[i].def = &(def[i]);
63 64
 		mapping[i].name_len = strlen(def[i].name);
65
+		mapping[i].pos = i;
64 66
 		/* record all the types for sanity checks */
65 67
 		types|=1 << CFG_VAR_MASK(def[i].type);
66 68
 
... ...
@@ -141,18 +143,24 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
141 143
 
142 144
 	group_name_len = strlen(group_name);
143 145
 	/* check for duplicates */
144
-	if (cfg_lookup_group(group_name, group_name_len)) {
145
-		LOG(L_ERR, "ERROR: register_cfg_def(): "
146
-			"configuration group has been already declared: %s\n",
147
-			group_name);
148
-		goto error;
146
+	if ((group = cfg_lookup_group(group_name, group_name_len))) {
147
+		if (group->dynamic != CFG_GROUP_UNKNOWN) {
148
+			/* conflict with another module/core group, or with a dynamic group */
149
+			LOG(L_ERR, "ERROR: register_cfg_def(): "
150
+				"configuration group has been already declared: %s\n",
151
+				group_name);
152
+			goto error;
153
+		}
154
+		/* An empty group is found which does not have any variable yet */
155
+		cfg_set_group(group, num, mapping, values, size, handle);
156
+	} else {
157
+		/* create a new group
158
+		I will allocate memory in shm mem for the variables later in a single block,
159
+		when we know the size of all the registered groups. */
160
+		if (!(group = cfg_new_group(group_name, group_name_len, num, mapping, values, size, handle)))
161
+			goto error;
149 162
 	}
150
-
151
-	/* create a new group
152
-	I will allocate memory in shm mem for the variables later in a single block,
153
-	when we know the size of all the registered groups. */
154
-	if (!cfg_new_group(group_name, group_name_len, num, mapping, values, size, handle))
155
-		goto error;
163
+	group->dynamic = CFG_GROUP_STATIC;
156 164
 
157 165
 	/* The cfg variables are ready to use, let us set the handle
158 166
 	before passing the new definitions to the drivers.
... ...
@@ -219,13 +227,63 @@ int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr)
219 227
 	return 0;
220 228
 }
221 229
 
230
+/* Add a varibale to a group instance with integer type.
231
+ * The group instance is created if it does not exist.
232
+ * wrapper function for new_add_var()
233
+ */
234
+int cfg_ginst_var_int(char *group_name, unsigned int group_id, char *var_name,
235
+			int val)
236
+{
237
+	str	gname, vname;
238
+
239
+	gname.s = group_name;
240
+	gname.len = strlen(group_name);
241
+	vname.s = var_name;
242
+	vname.len = strlen(var_name);
243
+
244
+	return new_add_var(&gname, group_id, &vname,
245
+			(void *)(long)val, CFG_VAR_INT);
246
+}
247
+
248
+/* Add a varibale to a group instance with string type.
249
+ * The group instance is created if it does not exist.
250
+ * wrapper function for new_add_var()
251
+ */
252
+int cfg_ginst_var_string(char *group_name, unsigned int group_id, char *var_name,
253
+			char *val)
254
+{
255
+	str	gname, vname;
256
+
257
+	gname.s = group_name;
258
+	gname.len = strlen(group_name);
259
+	vname.s = var_name;
260
+	vname.len = strlen(var_name);
261
+
262
+	return new_add_var(&gname, group_id, &vname,
263
+			(void *)val, CFG_VAR_STRING);
264
+}
265
+
266
+/* Create a new group instance.
267
+ * wrapper function for new_add_var()
268
+ */
269
+int cfg_new_ginst(char *group_name, unsigned int group_id)
270
+{
271
+	str	gname;
272
+
273
+	gname.s = group_name;
274
+	gname.len = strlen(group_name);
275
+
276
+	return new_add_var(&gname, group_id, NULL /* var */,
277
+			NULL /* val */, 0 /* type */);
278
+}
279
+
222 280
 /* returns the handle of a cfg group */
223 281
 void **cfg_get_handle(char *gname)
224 282
 {
225 283
 	cfg_group_t	*group;
226 284
 
227 285
 	group = cfg_lookup_group(gname, strlen(gname));
228
-	if (!group || group->dynamic) return NULL;
286
+	if (!group || (group->dynamic != CFG_GROUP_STATIC)) return NULL;
229 287
 
230 288
 	return group->handle;
231 289
 }
... ...
@@ -87,6 +87,25 @@ int cfg_declare_int(char *group_name, char *var_name,
87 87
 /* declares a single variable with str type */
88 88
 int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr);
89 89
 
90
+/* Add a varibale to a group instance with integer type.
91
+ * The group instance is created if it does not exist.
92
+ * wrapper function for new_add_var()
93
+ */
94
+int cfg_ginst_var_int(char *group_name, unsigned int group_id, char *var_name,
95
+			int val);
96
+
97
+/* Add a varibale to a group instance with string type.
98
+ * The group instance is created if it does not exist.
99
+ * wrapper function for new_add_var()
100
+ */
101
+int cfg_ginst_var_string(char *group_name, unsigned int group_id, char *var_name,
102
+			char *val);
103
+
104
+/* Create a new group instance.
105
+ * wrapper function for new_add_var()
106
+ */
107
+int cfg_new_ginst(char *group_name, unsigned int group_id);
108
+
90 109
 /* returns the handle of a cfg group */
91 110
 void **cfg_get_handle(char *gname);
92 111
 
... ...
@@ -77,7 +77,7 @@ int cfg_register_ctx(cfg_ctx_t **handle, cfg_on_declare on_declare_cb)
77 77
 		) {
78 78
 			/* dynamic groups are not ready, the callback
79 79
 			will be called later when the group is fixed-up */
80
-			if (group->dynamic) continue;
80
+			if (group->dynamic != CFG_GROUP_STATIC) continue;
81 81
 
82 82
 			gname.s = group->name;
83 83
 			gname.len = group->name_len;
... ...
@@ -239,6 +239,66 @@ error:
239 239
 		} \
240 240
 	} while(0)
241 241
 
242
+/* returns the size of the variable */
243
+static int cfg_var_size(cfg_mapping_t *var)
244
+{
245
+	switch (CFG_VAR_TYPE(var)) {
246
+
247
+	case CFG_VAR_INT:
248
+		return sizeof(int);
249
+
250
+	case CFG_VAR_STRING:
251
+		return sizeof(char *);
252
+
253
+	case CFG_VAR_STR:
254
+		return sizeof(str);
255
+
256
+	case CFG_VAR_POINTER:
257
+		return sizeof(void *);
258
+
259
+	default:
260
+		LOG(L_CRIT, "BUG: cfg_var_size(): unknown type: %u\n",
261
+			CFG_VAR_TYPE(var));
262
+		return 0;
263
+	}
264
+}
265
+
266
+/* Update the varibales of the array within the meta structure
267
+ * with the new default value.
268
+ * The array is cloned before a change if clone is set to 1.
269
+ */
270
+static int cfg_update_defaults(cfg_group_meta_t	*meta,
271
+				cfg_group_t *group, cfg_mapping_t *var, char *new_val,
272
+				int clone)
273
+{
274
+	int	i, clone_done=0;
275
+	cfg_group_inst_t *array, *ginst;
276
+
277
+	if (!(array = meta->array))
278
+		return 0;
279
+	for (i = 0; i < meta->num; i++) {
280
+		ginst = (cfg_group_inst_t *)((char *)array
281
+			+ (sizeof(cfg_group_inst_t) + group->size - 1) * i);
282
+
283
+		if (!CFG_VAR_TEST(ginst, var)) {
284
+			/* The variable uses the default value, it needs to be rewritten. */
285
+			if (clone && !clone_done) {
286
+				/* The array needs to be cloned before the modification */
287
+				if (!(array = cfg_clone_array(meta, group)))
288
+					return -1;
289
+				ginst = (cfg_group_inst_t *)translate_pointer((char *)array,
290
+								(char *)meta->array,
291
+								(char *)ginst);
292
+				/* re-link the array to the meta-data */
293
+				meta->array = array;
294
+				clone_done = 1;
295
+			}
296
+			memcpy(ginst->vars + var->offset, new_val, cfg_var_size(var)); 
297
+		}
298
+	}
299
+	return 0;
300
+}
301
+
242 302
 /* sets the value of a variable without the need of commit
243 303
  *
244 304
  * return value:
... ...
@@ -246,17 +306,20 @@ error:
246 306
  *  -1: error
247 307
  *   1: variable has not been found
248 308
  */
249
-int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
309
+int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
250 310
 			void *val, unsigned int val_type)
251 311
 {
312
+	int		i;
252 313
 	cfg_group_t	*group;
253 314
 	cfg_mapping_t	*var;
254 315
 	void		*p, *v;
255 316
 	cfg_block_t	*block = NULL;
256 317
 	str		s, s2;
257 318
 	char		*old_string = NULL;
258
-	char		**replaced = NULL;
319
+	void		**replaced = NULL;
259 320
 	cfg_child_cb_t	*child_cb = NULL;
321
+	cfg_group_inst_t	*group_inst = NULL, *new_array = NULL;
322
+	unsigned char		*var_block;
260 323
 
261 324
 	/* verify the context even if we do not need it now
262 325
 	to make sure that a cfg driver has called the function
... ...
@@ -266,6 +329,15 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
266 329
 		return -1;
267 330
 	}
268 331
 
332
+	if (group_id && !cfg_shmized) {
333
+		/* The config group has not been shmized yet,
334
+		but an additional instance of a variable needs to be added to the group.
335
+		Add this instance to the linked list of variables, they
336
+		will be fixed later. */
337
+		return new_add_var(group_name, *group_id, var_name,
338
+				val, val_type);
339
+	}
340
+
269 341
 	/* look-up the group and the variable */
270 342
 	if (cfg_lookup_var(group_name, var_name, &group, &var))
271 343
 		return 1;
... ...
@@ -276,6 +348,19 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
276 348
 		goto error0;
277 349
 	}
278 350
 
351
+	/* The additional variable instances having per-child process callback
352
+	 * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
353
+	 * The reason is that such variables typically set global parameters
354
+	 * as opposed to per-process variables. Hence, it is not possible to set
355
+	 * the group handle temporary to another block, and then reset it back later. */
356
+	if (group_id
357
+		&& var->def->on_set_child_cb
358
+		&& var->def->type & CFG_CB_ONLY_ONCE
359
+	) {
360
+		LOG(L_ERR, "ERROR: cfg_set_now(): This variable does not support muliple values.\n");
361
+		goto error0;
362
+	}
363
+
279 364
 	/* check whether we have to convert the type */
280 365
 	if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
281 366
 		goto error0;
... ...
@@ -294,7 +379,25 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
294 379
 		/* Call the fixup function.
295 380
 		There is no need to set a temporary cfg handle,
296 381
 		becaue a single variable is changed */
297
-		if (var->def->on_change_cb(*(group->handle),
382
+		if (!group_id) {
383
+			var_block = *(group->handle);
384
+		} else {
385
+			if (!cfg_local) {
386
+				LOG(L_ERR, "ERROR: cfg_set_now(): Local configuration is missing\n");
387
+				goto error0;
388
+			}
389
+			group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
390
+							group->size,
391
+							*group_id);
392
+			if (!group_inst) {
393
+				LOG(L_ERR, "ERROR: cfg_set_now(): local group instance %.*s[%u] is not found\n",
394
+					group_name->len, group_name->s, *group_id);
395
+				goto error0;
396
+			}
397
+			var_block = group_inst->vars;
398
+		}
399
+
400
+		if (var->def->on_change_cb(var_block,
298 401
 						group_name,
299 402
 						var_name,
300 403
 						&v) < 0) {
... ...
@@ -304,7 +407,10 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
304 407
 
305 408
 	}
306 409
 
307
-	if (var->def->on_set_child_cb) {
410
+	/* Set the per-child process callback only if the default value is changed.
411
+	 * The callback of other instances will be called when the config is
412
+	 * switched to that instance. */
413
+	if (!group_id && var->def->on_set_child_cb) {
308 414
 		/* get the name of the variable from the internal struct,
309 415
 		because var_name may be freed before the callback needs it */
310 416
 		s.s = group->name;
... ...
@@ -325,16 +431,51 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
325 431
 		while the new one is prepared */
326 432
 		CFG_WRITER_LOCK();
327 433
 
434
+		if (group_id) {
435
+			group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group),
436
+							group->size,
437
+							*group_id);
438
+			if (!group_inst) {
439
+				LOG(L_ERR, "ERROR: cfg_set_now(): global group instance %.*s[%u] is not found\n",
440
+					group_name->len, group_name->s, *group_id);
441
+				goto error;
442
+			}
443
+			var_block = group_inst->vars;
444
+		} else {
445
+			group_inst = NULL;
446
+			var_block = CFG_GROUP_DATA(*cfg_global, group);
447
+		}
448
+
328 449
 		if (var->def->type & CFG_ATOMIC) {
329 450
 			/* atomic change is allowed, we can rewrite the value
330 451
 			directly in the global config */
331
-			p = (*cfg_global)->vars+group->offset+var->offset;
452
+			p = var_block + var->offset;
332 453
 
333 454
 		} else {
334 455
 			/* clone the memory block, and prepare the modification */
335 456
 			if (!(block = cfg_clone_global())) goto error;
336 457
 
337
-			p = block->vars+group->offset+var->offset;
458
+			if (group_inst) {
459
+				/* The additional array of the group needs to be also cloned.
460
+				 * When any of the variables within this array is changed, then
461
+				 * the complete config block and this array is replaced. */
462
+				if (!(new_array = cfg_clone_array(CFG_GROUP_META(*cfg_global, group), group)))
463
+					goto error;
464
+				group_inst = (cfg_group_inst_t *)translate_pointer((char *)new_array,
465
+					(char *)CFG_GROUP_META(*cfg_global, group)->array,
466
+					(char *)group_inst);
467
+				var_block = group_inst->vars;
468
+				CFG_GROUP_META(block, group)->array = new_array;
469
+			} else {
470
+				/* The additional array may need to be replaced depending
471
+				 * on whether or not there is any variable in the array set
472
+				 * to the default value which is changed now. If this is the case,
473
+				 * then the array will be replaced later when the variables are
474
+				 * updated.
475
+				 */
476
+				var_block = CFG_GROUP_DATA(block, group);
477
+			}
478
+			p = var_block + var->offset;
338 479
 		}
339 480
 	} else {
340 481
 		/* we are allowed to rewrite the value on-the-fly
... ...
@@ -371,18 +512,43 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
371 512
 		break;
372 513
 
373 514
 	}
515
+	if (group_inst && !CFG_VAR_TEST_AND_SET(group_inst, var))
516
+		old_string = NULL; /* the string is the same as the default one,
517
+					it cannot be freed */
374 518
 
375 519
 	if (cfg_shmized) {
376
-		if (old_string) {
520
+		if (!group_inst) {
521
+			/* the default value is changed, the copies of this value
522
+			need to be also updated */
523
+			if (cfg_update_defaults(CFG_GROUP_META(block ? block : *cfg_global, group),
524
+						group, var, p,
525
+						block ? 1 : 0) /* clone if needed */
526
+			)
527
+				goto error;
528
+			if (block && (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array))
529
+				new_array = CFG_GROUP_META(block, group)->array;
530
+		}
531
+
532
+		if (old_string || new_array) {
377 533
 			/* prepare the array of the replaced strings,
534
+			and replaced group instances,
378 535
 			they will be freed when the old block is freed */
379
-			replaced = (char **)shm_malloc(sizeof(char *)*2);
536
+			replaced = (void **)shm_malloc(sizeof(void *)
537
+					* ((old_string?1:0) + (new_array?1:0) + 1));
380 538
 			if (!replaced) {
381 539
 				LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
382 540
 				goto error;
383 541
 			}
384
-			replaced[0] = old_string;
385
-			replaced[1] = NULL;
542
+			i = 0;
543
+			if (old_string) {
544
+				replaced[i] = old_string;
545
+				i++;
546
+			}
547
+			if (new_array) {	
548
+				replaced[i] = CFG_GROUP_META(*cfg_global, group)->array;
549
+				i++;
550
+			}
551
+			replaced[i] = NULL;
386 552
 		}
387 553
 		/* replace the global config with the new one */
388 554
 		if (block) cfg_install_global(block, replaced, child_cb, child_cb);
... ...
@@ -423,6 +589,9 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
423 589
 			group_name->len, group_name->s,
424 590
 			var_name->len, var_name->s,
425 591
 			((str *)val)->len, ((str *)val)->s);
592
+	if (group_id)
593
+		LOG(L_INFO, "INFO: cfg_set_now(): group id = %u\n",
594
+			*group_id);
426 595
 
427 596
 	convert_val_cleanup();
428 597
 	return 0;
... ...
@@ -430,7 +599,9 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
430 599
 error:
431 600
 	if (cfg_shmized) CFG_WRITER_UNLOCK();
432 601
 	if (block) cfg_block_free(block);
602
+	if (new_array) shm_free(new_array);
433 603
 	if (child_cb) cfg_child_cb_free(child_cb);
604
+	if (replaced) shm_free(replaced);
434 605
 
435 606
 error0:
436 607
 	LOG(L_ERR, "ERROR: cfg_set_now(): failed to set the variable: %.*s.%.*s\n",
... ...
@@ -443,45 +614,27 @@ error0:
443 614
 }
444 615
 
445 616
 /* wrapper function for cfg_set_now */
446
-int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
617
+int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
618
+			int val)
447 619
 {
448
-	return cfg_set_now(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
620
+	return cfg_set_now(ctx, group_name, group_id, var_name,
621
+				(void *)(long)val, CFG_VAR_INT);
449 622
 }
450 623
 
451 624
 /* wrapper function for cfg_set_now */
452
-int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
625
+int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
626
+			char *val)
453 627
 {
454
-	return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
628
+	return cfg_set_now(ctx, group_name, group_id, var_name,
629
+				(void *)val, CFG_VAR_STRING);
455 630
 }
456 631
 
457 632
 /* wrapper function for cfg_set_now */
458
-int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
633
+int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
634
+			str *val)
459 635
 {
460
-	return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
461
-}
462
-
463
-/* returns the size of the variable */
464
-static int cfg_var_size(cfg_mapping_t *var)
465
-{
466
-	switch (CFG_VAR_TYPE(var)) {
467
-
468
-	case CFG_VAR_INT:
469
-		return sizeof(int);
470
-
471
-	case CFG_VAR_STRING:
472
-		return sizeof(char *);
473
-
474
-	case CFG_VAR_STR:
475
-		return sizeof(str);
476
-
477
-	case CFG_VAR_POINTER:
478
-		return sizeof(void *);
479
-
480
-	default:
481
-		LOG(L_CRIT, "BUG: cfg_var_size(): unknown type: %u\n",
482
-			CFG_VAR_TYPE(var));
483
-		return 0;
484
-	}
636
+	return cfg_set_now(ctx, group_name, group_id, var_name,
637
+				(void *)val, CFG_VAR_STR);
485 638
 }
486 639
 
487 640
 /* sets the value of a variable but does not commit the change
... ...
@@ -491,22 +644,24 @@ static int cfg_var_size(cfg_mapping_t *var)
491 644
  *  -1: error
492 645
  *   1: variable has not been found
493 646
  */
494
-int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
647
+int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
495 648
 			void *val, unsigned int val_type)
496 649
 {
497 650
 	cfg_group_t	*group;
498 651
 	cfg_mapping_t	*var;
499 652
 	void		*v;
500
-	char		*temp_handle;
653
+	unsigned char	*temp_handle;
501 654
 	int		temp_handle_created;
502
-	cfg_changed_var_t	*changed = NULL;
655
+	cfg_changed_var_t	*changed = NULL, **changed_p;
503 656
 	int		size;
504 657
 	str		s;
658
+	cfg_group_inst_t	*group_inst = NULL;
659
+	unsigned char		*var_block;
505 660
 
506 661
 	if (!cfg_shmized)
507 662
 		/* the cfg has not been shmized yet, there is no
508 663
 		point in registering the change and committing it later */
509
-		return cfg_set_now(ctx, group_name, var_name,
664
+		return cfg_set_now(ctx, group_name, group_id, var_name,
510 665
 					val, val_type);
511 666
 
512 667
 	if (!ctx) {
... ...
@@ -524,6 +679,19 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
524 679
 		goto error0;
525 680
 	}
526 681
 
682
+	/* The additional variable instances having per-child process callback
683
+	 * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
684
+	 * The reason is that such variables typically set global parameters
685
+	 * as opposed to per-process variables. Hence, it is not possible to set
686
+	 * the group handle temporary to another block, and then reset it back later. */
687
+	if (group_id
688
+		&& var->def->on_set_child_cb
689
+		&& var->def->type & CFG_CB_ONLY_ONCE
690
+	) {
691
+		LOG(L_ERR, "ERROR: cfg_set_delayed(): This variable does not support muliple values.\n");
692
+		goto error0;
693
+	}
694
+
527 695
 	/* check whether we have to convert the type */
528 696
 	if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
529 697
 		goto error0;
... ...
@@ -549,31 +717,56 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
549 717
 		Only the values within the group are applied,
550 718
 		other modifications are not visible to the callback.
551 719
 		The local config is the base. */
720
+		if (!group_id) {
721
+			var_block = *(group->handle);
722
+		} else {
723
+			if (!cfg_local) {
724
+				LOG(L_ERR, "ERROR: cfg_set_delayed(): Local configuration is missing\n");
725
+				goto error;
726
+			}
727
+			group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
728
+							group->size,
729
+							*group_id);
730
+			if (!group_inst) {
731
+				LOG(L_ERR, "ERROR: cfg_set_delayed(): local group instance %.*s[%u] is not found\n",
732
+					group_name->len, group_name->s, *group_id);
733
+				goto error;
734
+			}
735
+			var_block = group_inst->vars;
736
+		}
552 737
 
553 738
 		if (ctx->changed_first) {
554
-			temp_handle = (char *)pkg_malloc(group->size);
739
+			temp_handle = (unsigned char *)pkg_malloc(group->size);
555 740
 			if (!temp_handle) {
556 741
 				LOG(L_ERR, "ERROR: cfg_set_delayed(): "
557 742
 					"not enough memory\n");
558 743
 				goto error;
559 744
 			}
560 745
 			temp_handle_created = 1;
561
-			memcpy(temp_handle, *(group->handle), group->size);
746
+			memcpy(temp_handle, var_block, group->size);
562 747
 
563 748
 			/* apply the changes */
564 749
 			for (	changed = ctx->changed_first;
565 750
 				changed;
566 751
 				changed = changed->next
567 752
 			) {
568
-				if (changed->group != group) continue;
569
-
570
-				memcpy(	temp_handle + changed->var->offset,
571
-					changed->new_val.vraw,
572
-					cfg_var_size(changed->var));
753
+				if (changed->group != group)
754
+					continue;
755
+				if ((!group_id && !changed->group_id_set) /* default values */
756
+					|| (group_id && !changed->group_id_set
757
+						&& !CFG_VAR_TEST(group_inst, changed->var))
758
+							/* default value is changed which affects the group_instance */
759
+					|| (group_id && changed->group_id_set
760
+						&& (*group_id == changed->group_id))
761
+							/* change within the group instance */
762
+				)
763
+					memcpy(	temp_handle + changed->var->offset,
764
+						changed->new_val.vraw,
765
+						cfg_var_size(changed->var));
573 766
 			}
574 767
 		} else {
575 768
 			/* there is not any change */
576
-			temp_handle = *(group->handle);
769
+			temp_handle = var_block;
577 770
 			temp_handle_created = 0;
578 771
 		}
579 772
 			
... ...
@@ -600,6 +793,10 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
600 793
 	memset(changed, 0, size);
601 794
 	changed->group = group;
602 795
 	changed->var = var;
796
+	if (group_id) {
797
+		changed->group_id = *group_id;
798
+		changed->group_id_set = 1;
799
+	}
603 800
 
604 801
 	switch (CFG_VAR_TYPE(var)) {
605 802
 
... ...
@@ -628,15 +825,27 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
628 825
 
629 826
 	}
630 827
 
631
-	/* Add the new item to the end of the linked list,
632
-	The commit will go though the list from the first item,
633
-	so the list is kept in order */
634
-	if (ctx->changed_first)
635
-		ctx->changed_last->next = changed;
636
-	else
637
-		ctx->changed_first = changed;
638
-
639
-	ctx->changed_last = changed;
828
+	/* Order the changes by group + group_id + original order.
829
+	 * Hence, the list is still kept in order within the group.
830
+	 * The changes can be committed faster this way, the group instances
831
+	 * do not have to be looked-up for each and every variable. */
832
+	/* Check whether there is any variable in the list which
833
+	belongs to the same group */
834
+	for (	changed_p = &ctx->changed_first;
835
+		*changed_p && ((*changed_p)->group != changed->group);
836
+		changed_p = &(*changed_p)->next);
837
+	/* try to find the group instance, and move changed_p to the end of
838
+	the instance. */
839
+	for (	;
840
+		*changed_p
841
+			&& ((*changed_p)->group == changed->group)
842
+			&& (!(*changed_p)->group_id_set
843
+				|| ((*changed_p)->group_id_set && changed->group_id_set
844
+					&& ((*changed_p)->group_id <= changed->group_id)));
845
+		changed_p = &(*changed_p)->next);
846
+	/* Add the new variable before *changed_p */
847
+	changed->next = *changed_p;
848
+	*changed_p = changed;
640 849
 
641 850
 	CFG_CTX_UNLOCK(ctx);
642 851
 
... ...
@@ -666,6 +875,11 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
666 875
 			var_name->len, var_name->s,
667 876
 			((str *)val)->len, ((str *)val)->s,
668 877
 			ctx);
878
+	if (group_id)
879
+		LOG(L_INFO, "INFO: cfg_set_delayed(): group id = %u "
880
+			"[context=%p]\n",
881
+			*group_id,
882
+			ctx);
669 883
 
670 884
 	convert_val_cleanup();
671 885
 	return 0;
... ...
@@ -683,21 +897,27 @@ error0:
683 897
 }
684 898
 
685 899
 /* wrapper function for cfg_set_delayed */
686
-int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
900
+int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
901
+				int val)
687 902
 {
688
-	return cfg_set_delayed(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
903
+	return cfg_set_delayed(ctx, group_name, group_id, var_name,
904
+				(void *)(long)val, CFG_VAR_INT);
689 905
 }
690 906
 
691 907
 /* wrapper function for cfg_set_delayed */
692
-int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
908
+int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
909
+				char *val)
693 910
 {
694
-	return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
911
+	return cfg_set_delayed(ctx, group_name, group_id, var_name,
912
+				(void *)val, CFG_VAR_STRING);
695 913
 }
696 914
 
697 915
 /* wrapper function for cfg_set_delayed */
698
-int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
916
+int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
917
+				str *val)
699 918
 {
700
-	return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
919
+	return cfg_set_delayed(ctx, group_name, group_id, var_name,
920
+				(void *)val, CFG_VAR_STR);
701 921
 }
702 922
 
703 923
 /* commits the previously prepared changes within the context */
... ...
@@ -705,14 +925,16 @@ int cfg_commit(cfg_ctx_t *ctx)
705 925
 {
706 926
 	int	replaced_num = 0;
707 927
 	cfg_changed_var_t	*changed, *changed2;
708
-	cfg_block_t	*block;
709
-	char	**replaced = NULL;
928
+	cfg_block_t	*block = NULL;
929
+	void	**replaced = NULL;
710 930
 	cfg_child_cb_t	*child_cb;
711 931
 	cfg_child_cb_t	*child_cb_first = NULL;
712 932
 	cfg_child_cb_t	*child_cb_last = NULL;
713 933
 	int	size;
714 934
 	void	*p;
715 935
 	str	s, s2;
936
+	cfg_group_t	*group;
937
+	cfg_group_inst_t	*group_inst = NULL;
716 938
 
717 939
 	if (!ctx) {
718 940
 		LOG(L_ERR, "ERROR: cfg_commit(): context is undefined\n");
... ...
@@ -728,19 +950,30 @@ int cfg_commit(cfg_ctx_t *ctx)
728 950
 	/* is there any change? */
729 951
 	if (!ctx->changed_first) goto done;
730 952
 
731
-	/* count the number of replaced strings,
732
-	and prepare the linked list of per-child process
733
-	callbacks, that will be added to the global list */
734
-	for (	changed = ctx->changed_first;
953
+	/* Count the number of replaced strings,
954
+	and replaced group arrays.
955
+	Prepare the linked list of per-child process
956
+	callbacks, that will be added to the global list. */
957
+	for (	changed = ctx->changed_first, group = NULL;
735 958
 		changed;
736 959
 		changed = changed->next
737 960
 	) {
961
+		/* Each string/str potentially causes an old string to be freed
962
+		 * unless the variable of an additional group instance is set
963
+		 * which uses the default value. This case cannot be determined
964
+		 * without locking *cfg_global, hence, it is better to count these
965
+		 * strings as well even though the slot might not be used later. */
738 966
 		if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
739 967
 		|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
740 968
 			replaced_num++;
741 969
 
970
+		/* See the above comments for strings */
971
+		if (group != changed->group) {
972
+			replaced_num++;
973
+			group = changed->group;
974
+		}
742 975
 
743
-		if (changed->var->def->on_set_child_cb) {
976
+		if (!changed->group_id_set && changed->var->def->on_set_child_cb) {
744 977
 			s.s = changed->group->name;
745 978
 			s.len = changed->group->name_len;
746 979
 			s2.s = changed->var->def->name;
... ...
@@ -760,11 +993,11 @@ int cfg_commit(cfg_ctx_t *ctx)
760 993
 
761 994
 	if (replaced_num) {
762 995
 		/* allocate memory for the replaced string array */
763
-		size = sizeof(char *)*(replaced_num + 1);
764
-		replaced = (char **)shm_malloc(size);
996
+		size = sizeof(void *)*(replaced_num + 1);
997
+		replaced = (void **)shm_malloc(size);
765 998
 		if (!replaced) {
766 999
 			LOG(L_ERR, "ERROR: cfg_commit(): not enough shm memory\n");
767
-			goto error;
1000
+			goto error0;
768 1001
 		}
769 1002
 		memset(replaced, 0 , size);
770 1003
 	}
... ...
@@ -774,23 +1007,57 @@ int cfg_commit(cfg_ctx_t *ctx)
774 1007
 	CFG_WRITER_LOCK();
775 1008
 
776 1009
 	/* clone the memory block, and prepare the modification */
777
-	if (!(block = cfg_clone_global())) {
778
-		CFG_WRITER_UNLOCK();
1010
+	if (!(block = cfg_clone_global()))
779 1011
 		goto error;
780
-	}
781 1012
 
782
-	/* apply the modifications to the buffer */
1013
+	/* Apply the modifications to the buffer.
1014
+	Note that the cycle relies on the order of the groups and group instances, i.e.
1015
+	the order is group + group_id + order of commits. */
783 1016
 	replaced_num = 0;
784
-	for (	changed = ctx->changed_first;
1017
+	for (	changed = ctx->changed_first, group = NULL; /* group points to the
1018
+							last group array that has been cloned */
785 1019
 		changed;
786 1020
 		changed = changed->next
787 1021
 	) {
788
-		p = block->vars
789
-			+ changed->group->offset
790
-			+ changed->var->offset;
1022
+		if (!changed->group_id_set) {
1023
+			p = CFG_GROUP_DATA(block, changed->group)
1024
+				+ changed->var->offset;
1025
+			group_inst = NULL; /* force the look-up of the next group_inst */
1026
+		} else {
1027
+			if (group != changed->group) {
1028
+				/* The group array has not been cloned yet. */
1029
+				group = changed->group;
1030
+				if (!(CFG_GROUP_META(block, group)->array = 
1031
+					cfg_clone_array(CFG_GROUP_META(*cfg_global, group), group))
1032
+				) {
1033
+					LOG(L_ERR, "ERROR: cfg_commit(): group array cannot be cloned for %.*s[%u]\n",
1034
+						group->name_len, group->name, changed->group_id);
1035
+					goto error;
1036
+				}
1037
+
1038
+				replaced[replaced_num] = CFG_GROUP_META(*cfg_global, group)->array;
1039
+				replaced_num++;
791 1040
 
792
-		if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
793
-		|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
1041
+				group_inst = NULL; /* fore the look-up of group_inst */
1042
+			}
1043
+			if (!group_inst || (group_inst->id != changed->group_id)) {
1044
+				group_inst = cfg_find_group(CFG_GROUP_META(block, group),
1045
+								group->size,
1046
+								changed->group_id);
1047
+			}
1048
+			if (!group_inst) {
1049
+				LOG(L_ERR, "ERROR: cfg_commit(): global group instance %.*s[%u] is not found\n",
1050
+					group->name_len, group->name, changed->group_id);
1051
+				goto error;
1052
+			}
1053
+			p = group_inst->vars + changed->var->offset;
1054
+		}
1055
+
1056
+		if (((changed->group_id_set && CFG_VAR_TEST_AND_SET(group_inst, changed->var))
1057
+			|| !changed->group_id_set)
1058
+		&& ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1059
+			|| (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) 
1060
+		) {
794 1061
 			replaced[replaced_num] = *(char **)p;
795 1062
 			if (replaced[replaced_num])
796 1063
 				replaced_num++;
... ...
@@ -802,13 +1069,33 @@ int cfg_commit(cfg_ctx_t *ctx)
802 1069
 		memcpy(	p,
803 1070
 			changed->new_val.vraw,
804 1071
 			cfg_var_size(changed->var));
1072
+
1073
+		if (!changed->group_id_set) {
1074
+			/* the default value is changed, the copies of this value
1075
+			need to be also updated */
1076
+			if (cfg_update_defaults(CFG_GROUP_META(block, changed->group),
1077
+						changed->group, changed->var, p,
1078
+						(group != changed->group)) /* clone if the array
1079
+									has not been cloned yet */
1080
+                        )
1081
+                                goto error;
1082
+                        if ((group != changed->group)
1083
+				&& (CFG_GROUP_META(block, changed->group)->array != CFG_GROUP_META(*cfg_global, changed->group)->array)
1084
+			) {
1085
+				/* The array has been cloned */
1086
+				group = changed->group;
1087
+
1088
+				replaced[replaced_num] = CFG_GROUP_META(*cfg_global, group)->array;
1089
+				replaced_num++;
1090
+			}
1091
+		}
805 1092
 	}
806 1093
 
807 1094
 	/* replace the global config with the new one */
808 1095
 	cfg_install_global(block, replaced, child_cb_first, child_cb_last);
809 1096
 	CFG_WRITER_UNLOCK();
810 1097
 
811
-	/* free the changed list */	
1098
+	/* free the changed list */
812 1099
 	for (	changed = ctx->changed_first;
813 1100
 		changed;
814 1101
 		changed = changed2
... ...
@@ -817,7 +1104,6 @@ int cfg_commit(cfg_ctx_t *ctx)
817 1104
 		shm_free(changed);
818 1105
 	}
819 1106
 	ctx->changed_first = NULL;
820
-	ctx->changed_last = NULL;
821 1107
 
822 1108
 done:
823 1109
 	LOG(L_INFO, "INFO: cfg_commit(): config changes have been applied "
... ...
@@ -828,9 +1114,24 @@ done:
828 1114
 	return 0;
829 1115
 
830 1116
 error:
831
-	CFG_CTX_UNLOCK(ctx);
1117
+	if (block) {
1118
+		/* clean the new block from the cloned arrays */
1119
+		for (	group = cfg_group;
1120
+			group;
1121
+			group = group->next
1122
+		)
1123
+			if (CFG_GROUP_META(block, group)->array
1124
+				&& (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array)
1125
+			)
1126
+				shm_free(CFG_GROUP_META(block, group)->array);
1127
+		/* the block can be freed outside of the writer lock */
1128
+	}
1129
+	CFG_WRITER_UNLOCK();
1130
+	if (block)
1131
+		shm_free(block);
832 1132
 
833 1133
 error0:
1134
+	CFG_CTX_UNLOCK(ctx);
834 1135
 
835 1136
 	if (child_cb_first) cfg_child_cb_free(child_cb_first);
836 1137
 	if (replaced) shm_free(replaced);
... ...
@@ -872,7 +1173,6 @@ int cfg_rollback(cfg_ctx_t *ctx)
872 1173
 		shm_free(changed);
873 1174
 	}
874 1175
 	ctx->changed_first = NULL;
875
-	ctx->changed_last = NULL;
876 1176
 
877 1177
 	CFG_CTX_UNLOCK(ctx);
878 1178
 
... ...
@@ -885,7 +1185,7 @@ int cfg_rollback(cfg_ctx_t *ctx)
885 1185
  * -1 - error
886 1186
  *  1 - variable exists, but it is not readable
887 1187
  */
888
-int cfg_get_by_name(cfg_ctx_t *ctx, str *group_name, str *var_name,
1188
+int cfg_get_by_name(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
889 1189
 			void **val, unsigned int *val_type)
890 1190
 {
891 1191
 	cfg_group_t	*group;
... ...
@@ -893,6 +1193,7 @@ int cfg_get_by_name(cfg_ctx_t *ctx, str *group_name, str *var_name,
893 1193
 	void		*p;
894 1194
 	static str	s;	/* we need the value even
895 1195
 				after the function returns */
1196
+	cfg_group_inst_t	*group_inst;
896 1197
 
897 1198
 	/* verify the context even if we do not need it now
898 1199
 	to make sure that a cfg driver has called the function
... ...
@@ -913,10 +1214,27 @@ int cfg_get_by_name(cfg_ctx_t *ctx, str *group_name, str *var_name,
913 1214
 		return 1;
914 1215
 	}
915 1216
 
916
-	/* use the module's handle to access the variable
917
-	It means that the variable is read from the local config
918
-	after forking */
919
-	p = *(group->handle) + var->offset;
1217
+	if (group_id) {
1218
+		if (!cfg_local) {
1219
+			LOG(L_ERR, "ERROR: cfg_get_by_name(): Local configuration is missing\n");
1220
+			return -1;
1221
+		}
1222
+		group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
1223
+						group->size,
1224
+						*group_id);
1225
+		if (!group_inst) {
1226
+			LOG(L_ERR, "ERROR: cfg_get_by_name(): local group instance %.*s[%u] is not found\n",
1227
+				group_name->len, group_name->s, *group_id);
1228
+			return -1;
1229
+		}
1230
+		p = group_inst->vars + var->offset;
1231
+
1232
+	} else {
1233
+		/* use the module's handle to access the variable
1234
+		It means that the variable is read from the local config
1235
+		after forking */
1236
+		p = *(group->handle) + var->offset;
1237
+	}
920 1238
 
921 1239
 	switch (CFG_VAR_TYPE(var)) {
922 1240
 	case CFG_VAR_INT:
... ...
@@ -1005,13 +1323,18 @@ int cfg_diff_init(cfg_ctx_t *ctx,
1005 1323
 
1006 1324
 /* return the pending changes that have not been
1007 1325
  * committed yet
1326
+ * return value:
1327
+ *	1: valid value is found
1328
+ *	0: no more changed value found
1329
+ *	-1: error occured 
1008 1330
  */
1009 1331
 int cfg_diff_next(void **h,
1010
-			str *gname, str *vname,
1332
+			str *gname, unsigned int **gid, str *vname,
1011 1333
 			void **old_val, void **new_val,
1012 1334
 			unsigned int *val_type)
1013 1335
 {
1014 1336
 	cfg_changed_var_t	*changed;
1337
+	cfg_group_inst_t	*group_inst;
1015 1338
 	union cfg_var_value* pval;
1016 1339
 	static str	old_s, new_s;	/* we need the value even
1017 1340
 					after the function returns */
... ...
@@ -1021,14 +1344,32 @@ int cfg_diff_next(void **h,
1021 1344
 
1022 1345
 	gname->s = changed->group->name;
1023 1346
 	gname->len = changed->group->name_len;
1347
+	*gid = (changed->group_id_set ? &changed->group_id : NULL);
1024 1348
 	vname->s = changed->var->def->name;
1025 1349
 	vname->len = changed->var->name_len;
1026 1350
 
1027 1351
 	/* use the module's handle to access the variable
1028 1352
 	It means that the variable is read from the local config
1029 1353
 	after forking */
1030
-	pval = (union cfg_var_value*)
1031
-			(*(changed->group->handle) + changed->var->offset);
1354
+	if (!changed->group_id_set) {
1355
+		pval = (union cfg_var_value*)
1356
+				(*(changed->group->handle) + changed->var->offset);
1357
+	} else {
1358
+		if (!cfg_local) {
1359
+			LOG(L_ERR, "ERROR: cfg_diff_next(): Local configuration is missing\n");
1360
+			return -1;
1361
+		}
1362
+		group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, changed->group),
1363
+						changed->group->size,
1364
+						changed->group_id);
1365
+		if (!group_inst) {
1366
+			LOG(L_ERR, "ERROR: cfg_diff_next(): local group instance %.*s[%u] is not found\n",
1367
+				changed->group->name_len, changed->group->name, changed->group_id);
1368
+			return -1;
1369
+		}
1370
+		pval = (union cfg_var_value*)
1371
+				(group_inst->vars + changed->var->offset);
1372
+	}
1032 1373
 
1033 1374
 	switch (CFG_VAR_TYPE(changed->var)) {
1034 1375
 	case CFG_VAR_INT:
... ...
@@ -1070,3 +1411,364 @@ void cfg_diff_release(cfg_ctx_t *ctx)
1070 1411
 
1071 1412
 	CFG_CTX_UNLOCK(ctx);
1072 1413
 }
1414
+
1415
+/* Add a new instance to an existing group */
1416
+int cfg_add_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
1417
+{
1418
+	cfg_group_t	*group;
1419
+	cfg_block_t	*block = NULL;
1420
+	void		**replaced = NULL;
1421
+	cfg_group_inst_t	*new_array = NULL, *new_inst;
1422
+
1423
+	/* verify the context even if we do not need it now
1424
+	to make sure that a cfg driver has called the function
1425
+	(very very weak security) */
1426
+	if (!ctx) {
1427
+		LOG(L_ERR, "ERROR: cfg_add_group_inst(): context is undefined\n");
1428
+		return -1;
1429
+	}
1430
+
1431
+	if (!cfg_shmized) {
1432
+		/* Add a new variable without any value to
1433
+		the linked list of additional values. This variable
1434
+		will force a new group instance to be created. */
1435
+		return new_add_var(group_name, group_id,  NULL /* var_name */,
1436
+					NULL /* val */, 0 /* type */);
1437
+	}
1438
+
1439
+	if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
1440
+		LOG(L_ERR, "ERROR: cfg_add_group_inst(): group not found\n");
1441
+		return -1;
1442
+	}
1443
+
1444
+	/* make sure that nobody else replaces the global config
1445
+	while the new one is prepared */
1446
+	CFG_WRITER_LOCK();
1447
+	if (cfg_find_group(CFG_GROUP_META(*cfg_global, group),
1448
+							group->size,
1449
+							group_id)
1450
+	) {
1451
+		LOG(L_DBG, "DEBUG: cfg_add_group_inst(): the group instance already exists\n");
1452
+		CFG_WRITER_UNLOCK();
1453
+		return 0; /* not an error */
1454
+	}
1455
+
1456
+	/* clone the global memory block because the additional array can be
1457
+	replaced only together with the block. */
1458
+	if (!(block = cfg_clone_global()))
1459
+		goto error;
1460
+
1461
+	/* Extend the array with a new group instance */
1462
+	if (!(new_array = cfg_extend_array(CFG_GROUP_META(*cfg_global, group), group,
1463
+					group_id,
1464
+					&new_inst))
1465
+	)
1466
+		goto error;
1467
+
1468
+	/* fill in the new group instance with the default data */
1469
+	memcpy(	new_inst->vars,
1470
+		CFG_GROUP_DATA(*cfg_global, group),
1471
+		group->size);
1472
+
1473
+	CFG_GROUP_META(block, group)->array = new_array;
1474
+	CFG_GROUP_META(block, group)->num++;
1475
+
1476
+	if (CFG_GROUP_META(*cfg_global, group)->array) {
1477
+		/* prepare the array of the replaced strings,
1478
+		and replaced group instances,
1479
+		they will be freed when the old block is freed */
1480
+		replaced = (void **)shm_malloc(sizeof(void *) * 2);
1481
+		if (!replaced) {
1482
+			LOG(L_ERR, "ERROR: cfg_add_group_inst(): not enough shm memory\n");
1483
+			goto error;
1484
+		}
1485
+		replaced[0] = CFG_GROUP_META(*cfg_global, group)->array;
1486
+		replaced[1] = NULL;
1487
+	}
1488
+	/* replace the global config with the new one */
1489
+	cfg_install_global(block, replaced, NULL, NULL);
1490
+	CFG_WRITER_UNLOCK();
1491
+
1492
+	LOG(L_INFO, "INFO: cfg_add_group_inst(): "
1493
+		"group instance is added: %.*s[%u]\n",
1494
+		group_name->len, group_name->s,
1495
+		group_id);
1496
+
1497
+	return 0;
1498
+error:
1499
+	CFG_WRITER_UNLOCK();
1500
+	if (block) cfg_block_free(block);
1501
+	if (new_array) shm_free(new_array);
1502
+	if (replaced) shm_free(replaced);
1503
+
1504
+	LOG(L_ERR, "ERROR: cfg_add_group_inst(): "
1505
+		"Failed to add the group instance: %.*s[%u]\n",
1506
+		group_name->len, group_name->s,
1507
+		group_id);
1508
+
1509
+	return -1;
1510
+}
1511
+
1512
+/* Delete an instance of a group */
1513
+int cfg_del_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
1514
+{
1515
+	cfg_group_t	*group;
1516
+	cfg_block_t	*block = NULL;
1517
+	void		**replaced = NULL;
1518
+	cfg_group_inst_t	*new_array = NULL, *group_inst;
1519
+
1520
+	/* verify the context even if we do not need it now
1521
+	to make sure that a cfg driver has called the function
1522
+	(very very weak security) */
1523
+	if (!ctx) {
1524
+		LOG(L_ERR, "ERROR: cfg_del_group_inst(): context is undefined\n");
1525
+		return -1;
1526
+	}
1527
+
1528
+	if (!cfg_shmized) {
1529
+		/* It makes no sense to delete a group instance that has not
1530
+		been created yet */
1531
+		return -1;
1532
+	}
1533
+
1534
+	if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
1535
+		LOG(L_ERR, "ERROR: cfg_del_group_inst(): group not found\n");
1536
+		return -1;
1537
+	}
1538
+
1539
+	/* make sure that nobody else replaces the global config
1540
+	while the new one is prepared */
1541
+	CFG_WRITER_LOCK();
1542
+	if (!(group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group),
1543
+							group->size,
1544
+							group_id))
1545
+	) {
1546
+		LOG(L_DBG, "DEBUG: cfg_del_group_inst(): the group instance does not exist\n");
1547
+		goto error;
1548
+	}
1549
+
1550
+	/* clone the global memory block because the additional array can be
1551
+	replaced only together with the block. */
1552
+	if (!(block = cfg_clone_global()))
1553
+		goto error;
1554
+
1555
+	/* Remove the group instance from the array. */
1556
+	if (cfg_collapse_array(CFG_GROUP_META(*cfg_global, group), group,
1557
+					group_inst,
1558
+					&new_array)
1559
+	)
1560
+		goto error;
1561
+
1562
+	CFG_GROUP_META(block, group)->array = new_array;
1563
+	CFG_GROUP_META(block, group)->num--;
1564
+
1565
+	if (CFG_GROUP_META(*cfg_global, group)->array) {
1566
+		/* prepare the array of the replaced strings,
1567
+		and replaced group instances,
1568
+		they will be freed when the old block is freed */
1569
+		replaced = (void **)shm_malloc(sizeof(void *) * 2);
1570
+		if (!replaced) {
1571
+			LOG(L_ERR, "ERROR: cfg_del_group_inst(): not enough shm memory\n");
1572
+			goto error;
1573
+		}
1574
+		replaced[0] = CFG_GROUP_META(*cfg_global, group)->array;
1575
+		replaced[1] = NULL;
1576
+	}
1577
+	/* replace the global config with the new one */
1578
+	cfg_install_global(block, replaced, NULL, NULL);
1579
+	CFG_WRITER_UNLOCK();
1580
+
1581
+	LOG(L_INFO, "INFO: cfg_del_group_inst(): "
1582
+		"group instance is deleted: %.*s[%u]\n",
1583
+		group_name->len, group_name->s,
1584
+		group_id);
1585
+
1586
+	return 0;
1587
+error:
1588
+	CFG_WRITER_UNLOCK();
1589
+	if (block) cfg_block_free(block);
1590
+	if (new_array) shm_free(new_array);
1591
+	if (replaced) shm_free(replaced);
1592
+
1593
+	LOG(L_ERR, "ERROR: cfg_add_group_inst(): "
1594
+		"Failed to delete the group instance: %.*s[%u]\n",
1595
+		group_name->len, group_name->s,
1596
+		group_id);
1597
+
1598
+	return -1;
1599
+}
1600
+
1601
+/* Apply the changes to a group instance as long as the additional variable
1602
+ * belongs to the specified group_id. *add_var_p is moved to the next additional
1603
+ * variable, and all the consumed variables are freed.
1604
+ * This function can be used only during the cfg shmize process.
1605
+ * For internal use only!
1606
+ */
1607
+int cfg_apply_list(cfg_group_inst_t *ginst, cfg_group_t *group,
1608
+			unsigned int group_id, cfg_add_var_t **add_var_p)
1609
+{
1610
+	cfg_add_var_t	*add_var;
1611
+	cfg_mapping_t	*var;
1612
+	void		*val, *v, *p;
1613
+	str		group_name, var_name, s;
1614
+	char		*old_string;
1615
+
1616
+	group_name.s = group->name;
1617
+	group_name.len = group->name_len;
1618
+	while (*add_var_p && ((*add_var_p)->group_id == group_id)) {
1619
+		add_var = *add_var_p;
1620
+
1621
+		if (add_var->type == 0)
1622
+			goto done; /* Nothing needs to be changed,
1623
+				this additional variable only forces a new
1624
+				group instance to be created. */
1625
+		var_name.s = add_var->name;
1626
+		var_name.len = add_var->name_len;
1627
+
1628
+		if (!(var = cfg_lookup_var2(group, add_var->name, add_var->name_len))) {
1629
+			LOG(L_ERR, "ERROR: cfg_apply_list(): Variable is not found: %.*s.%.*s\n",
1630
+				group->name_len, group->name,
1631
+				add_var->name_len, add_var->name);
1632
+			goto error;
1633
+		}
1634
+
1635
+		/* check whether the variable is read-only */
1636
+		if (var->def->type & CFG_READONLY) {
1637
+			LOG(L_ERR, "ERROR: cfg_apply_list(): variable is read-only\n");
1638
+			goto error;
1639
+		}
1640
+
1641
+		/* The additional variable instances having per-child process callback
1642
+		 * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
1643
+		 * The reason is that such variables typically set global parameters
1644
+		 * as opposed to per-process variables. Hence, it is not possible to set
1645
+		 * the group handle temporary to another block, and then reset it back later. */
1646
+		if (var->def->on_set_child_cb
1647
+			&& var->def->type & CFG_CB_ONLY_ONCE
1648
+		) {
1649
+			LOG(L_ERR, "ERROR: cfg_apply_list(): This variable does not support muliple values.\n");
1650
+			goto error;
1651
+		}
1652
+
1653
+		switch(add_var->type) {
1654
+		case CFG_VAR_INT:
1655
+			val = (void *)(long)add_var->val.i;
1656
+			break;
1657
+		case CFG_VAR_STR:
1658
+			val = (str *)&(add_var->val.s);
1659
+			break;
1660
+		case CFG_VAR_STRING:
1661
+			val = (char *)add_var->val.ch;
1662
+			break;
1663
+		default:
1664
+			LOG(L_ERR, "ERROR: cfg_apply_list(): unsupported variable type: %d\n",
1665
+				add_var->type);
1666
+			goto error;
1667
+		}
1668
+		/* check whether we have to convert the type */
1669
+		if (convert_val(add_var->type, val, CFG_INPUT_TYPE(var), &v))
1670
+			goto error;
1671
+
1672
+		if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
1673
+		&& (var->def->min || var->def->max)) {
1674
+			/* perform a simple min-max check for integers */
1675
+			if (((int)(long)v < var->def->min)
1676
+			|| ((int)(long)v > var->def->max)) {
1677
+				LOG(L_ERR, "ERROR: cfg_apply_list(): integer value is out of range\n");