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