all: updated FSF address in GPL text
[sip-router] / cfg / cfg_ctx.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2007 iptelorg GmbH
5  *
6  * This file is part of SIP-router, a free SIP server.
7  *
8  * SIP-router is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * SIP-router is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  * History
23  * -------
24  *  2007-12-03  Initial version (Miklos)
25  */
26
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "../ut.h"
32 #include "cfg_struct.h"
33 #include "cfg_script.h"
34 #include "cfg_ctx.h"
35
36
37 /* linked list of all the registered cfg contexts */
38 static cfg_ctx_t        *cfg_ctx_list = NULL;
39
40 /* creates a new config context that is an interface to the
41  * cfg variables with write permission
42  */
43 int cfg_register_ctx(cfg_ctx_t **handle, cfg_on_declare on_declare_cb)
44 {
45         cfg_ctx_t       *ctx;
46         cfg_group_t     *group;
47         str             gname;
48
49         /* allocate memory for the new context
50         Better to use shm mem, because 'changed' and 'lock'
51         must be in shm mem anyway */
52         ctx = (cfg_ctx_t *)shm_malloc(sizeof(cfg_ctx_t));
53         if (!ctx) {
54                 LOG(L_ERR, "ERROR: cfg_register_ctx(): not enough shm memory\n");
55                 return -1;
56         }
57         memset(ctx, 0, sizeof(cfg_ctx_t));
58         if (lock_init(&ctx->lock) == 0) {
59                 LOG(L_ERR, "ERROR: cfg_register_ctx(): failed to init lock\n");
60                 shm_free(ctx);
61                 return -1;
62         }
63
64         /* add the new ctx to the beginning of the list */
65         ctx->next = cfg_ctx_list;
66         cfg_ctx_list = ctx;
67
68         /* let the driver know about the already registered groups
69          * The handle of the context must be set before calling the
70          * on_declare callbacks. */
71         *handle = ctx;
72         if (on_declare_cb) {
73                 ctx->on_declare_cb = on_declare_cb;
74
75                 for (   group = cfg_group;
76                         group;
77                         group = group->next
78                 ) {
79                         /* dynamic groups are not ready, the callback
80                         will be called later when the group is fixed-up */
81                         if (group->dynamic != CFG_GROUP_STATIC) continue;
82
83                         gname.s = group->name;
84                         gname.len = group->name_len;
85                         on_declare_cb(&gname, group->mapping->def);
86                 }
87         }
88
89         return 0;
90 }
91
92 /* free the memory allocated for the contexts */
93 void cfg_ctx_destroy(void)
94 {
95         cfg_ctx_t       *ctx, *ctx2;
96
97         for (   ctx = cfg_ctx_list;
98                 ctx;
99                 ctx = ctx2
100         ) {
101                 ctx2 = ctx->next;
102                 shm_free(ctx);
103         }
104         cfg_ctx_list = NULL;
105 }
106
107 /* notify the drivers about the new config definition */
108 void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def)
109 {
110         cfg_ctx_t       *ctx;
111         str             gname;
112
113         gname.s = group_name;
114         gname.len = group_name_len;
115
116         for (   ctx = cfg_ctx_list;
117                 ctx;
118                 ctx = ctx->next
119         )
120                 if (ctx->on_declare_cb)
121                         ctx->on_declare_cb(&gname, def);
122 }
123
124 /* placeholder for a temporary string */
125 static char     *temp_string = NULL;
126
127 /* convert the value to the requested type */
128 int convert_val(unsigned int val_type, void *val,
129                         unsigned int var_type, void **new_val)
130 {
131         static str      s;
132         char            *end;
133         int             i;
134         static char     buf[INT2STR_MAX_LEN];
135
136         /* we have to convert from val_type to var_type */
137         switch (CFG_INPUT_MASK(var_type)) {
138         case CFG_INPUT_INT:
139                 if (val_type == CFG_VAR_INT) {
140                         *new_val = val;
141                         break;
142
143                 } else if (val_type == CFG_VAR_STRING) {
144                         if (!val || (((char *)val)[0] == '\0')) {
145                                 LOG(L_ERR, "ERROR: convert_val(): "
146                                         "cannot convert NULL string value to integer\n");
147                                 return -1;
148                         }
149                         *new_val = (void *)(long)strtol((char *)val, &end, 10);
150                         if (*end != '\0') {
151                                 LOG(L_ERR, "ERROR: convert_val(): "
152                                         "cannot convert string to integer '%s'\n",
153                                         (char *)val);
154                                 return -1;
155                         }
156                         break;
157
158                 } else if (val_type == CFG_VAR_STR) {
159                         if (!((str *)val)->len || !((str *)val)->s) {
160                                 LOG(L_ERR, "ERROR: convert_val(): "
161                                         "cannot convert NULL str value to integer\n");
162                                 return -1;
163                         }
164                         if (str2sint((str *)val, &i)) {
165                                 LOG(L_ERR, "ERROR: convert_val(): "
166                                         "cannot convert string to integer '%.*s'\n",
167                                         ((str *)val)->len, ((str *)val)->s);
168                                 return -1;
169                         }
170                         *new_val = (void *)(long)i;
171                         break;
172                 }
173                 goto error;
174
175         case CFG_INPUT_STRING:
176                 if (val_type == CFG_VAR_INT) {
177                         buf[snprintf(buf, sizeof(buf)-1, "%ld", (long)val)] = '\0';
178                         *new_val = buf;
179                         break;
180
181                 } else if (val_type == CFG_VAR_STRING) {
182                         *new_val = val;
183                         break;
184
185                 } else if (val_type == CFG_VAR_STR) {
186                         if (!((str *)val)->s) {
187                                 *new_val = NULL;
188                                 break;
189                         }
190                         /* the value may not be zero-terminated, thus,
191                         a new variable has to be allocated with larger memory space */
192                         if (temp_string) pkg_free(temp_string);
193                         temp_string = (char *)pkg_malloc(sizeof(char) * (((str *)val)->len + 1));
194                         if (!temp_string) {
195                                 LOG(L_ERR, "ERROR: convert_val(): not enough memory\n");
196                                 return -1;
197                         }
198                         memcpy(temp_string, ((str *)val)->s, ((str *)val)->len);
199                         temp_string[((str *)val)->len] = '\0';
200                         *new_val = (void *)temp_string;
201                         break;
202
203                 }
204                 goto error;
205
206         case CFG_INPUT_STR:
207                 if (val_type == CFG_VAR_INT) {
208                         s.len = snprintf(buf, sizeof(buf)-1, "%ld", (long)val);
209                         buf[s.len] = '\0';
210                         s.s = buf;
211                         *new_val = (void *)&s;
212                         break;
213
214                 } else if (val_type == CFG_VAR_STRING) {
215                         s.s = (char *)val;
216                         s.len = (s.s) ? strlen(s.s) : 0;
217                         *new_val = (void *)&s;
218                         break;
219
220                 } else if (val_type == CFG_VAR_STR) {
221                         *new_val = val;
222                         break;                  
223                 }
224                 goto error;
225         }
226
227         return 0;
228
229 error:
230         LOG(L_ERR, "ERROR: convert_val(): got a value with type %u, but expected %u\n",
231                         val_type, CFG_INPUT_MASK(var_type));
232         return -1;
233 }
234
235 void convert_val_cleanup(void)
236 {
237         if (temp_string) {
238                 pkg_free(temp_string);
239                 temp_string = NULL;
240         }
241 }
242
243 /* returns the size of the variable */
244 static int cfg_var_size(cfg_mapping_t *var)
245 {
246         switch (CFG_VAR_TYPE(var)) {
247
248         case CFG_VAR_INT:
249                 return sizeof(int);
250
251         case CFG_VAR_STRING:
252                 return sizeof(char *);
253
254         case CFG_VAR_STR:
255                 return sizeof(str);
256
257         case CFG_VAR_POINTER:
258                 return sizeof(void *);
259
260         default:
261                 LOG(L_CRIT, "BUG: cfg_var_size(): unknown type: %u\n",
262                         CFG_VAR_TYPE(var));
263                 return 0;
264         }
265 }
266
267 /* Update the varibales of the array within the meta structure
268  * with the new default value.
269  * The array is cloned before a change if clone is set to 1.
270  */
271 static int cfg_update_defaults(cfg_group_meta_t *meta,
272                                 cfg_group_t *group, cfg_mapping_t *var, char *new_val,
273                                 int clone)
274 {
275         int     i, clone_done=0;
276         cfg_group_inst_t *array, *ginst;
277
278         if (!(array = meta->array))
279                 return 0;
280         for (i = 0; i < meta->num; i++) {
281                 ginst = (cfg_group_inst_t *)((char *)array
282                         + (sizeof(cfg_group_inst_t) + group->size - 1) * i);
283
284                 if (!CFG_VAR_TEST(ginst, var)) {
285                         /* The variable uses the default value, it needs to be rewritten. */
286                         if (clone && !clone_done) {
287                                 /* The array needs to be cloned before the modification */
288                                 if (!(array = cfg_clone_array(meta, group)))
289                                         return -1;
290                                 ginst = (cfg_group_inst_t *)translate_pointer((char *)array,
291                                                                 (char *)meta->array,
292                                                                 (char *)ginst);
293                                 /* re-link the array to the meta-data */
294                                 meta->array = array;
295                                 clone_done = 1;
296                         }
297                         memcpy(ginst->vars + var->offset, new_val, cfg_var_size(var)); 
298                 }
299         }
300         return 0;
301 }
302
303 /* sets the value of a variable without the need of commit
304  *
305  * return value:
306  *   0: success
307  *  -1: error
308  *   1: variable has not been found
309  */
310 int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
311                         void *val, unsigned int val_type)
312 {
313         int             i;
314         cfg_group_t     *group;
315         cfg_mapping_t   *var;
316         void            *p, *v;
317         cfg_block_t     *block = NULL;
318         str             s, s2;
319         char            *old_string = NULL;
320         void            **replaced = NULL;
321         cfg_child_cb_t  *child_cb = NULL;
322         cfg_group_inst_t        *group_inst = NULL, *new_array = NULL;
323         unsigned char           *var_block;
324
325         /* verify the context even if we do not need it now
326         to make sure that a cfg driver has called the function
327         (very very weak security) */
328         if (!ctx) {
329                 LOG(L_ERR, "ERROR: cfg_set_now(): context is undefined\n");
330                 return -1;
331         }
332
333         if ((val_type == CFG_VAR_UNSET) && !group_id) {
334                 LOG(L_ERR, "ERROR: cfg_set_now(): Only group instance values can be deleted\n");
335                 return -1;
336         }
337
338         if (group_id && !cfg_shmized) {
339                 /* The config group has not been shmized yet,
340                 but an additional instance of a variable needs to be added to the group.
341                 Add this instance to the linked list of variables, they
342                 will be fixed later. */
343                 return new_add_var(group_name, *group_id, var_name,
344                                 val, val_type);
345         }
346
347         /* look-up the group and the variable */
348         if (cfg_lookup_var(group_name, var_name, &group, &var)) {
349                 if (!cfg_shmized) {
350                         /* The group may be dynamic which is not yet ready
351                          * before forking */
352                         if ((group = cfg_lookup_group(group_name->s, group_name->len))
353                                 && (group->dynamic == CFG_GROUP_DYNAMIC)
354                         )
355                                 return cfg_set_script_var(group, var_name, val, val_type);
356                 }
357                 return 1;
358         }
359                 
360         /* check whether the variable is read-only */
361         if (var->def->type & CFG_READONLY) {
362                 LOG(L_ERR, "ERROR: cfg_set_now(): variable is read-only\n");
363                 goto error0;
364         }
365
366         /* The additional variable instances having per-child process callback
367          * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
368          * The reason is that such variables typically set global parameters
369          * as opposed to per-process variables. Hence, it is not possible to set
370          * the group handle temporary to another block, and then reset it back later. */
371         if (group_id
372                 && var->def->on_set_child_cb
373                 && var->def->type & CFG_CB_ONLY_ONCE
374         ) {
375                 LOG(L_ERR, "ERROR: cfg_set_now(): This variable does not support muliple values.\n");
376                 goto error0;
377         }
378
379         /* check whether we have to convert the type */
380         if ((val_type != CFG_VAR_UNSET)
381                 && convert_val(val_type, val, CFG_INPUT_TYPE(var), &v)
382         )
383                 goto error0;
384         
385         if ((val_type != CFG_VAR_UNSET)
386         && (CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
387         && (var->def->min || var->def->max)) {
388                 /* perform a simple min-max check for integers */
389                 if (((int)(long)v < var->def->min)
390                 || ((int)(long)v > var->def->max)) {
391                         LOG(L_ERR, "ERROR: cfg_set_now(): integer value is out of range\n");
392                         goto error0;
393                 }
394         }
395
396         if ((val_type != CFG_VAR_UNSET)
397                 && var->def->on_change_cb
398         ) {
399                 /* Call the fixup function.
400                 There is no need to set a temporary cfg handle,
401                 becaue a single variable is changed */
402                 if (!group_id) {
403                         var_block = *(group->handle);
404                 } else {
405                         if (!cfg_local) {
406                                 LOG(L_ERR, "ERROR: cfg_set_now(): Local configuration is missing\n");
407                                 goto error0;
408                         }
409                         group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
410                                                         group->size,
411                                                         *group_id);
412                         if (!group_inst) {
413                                 LOG(L_ERR, "ERROR: cfg_set_now(): local group instance %.*s[%u] is not found\n",
414                                         group_name->len, group_name->s, *group_id);
415                                 goto error0;
416                         }
417                         var_block = group_inst->vars;
418                 }
419
420                 if (var->def->on_change_cb(var_block,
421                                                 group_name,
422                                                 var_name,
423                                                 &v) < 0) {
424                         LOG(L_ERR, "ERROR: cfg_set_now(): fixup failed\n");
425                         goto error0;
426                 }
427
428         }
429
430         /* Set the per-child process callback only if the default value is changed.
431          * The callback of other instances will be called when the config is
432          * switched to that instance. */
433         if (!group_id && var->def->on_set_child_cb) {
434                 /* get the name of the variable from the internal struct,
435                 because var_name may be freed before the callback needs it */
436                 s.s = group->name;
437                 s.len = group->name_len;
438                 s2.s = var->def->name;
439                 s2.len = var->name_len;
440                 child_cb = cfg_child_cb_new(&s, &s2,
441                                         var->def->on_set_child_cb,
442                                         var->def->type);
443                 if (!child_cb) {
444                         LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
445                         goto error0;
446                 }
447         }
448
449         if (cfg_shmized) {
450                 /* make sure that nobody else replaces the global config
451                 while the new one is prepared */
452                 CFG_WRITER_LOCK();
453
454                 if (group_id) {
455                         group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group),
456                                                         group->size,
457                                                         *group_id);
458                         if (!group_inst) {
459                                 LOG(L_ERR, "ERROR: cfg_set_now(): global group instance %.*s[%u] is not found\n",
460                                         group_name->len, group_name->s, *group_id);
461                                 goto error;
462                         }
463                         if ((val_type == CFG_VAR_UNSET) && !CFG_VAR_TEST(group_inst, var)) {
464                                 /* nothing to do, the variable is not set in the group instance */
465                                 CFG_WRITER_UNLOCK();
466                                 LOG(L_DBG, "DEBUG: cfg_set_now(): The variable is not set\n");
467                                 return 0;
468                         }
469                         var_block = group_inst->vars;
470                 } else {
471                         group_inst = NULL;
472                         var_block = CFG_GROUP_DATA(*cfg_global, group);
473                 }
474
475                 if (var->def->type & CFG_ATOMIC) {
476                         /* atomic change is allowed, we can rewrite the value
477                         directly in the global config */
478                         p = var_block + var->offset;
479
480                 } else {
481                         /* clone the memory block, and prepare the modification */
482                         if (!(block = cfg_clone_global())) goto error;
483
484                         if (group_inst) {
485                                 /* The additional array of the group needs to be also cloned.
486                                  * When any of the variables within this array is changed, then
487                                  * the complete config block and this array is replaced. */
488                                 if (!(new_array = cfg_clone_array(CFG_GROUP_META(*cfg_global, group), group)))
489                                         goto error;
490                                 group_inst = (cfg_group_inst_t *)translate_pointer((char *)new_array,
491                                         (char *)CFG_GROUP_META(*cfg_global, group)->array,
492                                         (char *)group_inst);
493                                 var_block = group_inst->vars;
494                                 CFG_GROUP_META(block, group)->array = new_array;
495                         } else {
496                                 /* The additional array may need to be replaced depending
497                                  * on whether or not there is any variable in the array set
498                                  * to the default value which is changed now. If this is the case,
499                                  * then the array will be replaced later when the variables are
500                                  * updated.
501                                  */
502                                 var_block = CFG_GROUP_DATA(block, group);
503                         }
504                         p = var_block + var->offset;
505                 }
506         } else {
507                 /* we are allowed to rewrite the value on-the-fly
508                 The handle either points to group->vars, or to the
509                 shared memory block (dynamic group) */
510                 p = *(group->handle) + var->offset;
511         }
512
513         if (val_type != CFG_VAR_UNSET) {
514                 /* set the new value */
515                 switch (CFG_VAR_TYPE(var)) {
516                 case CFG_VAR_INT:
517                         *(int *)p = (int)(long)v;
518                         break;
519
520                 case CFG_VAR_STRING:
521                         /* clone the string to shm mem */
522                         s.s = v;
523                         s.len = (s.s) ? strlen(s.s) : 0;
524                         if (cfg_clone_str(&s, &s)) goto error;
525                         old_string = *(char **)p;
526                         *(char **)p = s.s;
527                         break;
528
529                 case CFG_VAR_STR:
530                         /* clone the string to shm mem */
531                         s = *(str *)v;
532                         if (cfg_clone_str(&s, &s)) goto error;
533                         old_string = *(char **)p;
534                         memcpy(p, &s, sizeof(str));
535                         break;
536
537                 case CFG_VAR_POINTER:
538                         *(void **)p = v;
539                         break;
540
541                 }
542                 if (group_inst && !CFG_VAR_TEST_AND_SET(group_inst, var))
543                         old_string = NULL; /* the string is the same as the default one,
544                                                 it cannot be freed */
545         } else {
546                 /* copy the default value to the group instance */
547                 if ((CFG_VAR_TYPE(var) == CFG_VAR_STRING)
548                 || (CFG_VAR_TYPE(var) == CFG_VAR_STR))
549                         old_string = *(char **)p;
550                 memcpy(p, CFG_GROUP_DATA(*cfg_global, group) + var->offset, cfg_var_size(var)); 
551
552                 CFG_VAR_TEST_AND_RESET(group_inst, var);
553         }
554
555         if (cfg_shmized) {
556                 if (!group_inst) {
557                         /* the default value is changed, the copies of this value
558                         need to be also updated */
559                         if (cfg_update_defaults(CFG_GROUP_META(block ? block : *cfg_global, group),
560                                                 group, var, p,
561                                                 block ? 1 : 0) /* clone if needed */
562                         )
563                                 goto error;
564                         if (block && (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array))
565                                 new_array = CFG_GROUP_META(block, group)->array;
566                 }
567
568                 if (old_string || new_array) {
569                         /* prepare the array of the replaced strings,
570                         and replaced group instances,
571                         they will be freed when the old block is freed */
572                         replaced = (void **)shm_malloc(sizeof(void *)
573                                         * ((old_string?1:0) + (new_array?1:0) + 1));
574                         if (!replaced) {
575                                 LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
576                                 goto error;
577                         }
578                         i = 0;
579                         if (old_string) {
580                                 replaced[i] = old_string;
581                                 i++;
582                         }
583                         if (new_array) {        
584                                 replaced[i] = CFG_GROUP_META(*cfg_global, group)->array;
585                                 i++;
586                         }
587                         replaced[i] = NULL;
588                 }
589                 /* replace the global config with the new one */
590                 if (block) cfg_install_global(block, replaced, child_cb, child_cb);
591                 CFG_WRITER_UNLOCK();
592         } else {
593                 /* cfg_set() may be called more than once before forking */
594                 if (old_string && (var->flag & cfg_var_shmized))
595                         shm_free(old_string);
596
597                 /* flag the variable because there is no need
598                 to shmize it again */
599                 var->flag |= cfg_var_shmized;
600
601                 /* the global config does not have to be replaced,
602                 but the child callback has to be installed, otherwise the
603                 child processes will miss the change */
604                 if (child_cb)
605                         cfg_install_child_cb(child_cb, child_cb);
606         }
607
608         if (val_type == CFG_VAR_INT)
609                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
610                         "has been changed to %d\n",
611                         group_name->len, group_name->s,
612                         var_name->len, var_name->s,
613                         (int)(long)val);
614
615         else if (val_type == CFG_VAR_STRING)
616                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
617                         "has been changed to \"%s\"\n",
618                         group_name->len, group_name->s,
619                         var_name->len, var_name->s,
620                         (char *)val);
621
622         else if (val_type == CFG_VAR_STR)
623                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
624                         "has been changed to \"%.*s\"\n",
625                         group_name->len, group_name->s,
626                         var_name->len, var_name->s,
627                         ((str *)val)->len, ((str *)val)->s);
628
629         else if (val_type == CFG_VAR_UNSET)
630                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
631                         "has been deleted\n",
632                         group_name->len, group_name->s,
633                         var_name->len, var_name->s);
634
635         else
636                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
637                         "has been changed\n",
638                         group_name->len, group_name->s,
639                         var_name->len, var_name->s);
640
641         if (group_id)
642                 LOG(L_INFO, "INFO: cfg_set_now(): group id = %u\n",
643                         *group_id);
644
645         convert_val_cleanup();
646         return 0;
647
648 error:
649         if (cfg_shmized) CFG_WRITER_UNLOCK();
650         if (block) cfg_block_free(block);
651         if (new_array) shm_free(new_array);
652         if (child_cb) cfg_child_cb_free_list(child_cb);
653         if (replaced) shm_free(replaced);
654
655 error0:
656         LOG(L_ERR, "ERROR: cfg_set_now(): failed to set the variable: %.*s.%.*s\n",
657                         group_name->len, group_name->s,
658                         var_name->len, var_name->s);
659
660
661         convert_val_cleanup();
662         return -1;
663 }
664
665 /* wrapper function for cfg_set_now */
666 int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
667                         int val)
668 {
669         return cfg_set_now(ctx, group_name, group_id, var_name,
670                                 (void *)(long)val, CFG_VAR_INT);
671 }
672
673 /* wrapper function for cfg_set_now */
674 int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
675                         char *val)
676 {
677         return cfg_set_now(ctx, group_name, group_id, var_name,
678                                 (void *)val, CFG_VAR_STRING);
679 }
680
681 /* wrapper function for cfg_set_now */
682 int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
683                         str *val)
684 {
685         return cfg_set_now(ctx, group_name, group_id, var_name,
686                                 (void *)val, CFG_VAR_STR);
687 }
688
689 /* Delete a variable from the group instance.
690  * wrapper function for cfg_set_now */
691 int cfg_del_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name)
692 {
693         return cfg_set_now(ctx, group_name, group_id, var_name,
694                                 NULL, CFG_VAR_UNSET);
695 }
696
697 /* sets the value of a variable but does not commit the change
698  *
699  * return value:
700  *   0: success
701  *  -1: error
702  *   1: variable has not been found
703  */
704 int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
705                         void *val, unsigned int val_type)
706 {
707         cfg_group_t     *group;
708         cfg_mapping_t   *var;
709         void            *v;
710         unsigned char   *temp_handle;
711         int             temp_handle_created;
712         cfg_changed_var_t       *changed = NULL, **changed_p;
713         int             size;
714         str             s;
715         cfg_group_inst_t        *group_inst = NULL;
716         unsigned char           *var_block;
717
718         if (!cfg_shmized)
719                 /* the cfg has not been shmized yet, there is no
720                 point in registering the change and committing it later */
721                 return cfg_set_now(ctx, group_name, group_id, var_name,
722                                         val, val_type);
723
724         if (!ctx) {
725                 LOG(L_ERR, "ERROR: cfg_set_delayed(): context is undefined\n");
726                 return -1;
727         }
728
729         if ((val_type == CFG_VAR_UNSET) && !group_id) {
730                 LOG(L_ERR, "ERROR: cfg_set_delayed(): Only group instance values can be deleted\n");
731                 return -1;
732         }
733
734         /* look-up the group and the variable */
735         if (cfg_lookup_var(group_name, var_name, &group, &var))
736                 return 1;
737
738         /* check whether the variable is read-only */
739         if (var->def->type & CFG_READONLY) {
740                 LOG(L_ERR, "ERROR: cfg_set_delayed(): variable is read-only\n");
741                 goto error0;
742         }
743
744         /* The additional variable instances having per-child process callback
745          * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
746          * The reason is that such variables typically set global parameters
747          * as opposed to per-process variables. Hence, it is not possible to set
748          * the group handle temporary to another block, and then reset it back later. */
749         if (group_id
750                 && var->def->on_set_child_cb
751                 && var->def->type & CFG_CB_ONLY_ONCE
752         ) {
753                 LOG(L_ERR, "ERROR: cfg_set_delayed(): This variable does not support muliple values.\n");
754                 goto error0;
755         }
756
757         /* check whether we have to convert the type */
758         if ((val_type != CFG_VAR_UNSET)
759                 && convert_val(val_type, val, CFG_INPUT_TYPE(var), &v)
760         )
761                 goto error0;
762
763         if ((val_type != CFG_VAR_UNSET)
764         && (CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
765         && (var->def->min || var->def->max)) {
766                 /* perform a simple min-max check for integers */
767                 if (((int)(long)v < var->def->min)
768                 || ((int)(long)v > var->def->max)) {
769                         LOG(L_ERR, "ERROR: cfg_set_delayed(): integer value is out of range\n");
770                         goto error0;
771                 }
772         }
773
774         /* the ctx must be locked while reading and writing
775         the list of changed variables */
776         CFG_CTX_LOCK(ctx);
777
778         if ((val_type != CFG_VAR_UNSET) && var->def->on_change_cb) {
779                 /* The fixup function must see also the
780                 not yet committed values, so a temporary handle
781                 must be prepared that points to the new config.
782                 Only the values within the group are applied,
783                 other modifications are not visible to the callback.
784                 The local config is the base. */
785                 if (!group_id) {
786                         var_block = *(group->handle);
787                 } else {
788                         if (!cfg_local) {
789                                 LOG(L_ERR, "ERROR: cfg_set_delayed(): Local configuration is missing\n");
790                                 goto error;
791                         }
792                         group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
793                                                         group->size,
794                                                         *group_id);
795                         if (!group_inst) {
796                                 LOG(L_ERR, "ERROR: cfg_set_delayed(): local group instance %.*s[%u] is not found\n",
797                                         group_name->len, group_name->s, *group_id);
798                                 goto error;
799                         }
800                         var_block = group_inst->vars;
801                 }
802
803                 if (ctx->changed_first) {
804                         temp_handle = (unsigned char *)pkg_malloc(group->size);
805                         if (!temp_handle) {
806                                 LOG(L_ERR, "ERROR: cfg_set_delayed(): "
807                                         "not enough memory\n");
808                                 goto error;
809                         }
810                         temp_handle_created = 1;
811                         memcpy(temp_handle, var_block, group->size);
812
813                         /* apply the changes */
814                         for (   changed = ctx->changed_first;
815                                 changed;
816                                 changed = changed->next
817                         ) {
818                                 if (changed->group != group)
819                                         continue;
820                                 if ((!group_id && !changed->group_id_set) /* default values */
821                                         || (group_id && !changed->group_id_set
822                                                 && !CFG_VAR_TEST(group_inst, changed->var))
823                                                         /* default value is changed which affects the group_instance */
824                                         || (group_id && changed->group_id_set
825                                                 && (*group_id == changed->group_id))
826                                                         /* change within the group instance */
827                                 )
828                                         memcpy( temp_handle + changed->var->offset,
829                                                 changed->new_val.vraw,
830                                                 cfg_var_size(changed->var));
831                         }
832                 } else {
833                         /* there is not any change */
834                         temp_handle = var_block;
835                         temp_handle_created = 0;
836                 }
837                         
838                 if (var->def->on_change_cb(temp_handle,
839                                                 group_name,
840                                                 var_name,
841                                                 &v) < 0) {
842                         LOG(L_ERR, "ERROR: cfg_set_delayed(): fixup failed\n");
843                         if (temp_handle_created) pkg_free(temp_handle);
844                         goto error;
845                 }
846                 if (temp_handle_created) pkg_free(temp_handle);
847
848         }
849
850         /* everything went ok, we can add the new value to the list */
851         size = sizeof(cfg_changed_var_t)
852                 - sizeof(((cfg_changed_var_t*)0)->new_val)
853                 + ((val_type != CFG_VAR_UNSET) ? cfg_var_size(var) : 0);
854         changed = (cfg_changed_var_t *)shm_malloc(size);
855         if (!changed) {
856                 LOG(L_ERR, "ERROR: cfg_set_delayed(): not enough shm memory\n");
857                 goto error;
858         }
859         memset(changed, 0, size);
860         changed->group = group;
861         changed->var = var;
862         if (group_id) {
863                 changed->group_id = *group_id;
864                 changed->group_id_set = 1;
865         }
866
867         if (val_type != CFG_VAR_UNSET) {
868                 switch (CFG_VAR_TYPE(var)) {
869
870                 case CFG_VAR_INT:
871                         changed->new_val.vint = (int)(long)v;
872                         break;
873
874                 case CFG_VAR_STRING:
875                         /* clone the string to shm mem */
876                         s.s = v;
877                         s.len = (s.s) ? strlen(s.s) : 0;
878                         if (cfg_clone_str(&s, &s)) goto error;
879                         changed->new_val.vp = s.s;
880                         break;
881
882                 case CFG_VAR_STR:
883                         /* clone the string to shm mem */
884                         s = *(str *)v;
885                         if (cfg_clone_str(&s, &s)) goto error;
886                         changed->new_val.vstr=s;
887                         break;
888
889                 case CFG_VAR_POINTER:
890                         changed->new_val.vp=v;
891                         break;
892
893                 }
894         } else {
895                 changed->del_value = 1;
896         }
897
898         /* Order the changes by group + group_id + original order.
899          * Hence, the list is still kept in order within the group.
900          * The changes can be committed faster this way, the group instances
901          * do not have to be looked-up for each and every variable. */
902         /* Check whether there is any variable in the list which
903         belongs to the same group */
904         for (   changed_p = &ctx->changed_first;
905                 *changed_p && ((*changed_p)->group != changed->group);
906                 changed_p = &(*changed_p)->next);
907         /* try to find the group instance, and move changed_p to the end of
908         the instance. */
909         for (   ;
910                 *changed_p
911                         && ((*changed_p)->group == changed->group)
912                         && (!(*changed_p)->group_id_set
913                                 || ((*changed_p)->group_id_set && changed->group_id_set
914                                         && ((*changed_p)->group_id <= changed->group_id)));
915                 changed_p = &(*changed_p)->next);
916         /* Add the new variable before *changed_p */
917         changed->next = *changed_p;
918         *changed_p = changed;
919
920         CFG_CTX_UNLOCK(ctx);
921
922         if (val_type == CFG_VAR_INT)
923                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
924                         "is going to be changed to %d "
925                         "[context=%p]\n",
926                         group_name->len, group_name->s,
927                         var_name->len, var_name->s,
928                         (int)(long)val,
929                         ctx);
930
931         else if (val_type == CFG_VAR_STRING)
932                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
933                         "is going to be changed to \"%s\" "
934                         "[context=%p]\n",
935                         group_name->len, group_name->s,
936                         var_name->len, var_name->s,
937                         (char *)val,
938                         ctx);
939
940         else if (val_type == CFG_VAR_STR)
941                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
942                         "is going to be changed to \"%.*s\" "
943                         "[context=%p]\n",
944                         group_name->len, group_name->s,
945                         var_name->len, var_name->s,
946                         ((str *)val)->len, ((str *)val)->s,
947                         ctx);
948
949         else if (val_type == CFG_VAR_UNSET)
950                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
951                         "is going to be deleted "
952                         "[context=%p]\n",
953                         group_name->len, group_name->s,
954                         var_name->len, var_name->s,
955                         ctx);
956
957         else
958                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
959                         "is going to be changed "
960                         "[context=%p]\n",
961                         group_name->len, group_name->s,
962                         var_name->len, var_name->s,
963                         ctx);
964
965         if (group_id)
966                 LOG(L_INFO, "INFO: cfg_set_delayed(): group id = %u "
967                         "[context=%p]\n",
968                         *group_id,
969                         ctx);
970
971         convert_val_cleanup();
972         return 0;
973
974 error:
975         CFG_CTX_UNLOCK(ctx);
976         if (changed) shm_free(changed);
977 error0:
978         LOG(L_ERR, "ERROR: cfg_set_delayed(): failed to set the variable: %.*s.%.*s\n",
979                         group_name->len, group_name->s,
980                         var_name->len, var_name->s);
981
982         convert_val_cleanup();
983         return -1;
984 }
985
986 /* wrapper function for cfg_set_delayed */
987 int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
988                                 int val)
989 {
990         return cfg_set_delayed(ctx, group_name, group_id, var_name,
991                                 (void *)(long)val, CFG_VAR_INT);
992 }
993
994 /* wrapper function for cfg_set_delayed */
995 int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
996                                 char *val)
997 {
998         return cfg_set_delayed(ctx, group_name, group_id, var_name,
999                                 (void *)val, CFG_VAR_STRING);
1000 }
1001
1002 /* wrapper function for cfg_set_delayed */
1003 int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
1004                                 str *val)
1005 {
1006         return cfg_set_delayed(ctx, group_name, group_id, var_name,
1007                                 (void *)val, CFG_VAR_STR);
1008 }
1009
1010 /* Delete a variable from the group instance.
1011  * wrapper function for cfg_set_delayed */
1012 int cfg_del_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name)
1013 {
1014         return cfg_set_delayed(ctx, group_name, group_id, var_name,
1015                                 NULL, CFG_VAR_UNSET);
1016 }
1017
1018 /* commits the previously prepared changes within the context */
1019 int cfg_commit(cfg_ctx_t *ctx)
1020 {
1021         int     replaced_num = 0;
1022         cfg_changed_var_t       *changed, *changed2;
1023         cfg_block_t     *block = NULL;
1024         void    **replaced = NULL;
1025         cfg_child_cb_t  *child_cb;
1026         cfg_child_cb_t  *child_cb_first = NULL;
1027         cfg_child_cb_t  *child_cb_last = NULL;
1028         int     size;
1029         void    *p;
1030         str     s, s2;
1031         cfg_group_t     *group;
1032         cfg_group_inst_t        *group_inst = NULL;
1033
1034         if (!ctx) {
1035                 LOG(L_ERR, "ERROR: cfg_commit(): context is undefined\n");
1036                 return -1;
1037         }
1038
1039         if (!cfg_shmized) return 0; /* nothing to do */
1040
1041         /* the ctx must be locked while reading and writing
1042         the list of changed variables */
1043         CFG_CTX_LOCK(ctx);
1044
1045         /* is there any change? */
1046         if (!ctx->changed_first) goto done;
1047
1048         /* Count the number of replaced strings,
1049         and replaced group arrays.
1050         Prepare the linked list of per-child process
1051         callbacks, that will be added to the global list. */
1052         for (   changed = ctx->changed_first, group = NULL;
1053                 changed;
1054                 changed = changed->next
1055         ) {
1056                 /* Each string/str potentially causes an old string to be freed
1057                  * unless the variable of an additional group instance is set
1058                  * which uses the default value. This case cannot be determined
1059                  * without locking *cfg_global, hence, it is better to count these
1060                  * strings as well even though the slot might not be used later. */
1061                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1062                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1063                         replaced_num++;
1064
1065                 /* See the above comments for strings */
1066                 if (group != changed->group) {
1067                         replaced_num++;
1068                         group = changed->group;
1069                 }
1070
1071                 if (changed->group && !changed->group_id_set && changed->var->def->on_set_child_cb) {
1072                         s.s = changed->group->name;
1073                         s.len = changed->group->name_len;
1074                         s2.s = changed->var->def->name;
1075                         s2.len = changed->var->name_len;
1076                         child_cb = cfg_child_cb_new(&s, &s2,
1077                                         changed->var->def->on_set_child_cb,
1078                                         changed->var->def->type);
1079                         if (!child_cb) goto error0;
1080
1081                         if (child_cb_last)
1082                                 child_cb_last->next = child_cb;
1083                         else
1084                                 child_cb_first = child_cb;
1085                         child_cb_last = child_cb;
1086                 }
1087         }
1088
1089         if (replaced_num) {
1090                 /* allocate memory for the replaced string array */
1091                 size = sizeof(void *)*(replaced_num + 1);
1092                 replaced = (void **)shm_malloc(size);
1093                 if (!replaced) {
1094                         LOG(L_ERR, "ERROR: cfg_commit(): not enough shm memory\n");
1095                         goto error0;
1096                 }
1097                 memset(replaced, 0 , size);
1098         }
1099
1100         /* make sure that nobody else replaces the global config
1101         while the new one is prepared */
1102         CFG_WRITER_LOCK();
1103
1104         /* clone the memory block, and prepare the modification */
1105         if (!(block = cfg_clone_global()))
1106                 goto error;
1107
1108         /* Apply the modifications to the buffer.
1109         Note that the cycle relies on the order of the groups and group instances, i.e.
1110         the order is group + group_id + order of commits. */
1111         replaced_num = 0;
1112         for (   changed = ctx->changed_first, group = NULL; /* group points to the
1113                                                         last group array that has been cloned */
1114                 changed;
1115                 changed = changed->next
1116         ) {
1117                 if (!changed->group_id_set) {
1118                         p = CFG_GROUP_DATA(block, changed->group)
1119                                 + changed->var->offset;
1120                         group_inst = NULL; /* force the look-up of the next group_inst */
1121                 } else {
1122                         if (group != changed->group) {
1123                                 /* The group array has not been cloned yet. */
1124                                 group = changed->group;
1125                                 if (!(CFG_GROUP_META(block, group)->array = 
1126                                         cfg_clone_array(CFG_GROUP_META(*cfg_global, group), group))
1127                                 ) {
1128                                         LOG(L_ERR, "ERROR: cfg_commit(): group array cannot be cloned for %.*s[%u]\n",
1129                                                 group->name_len, group->name, changed->group_id);
1130                                         goto error;
1131                                 }
1132
1133                                 replaced[replaced_num] = CFG_GROUP_META(*cfg_global, group)->array;
1134                                 replaced_num++;
1135
1136                                 group_inst = NULL; /* fore the look-up of group_inst */
1137                         }
1138                         if (group && (!group_inst || (group_inst->id != changed->group_id))) {
1139                                 group_inst = cfg_find_group(CFG_GROUP_META(block, group),
1140                                                                 group->size,
1141                                                                 changed->group_id);
1142                         }
1143                         if (group && !group_inst) {
1144                                 LOG(L_ERR, "ERROR: cfg_commit(): global group instance %.*s[%u] is not found\n",
1145                                         group->name_len, group->name, changed->group_id);
1146                                 goto error;
1147                         }
1148                         p = group_inst->vars + changed->var->offset;
1149                 }
1150
1151                 if (((changed->group_id_set && !changed->del_value && CFG_VAR_TEST_AND_SET(group_inst, changed->var))
1152                         || (changed->group_id_set && changed->del_value && CFG_VAR_TEST_AND_RESET(group_inst, changed->var))
1153                         || !changed->group_id_set)
1154                 && ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1155                         || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1156                 ) {
1157                         replaced[replaced_num] = *(char **)p;
1158                         if (replaced[replaced_num])
1159                                 replaced_num++;
1160                         /* else do not increase replaced_num, because
1161                         the cfg_block_free() will stop at the first
1162                         NULL value */
1163                 }
1164
1165                 if (!changed->del_value)
1166                         memcpy( p,
1167                                 changed->new_val.vraw,
1168                                 cfg_var_size(changed->var));
1169                 else
1170                         memcpy( p,
1171                                 CFG_GROUP_DATA(block, changed->group) + changed->var->offset,
1172                                 cfg_var_size(changed->var));
1173
1174
1175                 if (!changed->group_id_set) {
1176                         /* the default value is changed, the copies of this value
1177                         need to be also updated */
1178                         if (cfg_update_defaults(CFG_GROUP_META(block, changed->group),
1179                                                 changed->group, changed->var, p,
1180                                                 (group != changed->group)) /* clone if the array
1181                                                                         has not been cloned yet */
1182                         )
1183                                 goto error;
1184                         if ((group != changed->group)
1185                                 && (CFG_GROUP_META(block, changed->group)->array != CFG_GROUP_META(*cfg_global, changed->group)->array)
1186                         ) {
1187                                 /* The array has been cloned */
1188                                 group = changed->group;
1189
1190                                 replaced[replaced_num] = CFG_GROUP_META(*cfg_global, group)->array;
1191                                 replaced_num++;
1192                         }
1193                 }
1194         }
1195
1196         /* replace the global config with the new one */
1197         cfg_install_global(block, replaced, child_cb_first, child_cb_last);
1198         CFG_WRITER_UNLOCK();
1199
1200         /* free the changed list */
1201         for (   changed = ctx->changed_first;
1202                 changed;
1203                 changed = changed2
1204         ) {
1205                 changed2 = changed->next;
1206                 shm_free(changed);
1207         }
1208         ctx->changed_first = NULL;
1209
1210 done:
1211         LOG(L_INFO, "INFO: cfg_commit(): config changes have been applied "
1212                         "[context=%p]\n",
1213                         ctx);
1214
1215         CFG_CTX_UNLOCK(ctx);
1216         return 0;
1217
1218 error:
1219         if (block) {
1220                 /* clean the new block from the cloned arrays */
1221                 for (   group = cfg_group;
1222                         group;
1223                         group = group->next
1224                 )
1225                         if (CFG_GROUP_META(block, group)->array
1226                                 && (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array)
1227                         )
1228                                 shm_free(CFG_GROUP_META(block, group)->array);
1229                 /* the block can be freed outside of the writer lock */
1230         }
1231         CFG_WRITER_UNLOCK();
1232         if (block)
1233                 shm_free(block);
1234
1235 error0:
1236         CFG_CTX_UNLOCK(ctx);
1237
1238         if (child_cb_first) cfg_child_cb_free_list(child_cb_first);
1239         if (replaced) shm_free(replaced);
1240
1241         return -1;
1242 }
1243
1244 /* drops the not yet committed changes within the context */
1245 int cfg_rollback(cfg_ctx_t *ctx)
1246 {
1247         cfg_changed_var_t       *changed, *changed2;
1248
1249         if (!ctx) {
1250                 LOG(L_ERR, "ERROR: cfg_rollback(): context is undefined\n");
1251                 return -1;
1252         }
1253
1254         if (!cfg_shmized) return 0; /* nothing to do */
1255
1256         LOG(L_INFO, "INFO: cfg_rollback(): deleting the config changes "
1257                         "[context=%p]\n",
1258                         ctx);
1259
1260         /* the ctx must be locked while reading and writing
1261         the list of changed variables */
1262         CFG_CTX_LOCK(ctx);
1263
1264         for (   changed = ctx->changed_first;
1265                 changed;
1266                 changed = changed2
1267         ) {
1268                 changed2 = changed->next;
1269
1270                 if (!changed->del_value
1271                         && ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1272                                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1273                 ) {
1274                         if (changed->new_val.vp)
1275                                 shm_free(changed->new_val.vp);
1276                 }
1277                 shm_free(changed);
1278         }
1279         ctx->changed_first = NULL;
1280
1281         CFG_CTX_UNLOCK(ctx);
1282
1283         return 0;
1284 }
1285
1286 /* retrieves the value of a variable
1287  * Return value:
1288  *  0 - success
1289  * -1 - error
1290  *  1 - variable exists, but it is not readable
1291  */
1292 int cfg_get_by_name(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
1293                         void **val, unsigned int *val_type)
1294 {
1295         cfg_group_t     *group;
1296         cfg_mapping_t   *var;
1297         void            *p;
1298         static str      s;      /* we need the value even
1299                                 after the function returns */
1300         cfg_group_inst_t        *group_inst;
1301
1302         /* verify the context even if we do not need it now
1303         to make sure that a cfg driver has called the function
1304         (very very weak security) */
1305         if (!ctx) {
1306                 LOG(L_ERR, "ERROR: cfg_get_by_name(): context is undefined\n");
1307                 return -1;
1308         }
1309
1310         /* look-up the group and the variable */
1311         if (cfg_lookup_var(group_name, var_name, &group, &var))
1312                 return -1;
1313
1314         if (var->def->on_change_cb) {
1315                 /* The variable cannot be retrieved, because the fixup
1316                 function may have changed it, and it is better to return
1317                 an error than an incorrect value */
1318                 return 1;
1319         }
1320
1321         if (group_id) {
1322                 if (!cfg_local) {
1323                         LOG(L_ERR, "ERROR: cfg_get_by_name(): Local configuration is missing\n");
1324                         return -1;
1325                 }
1326                 group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
1327                                                 group->size,
1328                                                 *group_id);
1329                 if (!group_inst) {
1330                         LOG(L_ERR, "ERROR: cfg_get_by_name(): local group instance %.*s[%u] is not found\n",
1331                                 group_name->len, group_name->s, *group_id);
1332                         return -1;
1333                 }
1334                 p = group_inst->vars + var->offset;
1335
1336         } else {
1337                 /* use the module's handle to access the variable
1338                 It means that the variable is read from the local config
1339                 after forking */
1340                 p = *(group->handle) + var->offset;
1341         }
1342
1343         switch (CFG_VAR_TYPE(var)) {
1344         case CFG_VAR_INT:
1345                 *val = (void *)(long)*(int *)p;
1346                 break;
1347
1348         case CFG_VAR_STRING:
1349                 *val = (void *)*(char **)p;
1350                 break;
1351
1352         case CFG_VAR_STR:
1353                 memcpy(&s, p, sizeof(str));
1354                 *val = (void *)&s;
1355                 break;
1356
1357         case CFG_VAR_POINTER:
1358                 *val = *(void **)p;
1359                 break;
1360
1361         }
1362         *val_type = CFG_VAR_TYPE(var);
1363
1364         return 0;
1365 }
1366
1367 /* returns the description of a variable */
1368 int cfg_help(cfg_ctx_t *ctx, str *group_name, str *var_name,
1369                         char **ch, unsigned int *input_type)
1370 {
1371         cfg_mapping_t   *var;
1372
1373         /* verify the context even if we do not need it now
1374         to make sure that a cfg driver has called the function
1375         (very very weak security) */
1376         if (!ctx) {
1377                 LOG(L_ERR, "ERROR: cfg_help(): context is undefined\n");
1378                 return -1;
1379         }
1380
1381         /* look-up the group and the variable */
1382         if (cfg_lookup_var(group_name, var_name, NULL, &var))
1383                 return -1;
1384
1385         *ch = var->def->descr;
1386         if (input_type)
1387                 *input_type = CFG_INPUT_TYPE(var);
1388         return 0;
1389 }
1390
1391 /* return the group name and the cfg structure definition,
1392  * and moves the handle to the next group
1393  * Return value:
1394  *      0: no more group
1395  *      1: group exists
1396  */
1397 int cfg_get_group_next(void **h,
1398                         str *gname, cfg_def_t **def)
1399 {
1400         cfg_group_t     *group;
1401
1402         group = (cfg_group_t *)(*h);
1403         if (group == NULL) return 0;
1404
1405         gname->s = group->name;
1406         gname->len = group->name_len;
1407         (*def) = group->mapping->def;
1408
1409         (*h) = (void *)group->next;
1410         return 1;
1411 }
1412
1413 /* Initialize the handle for cfg_diff_next() */
1414 int cfg_diff_init(cfg_ctx_t *ctx,
1415                 void **h)
1416 {
1417         if (!ctx) {
1418                 LOG(L_ERR, "ERROR: cfg_diff_init(): context is undefined\n");
1419                 return -1;
1420         }
1421
1422         CFG_CTX_LOCK(ctx);
1423         (*h) = (void *)ctx->changed_first;
1424
1425         return 0;
1426 }
1427
1428 /* return the pending changes that have not been
1429  * committed yet
1430  * return value:
1431  *      1: valid value is found
1432  *      0: no more changed value found
1433  *      -1: error occured 
1434  */
1435 int cfg_diff_next(void **h,
1436                         str *gname, unsigned int **gid, str *vname,
1437                         void **old_val, void **new_val,
1438                         unsigned int *val_type)
1439 {
1440         cfg_changed_var_t       *changed;
1441         cfg_group_inst_t        *group_inst;
1442         union cfg_var_value     *pval_old, *pval_new;
1443         static str      old_s, new_s;   /* we need the value even
1444                                         after the function returns */
1445
1446         changed = (cfg_changed_var_t *)(*h);
1447         if (changed == NULL) return 0;
1448
1449         gname->s = changed->group->name;
1450         gname->len = changed->group->name_len;
1451         *gid = (changed->group_id_set ? &changed->group_id : NULL);
1452         vname->s = changed->var->def->name;
1453         vname->len = changed->var->name_len;
1454
1455         /* use the module's handle to access the variable
1456         It means that the variable is read from the local config
1457         after forking */
1458         if (!changed->group_id_set) {
1459                 pval_old = (union cfg_var_value*)
1460                                 (*(changed->group->handle) + changed->var->offset);
1461         } else {
1462                 if (!cfg_local) {
1463                         LOG(L_ERR, "ERROR: cfg_diff_next(): Local configuration is missing\n");
1464                         return -1;
1465                 }
1466                 group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, changed->group),
1467                                                 changed->group->size,
1468                                                 changed->group_id);
1469                 if (!group_inst) {
1470                         LOG(L_ERR, "ERROR: cfg_diff_next(): local group instance %.*s[%u] is not found\n",
1471                                 changed->group->name_len, changed->group->name, changed->group_id);
1472                         return -1;
1473                 }
1474                 pval_old = (union cfg_var_value*)
1475                                 (group_inst->vars + changed->var->offset);
1476         }
1477         if (!changed->del_value)
1478                 pval_new = &changed->new_val;
1479         else
1480                 pval_new = (union cfg_var_value*)
1481                                 (*(changed->group->handle) + changed->var->offset);
1482
1483         switch (CFG_VAR_TYPE(changed->var)) {
1484         case CFG_VAR_INT:
1485                 *old_val = (void *)(long)pval_old->vint;
1486                 *new_val = (void *)(long)pval_new->vint;
1487                 break;
1488
1489         case CFG_VAR_STRING:
1490                 *old_val = pval_old->vp;
1491                 *new_val = pval_new->vp;
1492                 break;
1493
1494         case CFG_VAR_STR:
1495                 old_s=pval_old->vstr;
1496                 *old_val = (void *)&old_s;
1497                 new_s=pval_new->vstr;
1498                 *new_val = (void *)&new_s;
1499                 break;
1500
1501         case CFG_VAR_POINTER:
1502                 *old_val = pval_old->vp;
1503                 *new_val = pval_new->vp;
1504                 break;
1505
1506         }
1507         *val_type = CFG_VAR_TYPE(changed->var);
1508
1509         (*h) = (void *)changed->next;
1510         return 1;
1511 }
1512
1513 /* release the handle of cfg_diff_next() */
1514 void cfg_diff_release(cfg_ctx_t *ctx)
1515 {
1516         if (!ctx) {
1517                 LOG(L_ERR, "ERROR: cfg_diff_release(): context is undefined\n");
1518                 return;
1519         }
1520
1521         CFG_CTX_UNLOCK(ctx);
1522 }
1523
1524 /* Add a new instance to an existing group */
1525 int cfg_add_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
1526 {
1527         cfg_group_t     *group;
1528         cfg_block_t     *block = NULL;
1529         void            **replaced = NULL;
1530         cfg_group_inst_t        *new_array = NULL, *new_inst;
1531
1532         /* verify the context even if we do not need it now
1533         to make sure that a cfg driver has called the function
1534         (very very weak security) */
1535         if (!ctx) {
1536                 LOG(L_ERR, "ERROR: cfg_add_group_inst(): context is undefined\n");
1537                 return -1;
1538         }
1539
1540         if (!cfg_shmized) {
1541                 /* Add a new variable without any value to
1542                 the linked list of additional values. This variable
1543                 will force a new group instance to be created. */
1544                 return new_add_var(group_name, group_id,  NULL /* var_name */,
1545                                         NULL /* val */, 0 /* type */);
1546         }
1547
1548         if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
1549                 LOG(L_ERR, "ERROR: cfg_add_group_inst(): group not found\n");
1550                 return -1;
1551         }
1552
1553         /* make sure that nobody else replaces the global config
1554         while the new one is prepared */
1555         CFG_WRITER_LOCK();
1556         if (cfg_find_group(CFG_GROUP_META(*cfg_global, group),
1557                                                         group->size,
1558                                                         group_id)
1559         ) {
1560                 LOG(L_DBG, "DEBUG: cfg_add_group_inst(): the group instance already exists\n");
1561                 CFG_WRITER_UNLOCK();
1562                 return 0; /* not an error */
1563         }
1564
1565         /* clone the global memory block because the additional array can be
1566         replaced only together with the block. */
1567         if (!(block = cfg_clone_global()))
1568                 goto error;
1569
1570         /* Extend the array with a new group instance */
1571         if (!(new_array = cfg_extend_array(CFG_GROUP_META(*cfg_global, group), group,
1572                                         group_id,
1573                                         &new_inst))
1574         )
1575                 goto error;
1576
1577         /* fill in the new group instance with the default data */
1578         memcpy( new_inst->vars,
1579                 CFG_GROUP_DATA(*cfg_global, group),
1580                 group->size);
1581
1582         CFG_GROUP_META(block, group)->array = new_array;
1583         CFG_GROUP_META(block, group)->num++;
1584
1585         if (CFG_GROUP_META(*cfg_global, group)->array) {
1586                 /* prepare the array of the replaced strings,
1587                 and replaced group instances,
1588                 they will be freed when the old block is freed */
1589                 replaced = (void **)shm_malloc(sizeof(void *) * 2);
1590                 if (!replaced) {
1591                         LOG(L_ERR, "ERROR: cfg_add_group_inst(): not enough shm memory\n");
1592                         goto error;
1593                 }
1594                 replaced[0] = CFG_GROUP_META(*cfg_global, group)->array;
1595                 replaced[1] = NULL;
1596         }
1597         /* replace the global config with the new one */
1598         cfg_install_global(block, replaced, NULL, NULL);
1599         CFG_WRITER_UNLOCK();
1600
1601         LOG(L_INFO, "INFO: cfg_add_group_inst(): "
1602                 "group instance is added: %.*s[%u]\n",
1603                 group_name->len, group_name->s,
1604                 group_id);
1605
1606         /* Make sure that cfg_set_*() sees the change when
1607          * the function is immediately called after the group
1608          * instance has been added. */
1609         cfg_update();
1610
1611         return 0;
1612 error:
1613         CFG_WRITER_UNLOCK();
1614         if (block) cfg_block_free(block);
1615         if (new_array) shm_free(new_array);
1616         if (replaced) shm_free(replaced);
1617
1618         LOG(L_ERR, "ERROR: cfg_add_group_inst(): "
1619                 "Failed to add the group instance: %.*s[%u]\n",
1620                 group_name->len, group_name->s,
1621                 group_id);
1622
1623         return -1;
1624 }
1625
1626 /* Delete an instance of a group */
1627 int cfg_del_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
1628 {
1629         cfg_group_t     *group;
1630         cfg_block_t     *block = NULL;
1631         void            **replaced = NULL;
1632         cfg_group_inst_t        *new_array = NULL, *group_inst;
1633         cfg_mapping_t   *var;
1634         int             i, num;
1635
1636         /* verify the context even if we do not need it now
1637         to make sure that a cfg driver has called the function
1638         (very very weak security) */
1639         if (!ctx) {
1640                 LOG(L_ERR, "ERROR: cfg_del_group_inst(): context is undefined\n");
1641                 return -1;
1642         }
1643
1644         if (!cfg_shmized) {
1645                 /* It makes no sense to delete a group instance that has not
1646                 been created yet */
1647                 return -1;
1648         }
1649
1650         if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
1651                 LOG(L_ERR, "ERROR: cfg_del_group_inst(): group not found\n");
1652                 return -1;
1653         }
1654
1655         /* make sure that nobody else replaces the global config
1656         while the new one is prepared */
1657         CFG_WRITER_LOCK();
1658         if (!(group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group),
1659                                                         group->size,
1660                                                         group_id))
1661         ) {
1662                 LOG(L_DBG, "DEBUG: cfg_del_group_inst(): the group instance does not exist\n");
1663                 goto error;
1664         }
1665
1666         /* clone the global memory block because the additional array can be
1667         replaced only together with the block. */
1668         if (!(block = cfg_clone_global()))
1669                 goto error;
1670
1671         /* Remove the group instance from the array. */
1672         if (cfg_collapse_array(CFG_GROUP_META(*cfg_global, group), group,
1673                                         group_inst,
1674                                         &new_array)
1675         )
1676                 goto error;
1677
1678         CFG_GROUP_META(block, group)->array = new_array;
1679         CFG_GROUP_META(block, group)->num--;
1680
1681         if (CFG_GROUP_META(*cfg_global, group)->array) {
1682                 /* prepare the array of the replaced strings,
1683                 and replaced group instances,
1684                 they will be freed when the old block is freed */
1685
1686                 /* count the number of strings that has to be freed */
1687                 num = 0;
1688                 for (i = 0; i < group->num; i++) {
1689                         var = &group->mapping[i];
1690                         if (CFG_VAR_TEST(group_inst, var)
1691                                 && ((CFG_VAR_TYPE(var) == CFG_VAR_STRING) || (CFG_VAR_TYPE(var) == CFG_VAR_STR))
1692                                 && (*(char **)(group_inst->vars + var->offset) != NULL)
1693                         )
1694                                 num++;
1695                 }
1696
1697                 replaced = (void **)shm_malloc(sizeof(void *) * (num + 2));
1698                 if (!replaced) {
1699                         LOG(L_ERR, "ERROR: cfg_del_group_inst(): not enough shm memory\n");
1700                         goto error;
1701                 }
1702
1703                 if (num) {
1704                         /* There was at least one string to free, go though the list again */
1705                         num = 0;
1706                         for (i = 0; i < group->num; i++) {
1707                                 var = &group->mapping[i];
1708                                 if (CFG_VAR_TEST(group_inst, var)
1709                                         && ((CFG_VAR_TYPE(var) == CFG_VAR_STRING) || (CFG_VAR_TYPE(var) == CFG_VAR_STR))
1710                                         && (*(char **)(group_inst->vars + var->offset) != NULL)
1711                                 ) {
1712                                         replaced[num] = *(char **)(group_inst->vars + var->offset);
1713                                         num++;
1714                                 }
1715                         }
1716                 }
1717
1718                 replaced[num] = CFG_GROUP_META(*cfg_global, group)->array;
1719                 replaced[num+1] = NULL;
1720         }
1721         /* replace the global config with the new one */
1722         cfg_install_global(block, replaced, NULL, NULL);
1723         CFG_WRITER_UNLOCK();
1724
1725         LOG(L_INFO, "INFO: cfg_del_group_inst(): "
1726                 "group instance is deleted: %.*s[%u]\n",
1727                 group_name->len, group_name->s,
1728                 group_id);
1729
1730         /* Make sure that cfg_set_*() sees the change when
1731          * the function is immediately called after the group
1732          * instance has been deleted. */
1733         cfg_update();
1734
1735         return 0;
1736 error:
1737         CFG_WRITER_UNLOCK();
1738         if (block) cfg_block_free(block);
1739         if (new_array) shm_free(new_array);
1740         if (replaced) shm_free(replaced);
1741
1742         LOG(L_ERR, "ERROR: cfg_add_group_inst(): "
1743                 "Failed to delete the group instance: %.*s[%u]\n",
1744                 group_name->len, group_name->s,
1745                 group_id);
1746
1747         return -1;
1748 }
1749
1750 /* Check the existance of a group instance.
1751  * return value:
1752  *      1: exists
1753  *      0: does not exist
1754  */
1755 int cfg_group_inst_exists(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
1756 {
1757         cfg_group_t     *group;
1758         cfg_add_var_t   *add_var;
1759         int     found;
1760
1761         /* verify the context even if we do not need it now
1762         to make sure that a cfg driver has called the function
1763         (very very weak security) */
1764         if (!ctx) {
1765                 LOG(L_ERR, "ERROR: cfg_group_inst_exists(): context is undefined\n");
1766                 return 0;
1767         }
1768
1769         if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
1770                 LOG(L_ERR, "ERROR: cfg_group_inst_exists(): group not found\n");
1771                 return 0;
1772         }
1773
1774         if (!cfg_shmized) {
1775                 /* group instances are stored in the additional variable list
1776                  * before forking */
1777                 found = 0;
1778                 for (   add_var = group->add_var;
1779                         add_var;
1780                         add_var = add_var->next
1781                 )
1782                         if (add_var->group_id == group_id) {
1783                                 found = 1;
1784                                 break;
1785                         }
1786
1787         } else {
1788                 /* make sure that nobody else replaces the global config meantime */
1789                 CFG_WRITER_LOCK();
1790                 found = (cfg_find_group(CFG_GROUP_META(*cfg_global, group),
1791                                                                 group->size,
1792                                                                 group_id)
1793                                 != NULL);
1794                 CFG_WRITER_UNLOCK();
1795         }
1796
1797         return found;
1798 }
1799
1800 /* Apply the changes to a group instance as long as the additional variable
1801  * belongs to the specified group_id. *add_var_p is moved to the next additional
1802  * variable, and all the consumed variables are freed.
1803  * This function can be used only during the cfg shmize process.
1804  * For internal use only!
1805  */
1806 int cfg_apply_list(cfg_group_inst_t *ginst, cfg_group_t *group,
1807                         unsigned int group_id, cfg_add_var_t **add_var_p)
1808 {
1809         cfg_add_var_t   *add_var;
1810         cfg_mapping_t   *var;
1811         void            *val, *v, *p;
1812         str             group_name, var_name, s;
1813         char            *old_string;
1814
1815         group_name.s = group->name;
1816         group_name.len = group->name_len;
1817         while (*add_var_p && ((*add_var_p)->group_id == group_id)) {
1818                 add_var = *add_var_p;
1819
1820                 if (add_var->type == 0)
1821                         goto done; /* Nothing needs to be changed,
1822                                 this additional variable only forces a new
1823                                 group instance to be created. */
1824                 var_name.s = add_var->name;
1825                 var_name.len = add_var->name_len;
1826
1827                 if (!(var = cfg_lookup_var2(group, add_var->name, add_var->name_len))) {
1828                         LOG(L_ERR, "ERROR: cfg_apply_list(): Variable is not found: %.*s.%.*s\n",
1829                                 group->name_len, group->name,
1830                                 add_var->name_len, add_var->name);
1831                         goto error;
1832                 }
1833
1834                 /* check whether the variable is read-only */
1835                 if (var->def->type & CFG_READONLY) {
1836                         LOG(L_ERR, "ERROR: cfg_apply_list(): variable is read-only\n");
1837                         goto error;
1838                 }
1839
1840                 /* The additional variable instances having per-child process callback
1841                  * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
1842                  * The reason is that such variables typically set global parameters
1843                  * as opposed to per-process variables. Hence, it is not possible to set
1844                  * the group handle temporary to another block, and then reset it back later. */
1845                 if (var->def->on_set_child_cb
1846                         && var->def->type & CFG_CB_ONLY_ONCE
1847                 ) {
1848                         LOG(L_ERR, "ERROR: cfg_apply_list(): This variable does not support muliple values.\n");
1849                         goto error;
1850                 }
1851
1852                 switch(add_var->type) {
1853                 case CFG_VAR_INT:
1854                         val = (void *)(long)add_var->val.i;
1855                         break;
1856                 case CFG_VAR_STR:
1857                         val = (str *)&(add_var->val.s);
1858                         break;
1859                 case CFG_VAR_STRING:
1860                         val = (char *)add_var->val.ch;
1861                         break;
1862                 default:
1863                         LOG(L_ERR, "ERROR: cfg_apply_list(): unsupported variable type: %d\n",
1864                                 add_var->type);
1865                         goto error;
1866                 }
1867                 /* check whether we have to convert the type */
1868                 if (convert_val(add_var->type, val, CFG_INPUT_TYPE(var), &v))
1869                         goto error;
1870
1871                 if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
1872                 && (var->def->min || var->def->max)) {
1873                         /* perform a simple min-max check for integers */
1874                         if (((int)(long)v < var->def->min)
1875                         || ((int)(long)v > var->def->max)) {
1876                                 LOG(L_ERR, "ERROR: cfg_apply_list(): integer value is out of range\n");
1877                                 goto error;
1878                         }
1879                 }
1880
1881                 if (var->def->on_change_cb) {
1882                         /* Call the fixup function.
1883                         The handle can point to the variables of the group instance. */
1884                         if (var->def->on_change_cb(ginst->vars,
1885                                                         &group_name,
1886                                                         &var_name,
1887                                                         &v) < 0) {
1888                                 LOG(L_ERR, "ERROR: cfg_apply_list(): fixup failed\n");
1889                                 goto error;
1890                         }
1891                 }
1892
1893                 p = ginst->vars + var->offset;
1894                 old_string = NULL;
1895                 /* set the new value */
1896                 switch (CFG_VAR_TYPE(var)) {
1897                 case CFG_VAR_INT:
1898                         *(int *)p = (int)(long)v;
1899                         break;
1900
1901                 case CFG_VAR_STRING:
1902                         /* clone the string to shm mem */
1903                         s.s = v;
1904                         s.len = (s.s) ? strlen(s.s) : 0;
1905                         if (cfg_clone_str(&s, &s)) goto error;
1906                         old_string = *(char **)p;
1907                         *(char **)p = s.s;
1908                         break;
1909
1910                 case CFG_VAR_STR:
1911                         /* clone the string to shm mem */
1912                         s = *(str *)v;
1913                         if (cfg_clone_str(&s, &s)) goto error;
1914                         old_string = *(char **)p;
1915                         memcpy(p, &s, sizeof(str));
1916                         break;
1917
1918                 case CFG_VAR_POINTER:
1919                         *(void **)p = v;
1920                         break;
1921
1922                 }
1923                 if (CFG_VAR_TEST_AND_SET(ginst, var) && old_string)
1924                         shm_free(old_string); /* the string was already in shm memory,
1925                                         it needs to be freed.
1926                                         This can happen when the same variable is set
1927                                         multiple times before forking. */
1928
1929                 if (add_var->type == CFG_VAR_INT)
1930                         LOG(L_INFO, "INFO: cfg_apply_list(): %.*s[%u].%.*s "
1931                                 "has been set to %d\n",
1932                                 group_name.len, group_name.s,
1933                                 group_id,
1934                                 var_name.len, var_name.s,
1935                                 (int)(long)val);
1936
1937                 else if (add_var->type == CFG_VAR_STRING)
1938                         LOG(L_INFO, "INFO: cfg_apply_list(): %.*s[%u].%.*s "
1939                                 "has been set to \"%s\"\n",
1940                                 group_name.len, group_name.s,
1941                                 group_id,
1942                                 var_name.len, var_name.s,
1943                                 (char *)val);
1944
1945                 else /* str type */
1946                         LOG(L_INFO, "INFO: cfg_apply_list(): %.*s[%u].%.*s "
1947                                 "has been set to \"%.*s\"\n",
1948                                 group_name.len, group_name.s,
1949                                 group_id,
1950                                 var_name.len, var_name.s,
1951                                 ((str *)val)->len, ((str *)val)->s);
1952
1953                 convert_val_cleanup();
1954
1955 done:
1956                 *add_var_p = add_var->next;
1957
1958                 if ((add_var->type == CFG_VAR_STR) && add_var->val.s.s)
1959                         pkg_free(add_var->val.s.s);
1960                 else if ((add_var->type == CFG_VAR_STRING) && add_var->val.ch)
1961                         pkg_free(add_var->val.ch);
1962                 pkg_free(add_var);
1963         }
1964         return 0;
1965
1966 error:
1967         LOG(L_ERR, "ERROR: cfg_apply_list(): Failed to set the value for: %.*s[%u].%.*s\n",
1968                 group->name_len, group->name,
1969                 group_id,
1970                 add_var->name_len, add_var->name);
1971         convert_val_cleanup();
1972         return -1;
1973 }