Merge remote branch 'origin/andrei/pointer_alias_warnings'
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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_ctx.h"
34
35
36 /* linked list of all the registered cfg contexts */
37 static cfg_ctx_t        *cfg_ctx_list = NULL;
38
39 /* creates a new config context that is an interface to the
40  * cfg variables with write permission
41  */
42 int cfg_register_ctx(cfg_ctx_t **handle, cfg_on_declare on_declare_cb)
43 {
44         cfg_ctx_t       *ctx;
45         cfg_group_t     *group;
46         str             gname;
47
48         /* allocate memory for the new context
49         Better to use shm mem, because 'changed' and 'lock'
50         must be in shm mem anyway */
51         ctx = (cfg_ctx_t *)shm_malloc(sizeof(cfg_ctx_t));
52         if (!ctx) {
53                 LOG(L_ERR, "ERROR: cfg_register_ctx(): not enough shm memory\n");
54                 return -1;
55         }
56         memset(ctx, 0, sizeof(cfg_ctx_t));
57         if (lock_init(&ctx->lock) == 0) {
58                 LOG(L_ERR, "ERROR: cfg_register_ctx(): failed to init lock\n");
59                 shm_free(ctx);
60                 return -1;
61         }
62
63         /* add the new ctx to the beginning of the list */
64         ctx->next = cfg_ctx_list;
65         cfg_ctx_list = ctx;
66
67         /* let the driver know about the already registered groups
68          * The handle of the context must be set before calling the
69          * on_declare callbacks. */
70         *handle = ctx;
71         if (on_declare_cb) {
72                 ctx->on_declare_cb = on_declare_cb;
73
74                 for (   group = cfg_group;
75                         group;
76                         group = group->next
77                 ) {
78                         /* dynamic groups are not ready, the callback
79                         will be called later when the group is fixed-up */
80                         if (group->dynamic) continue;
81
82                         gname.s = group->name;
83                         gname.len = group->name_len;
84                         on_declare_cb(&gname, group->mapping->def);
85                 }
86         }
87
88         return 0;
89 }
90
91 /* free the memory allocated for the contexts */
92 void cfg_ctx_destroy(void)
93 {
94         cfg_ctx_t       *ctx, *ctx2;
95
96         for (   ctx = cfg_ctx_list;
97                 ctx;
98                 ctx = ctx2
99         ) {
100                 ctx2 = ctx->next;
101                 shm_free(ctx);
102         }
103         cfg_ctx_list = NULL;
104 }
105
106 /* notify the drivers about the new config definition */
107 void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def)
108 {
109         cfg_ctx_t       *ctx;
110         str             gname;
111
112         gname.s = group_name;
113         gname.len = group_name_len;
114
115         for (   ctx = cfg_ctx_list;
116                 ctx;
117                 ctx = ctx->next
118         )
119                 if (ctx->on_declare_cb)
120                         ctx->on_declare_cb(&gname, def);
121 }
122
123 /* placeholder for a temporary string */
124 static char     *temp_string = NULL;
125
126 /* convert the value to the requested type */
127 int convert_val(unsigned int val_type, void *val,
128                         unsigned int var_type, void **new_val)
129 {
130         static str      s;
131         char            *end;
132         int             i;
133         static char     buf[INT2STR_MAX_LEN];
134
135         /* we have to convert from val_type to var_type */
136         switch (CFG_INPUT_MASK(var_type)) {
137         case CFG_INPUT_INT:
138                 if (val_type == CFG_VAR_INT) {
139                         *new_val = val;
140                         break;
141
142                 } else if (val_type == CFG_VAR_STRING) {
143                         if (!val || (((char *)val)[0] == '\0')) {
144                                 LOG(L_ERR, "ERROR: convert_val(): "
145                                         "cannot convert NULL string value to integer\n");
146                                 return -1;
147                         }
148                         *new_val = (void *)(long)strtol((char *)val, &end, 10);
149                         if (*end != '\0') {
150                                 LOG(L_ERR, "ERROR: convert_val(): "
151                                         "cannot convert string to integer '%s'\n",
152                                         (char *)val);
153                                 return -1;
154                         }
155                         break;
156
157                 } else if (val_type == CFG_VAR_STR) {
158                         if (!((str *)val)->len || !((str *)val)->s) {
159                                 LOG(L_ERR, "ERROR: convert_val(): "
160                                         "cannot convert NULL str value to integer\n");
161                                 return -1;
162                         }
163                         if (str2sint((str *)val, &i)) {
164                                 LOG(L_ERR, "ERROR: convert_val(): "
165                                         "cannot convert string to integer '%.*s'\n",
166                                         ((str *)val)->len, ((str *)val)->s);
167                                 return -1;
168                         }
169                         *new_val = (void *)(long)i;
170                         break;
171                 }
172                 goto error;
173
174         case CFG_INPUT_STRING:
175                 if (val_type == CFG_VAR_INT) {
176                         buf[snprintf(buf, sizeof(buf)-1, "%ld", (long)val)] = '\0';
177                         *new_val = buf;
178                         break;
179
180                 } else if (val_type == CFG_VAR_STRING) {
181                         *new_val = val;
182                         break;
183
184                 } else if (val_type == CFG_VAR_STR) {
185                         if (!((str *)val)->s) {
186                                 *new_val = NULL;
187                                 break;
188                         }
189                         /* the value may not be zero-terminated, thus,
190                         a new variable has to be allocated with larger memory space */
191                         if (temp_string) pkg_free(temp_string);
192                         temp_string = (char *)pkg_malloc(sizeof(char) * (((str *)val)->len + 1));
193                         if (!temp_string) {
194                                 LOG(L_ERR, "ERROR: convert_val(): not enough memory\n");
195                                 return -1;
196                         }
197                         memcpy(temp_string, ((str *)val)->s, ((str *)val)->len);
198                         temp_string[((str *)val)->len] = '\0';
199                         *new_val = (void *)temp_string;
200                         break;
201
202                 }
203                 goto error;
204
205         case CFG_INPUT_STR:
206                 if (val_type == CFG_VAR_INT) {
207                         s.len = snprintf(buf, sizeof(buf)-1, "%ld", (long)val);
208                         buf[s.len] = '\0';
209                         s.s = buf;
210                         *new_val = (void *)&s;
211                         break;
212
213                 } else if (val_type == CFG_VAR_STRING) {
214                         s.s = (char *)val;
215                         s.len = (s.s) ? strlen(s.s) : 0;
216                         *new_val = (void *)&s;
217                         break;
218
219                 } else if (val_type == CFG_VAR_STR) {
220                         *new_val = val;
221                         break;                  
222                 }
223                 goto error;
224         }
225
226         return 0;
227
228 error:
229         LOG(L_ERR, "ERROR: convert_val(): got a value with type %u, but expected %u\n",
230                         val_type, CFG_INPUT_MASK(var_type));
231         return -1;
232 }
233
234 #define convert_val_cleanup() \
235         do { \
236                 if (temp_string) { \
237                         pkg_free(temp_string); \
238                         temp_string = NULL; \
239                 } \
240         } while(0)
241
242 /* sets the value of a variable without the need of commit
243  *
244  * return value:
245  *   0: success
246  *  -1: error
247  *   1: variable has not been found
248  */
249 int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
250                         void *val, unsigned int val_type)
251 {
252         cfg_group_t     *group;
253         cfg_mapping_t   *var;
254         void            *p, *v;
255         cfg_block_t     *block = NULL;
256         str             s, s2;
257         char            *old_string = NULL;
258         char            **replaced = NULL;
259         cfg_child_cb_t  *child_cb = NULL;
260
261         /* verify the context even if we do not need it now
262         to make sure that a cfg driver has called the function
263         (very very weak security) */
264         if (!ctx) {
265                 LOG(L_ERR, "ERROR: cfg_set_now(): context is undefined\n");
266                 return -1;
267         }
268
269         /* look-up the group and the variable */
270         if (cfg_lookup_var(group_name, var_name, &group, &var))
271                 return 1;
272                 
273         /* check whether the variable is read-only */
274         if (var->def->type & CFG_READONLY) {
275                 LOG(L_ERR, "ERROR: cfg_set_now(): variable is read-only\n");
276                 goto error0;
277         }
278
279         /* check whether we have to convert the type */
280         if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
281                 goto error0;
282         
283         if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
284         && (var->def->min || var->def->max)) {
285                 /* perform a simple min-max check for integers */
286                 if (((int)(long)v < var->def->min)
287                 || ((int)(long)v > var->def->max)) {
288                         LOG(L_ERR, "ERROR: cfg_set_now(): integer value is out of range\n");
289                         goto error0;
290                 }
291         }
292
293         if (var->def->on_change_cb) {
294                 /* Call the fixup function.
295                 There is no need to set a temporary cfg handle,
296                 becaue a single variable is changed */
297                 if (var->def->on_change_cb(*(group->handle),
298                                                 group_name,
299                                                 var_name,
300                                                 &v) < 0) {
301                         LOG(L_ERR, "ERROR: cfg_set_now(): fixup failed\n");
302                         goto error0;
303                 }
304
305         }
306
307         if (var->def->on_set_child_cb) {
308                 /* get the name of the variable from the internal struct,
309                 because var_name may be freed before the callback needs it */
310                 s.s = group->name;
311                 s.len = group->name_len;
312                 s2.s = var->def->name;
313                 s2.len = var->name_len;
314                 child_cb = cfg_child_cb_new(&s, &s2,
315                                         var->def->on_set_child_cb,
316                                         var->def->type);
317                 if (!child_cb) {
318                         LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
319                         goto error0;
320                 }
321         }
322
323         if (cfg_shmized) {
324                 /* make sure that nobody else replaces the global config
325                 while the new one is prepared */
326                 CFG_WRITER_LOCK();
327
328                 if (var->def->type & CFG_ATOMIC) {
329                         /* atomic change is allowed, we can rewrite the value
330                         directly in the global config */
331                         p = (*cfg_global)->vars+group->offset+var->offset;
332
333                 } else {
334                         /* clone the memory block, and prepare the modification */
335                         if (!(block = cfg_clone_global())) goto error;
336
337                         p = block->vars+group->offset+var->offset;
338                 }
339         } else {
340                 /* we are allowed to rewrite the value on-the-fly
341                 The handle either points to group->vars, or to the
342                 shared memory block (dynamic group) */
343                 p = *(group->handle) + var->offset;
344         }
345
346         /* set the new value */
347         switch (CFG_VAR_TYPE(var)) {
348         case CFG_VAR_INT:
349                 *(int *)p = (int)(long)v;
350                 break;
351
352         case CFG_VAR_STRING:
353                 /* clone the string to shm mem */
354                 s.s = v;
355                 s.len = (s.s) ? strlen(s.s) : 0;
356                 if (cfg_clone_str(&s, &s)) goto error;
357                 old_string = *(char **)p;
358                 *(char **)p = s.s;
359                 break;
360
361         case CFG_VAR_STR:
362                 /* clone the string to shm mem */
363                 s = *(str *)v;
364                 if (cfg_clone_str(&s, &s)) goto error;
365                 old_string = *(char **)p;
366                 memcpy(p, &s, sizeof(str));
367                 break;
368
369         case CFG_VAR_POINTER:
370                 *(void **)p = v;
371                 break;
372
373         }
374
375         if (cfg_shmized) {
376                 if (old_string) {
377                         /* prepare the array of the replaced strings,
378                         they will be freed when the old block is freed */
379                         replaced = (char **)shm_malloc(sizeof(char *)*2);
380                         if (!replaced) {
381                                 LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
382                                 goto error;
383                         }
384                         replaced[0] = old_string;
385                         replaced[1] = NULL;
386                 }
387                 /* replace the global config with the new one */
388                 if (block) cfg_install_global(block, replaced, child_cb, child_cb);
389                 CFG_WRITER_UNLOCK();
390         } else {
391                 /* cfg_set() may be called more than once before forking */
392                 if (old_string && (var->flag & cfg_var_shmized))
393                         shm_free(old_string);
394
395                 /* flag the variable because there is no need
396                 to shmize it again */
397                 var->flag |= cfg_var_shmized;
398
399                 /* the global config does not have to be replaced,
400                 but the child callback has to be installed, otherwise the
401                 child processes will miss the change */
402                 if (child_cb)
403                         cfg_install_child_cb(child_cb, child_cb);
404         }
405
406         if (val_type == CFG_VAR_INT)
407                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
408                         "has been changed to %d\n",
409                         group_name->len, group_name->s,
410                         var_name->len, var_name->s,
411                         (int)(long)val);
412
413         else if (val_type == CFG_VAR_STRING)
414                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
415                         "has been changed to \"%s\"\n",
416                         group_name->len, group_name->s,
417                         var_name->len, var_name->s,
418                         (char *)val);
419
420         else /* str type */
421                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
422                         "has been changed to \"%.*s\"\n",
423                         group_name->len, group_name->s,
424                         var_name->len, var_name->s,
425                         ((str *)val)->len, ((str *)val)->s);
426
427         convert_val_cleanup();
428         return 0;
429
430 error:
431         if (cfg_shmized) CFG_WRITER_UNLOCK();
432         if (block) cfg_block_free(block);
433         if (child_cb) cfg_child_cb_free(child_cb);
434
435 error0:
436         LOG(L_ERR, "ERROR: cfg_set_now(): failed to set the variable: %.*s.%.*s\n",
437                         group_name->len, group_name->s,
438                         var_name->len, var_name->s);
439
440
441         convert_val_cleanup();
442         return -1;
443 }
444
445 /* wrapper function for cfg_set_now */
446 int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
447 {
448         return cfg_set_now(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
449 }
450
451 /* wrapper function for cfg_set_now */
452 int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
453 {
454         return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
455 }
456
457 /* wrapper function for cfg_set_now */
458 int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
459 {
460         return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
461 }
462
463 /* returns the size of the variable */
464 static int cfg_var_size(cfg_mapping_t *var)
465 {
466         switch (CFG_VAR_TYPE(var)) {
467
468         case CFG_VAR_INT:
469                 return sizeof(int);
470
471         case CFG_VAR_STRING:
472                 return sizeof(char *);
473
474         case CFG_VAR_STR:
475                 return sizeof(str);
476
477         case CFG_VAR_POINTER:
478                 return sizeof(void *);
479
480         default:
481                 LOG(L_CRIT, "BUG: cfg_var_size(): unknown type: %u\n",
482                         CFG_VAR_TYPE(var));
483                 return 0;
484         }
485 }
486
487 /* sets the value of a variable but does not commit the change
488  *
489  * return value:
490  *   0: success
491  *  -1: error
492  *   1: variable has not been found
493  */
494 int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
495                         void *val, unsigned int val_type)
496 {
497         cfg_group_t     *group;
498         cfg_mapping_t   *var;
499         void            *v;
500         char            *temp_handle;
501         int             temp_handle_created;
502         cfg_changed_var_t       *changed = NULL;
503         int             size;
504         str             s;
505
506         if (!cfg_shmized)
507                 /* the cfg has not been shmized yet, there is no
508                 point in registering the change and committing it later */
509                 return cfg_set_now(ctx, group_name, var_name,
510                                         val, val_type);
511
512         if (!ctx) {
513                 LOG(L_ERR, "ERROR: cfg_set_delayed(): context is undefined\n");
514                 return -1;
515         }
516
517         /* look-up the group and the variable */
518         if (cfg_lookup_var(group_name, var_name, &group, &var))
519                 return 1;
520
521         /* check whether the variable is read-only */
522         if (var->def->type & CFG_READONLY) {
523                 LOG(L_ERR, "ERROR: cfg_set_delayed(): variable is read-only\n");
524                 goto error0;
525         }
526
527         /* check whether we have to convert the type */
528         if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
529                 goto error0;
530
531         if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
532         && (var->def->min || var->def->max)) {
533                 /* perform a simple min-max check for integers */
534                 if (((int)(long)v < var->def->min)
535                 || ((int)(long)v > var->def->max)) {
536                         LOG(L_ERR, "ERROR: cfg_set_delayed(): integer value is out of range\n");
537                         goto error0;
538                 }
539         }
540
541         /* the ctx must be locked while reading and writing
542         the list of changed variables */
543         CFG_CTX_LOCK(ctx);
544
545         if (var->def->on_change_cb) {
546                 /* The fixup function must see also the
547                 not yet committed values, so a temporary handle
548                 must be prepared that points to the new config.
549                 Only the values within the group are applied,
550                 other modifications are not visible to the callback.
551                 The local config is the base. */
552
553                 if (ctx->changed_first) {
554                         temp_handle = (char *)pkg_malloc(group->size);
555                         if (!temp_handle) {
556                                 LOG(L_ERR, "ERROR: cfg_set_delayed(): "
557                                         "not enough memory\n");
558                                 goto error;
559                         }
560                         temp_handle_created = 1;
561                         memcpy(temp_handle, *(group->handle), group->size);
562
563                         /* apply the changes */
564                         for (   changed = ctx->changed_first;
565                                 changed;
566                                 changed = changed->next
567                         ) {
568                                 if (changed->group != group) continue;
569
570                                 memcpy( temp_handle + changed->var->offset,
571                                         changed->new_val.vraw,
572                                         cfg_var_size(changed->var));
573                         }
574                 } else {
575                         /* there is not any change */
576                         temp_handle = *(group->handle);
577                         temp_handle_created = 0;
578                 }
579                         
580                 if (var->def->on_change_cb(temp_handle,
581                                                 group_name,
582                                                 var_name,
583                                                 &v) < 0) {
584                         LOG(L_ERR, "ERROR: cfg_set_delayed(): fixup failed\n");
585                         if (temp_handle_created) pkg_free(temp_handle);
586                         goto error;
587                 }
588                 if (temp_handle_created) pkg_free(temp_handle);
589
590         }
591
592         /* everything went ok, we can add the new value to the list */
593         size = sizeof(cfg_changed_var_t) -
594                         sizeof(((cfg_changed_var_t*)0)->new_val) + cfg_var_size(var);
595         changed = (cfg_changed_var_t *)shm_malloc(size);
596         if (!changed) {
597                 LOG(L_ERR, "ERROR: cfg_set_delayed(): not enough shm memory\n");
598                 goto error;
599         }
600         memset(changed, 0, size);
601         changed->group = group;
602         changed->var = var;
603
604         switch (CFG_VAR_TYPE(var)) {
605
606         case CFG_VAR_INT:
607                 changed->new_val.vint = (int)(long)v;
608                 break;
609
610         case CFG_VAR_STRING:
611                 /* clone the string to shm mem */
612                 s.s = v;
613                 s.len = (s.s) ? strlen(s.s) : 0;
614                 if (cfg_clone_str(&s, &s)) goto error;
615                 changed->new_val.vp = s.s;
616                 break;
617
618         case CFG_VAR_STR:
619                 /* clone the string to shm mem */
620                 s = *(str *)v;
621                 if (cfg_clone_str(&s, &s)) goto error;
622                 changed->new_val.vstr=s;
623                 break;
624
625         case CFG_VAR_POINTER:
626                 changed->new_val.vp=v;
627                 break;
628
629         }
630
631         /* Add the new item to the end of the linked list,
632         The commit will go though the list from the first item,
633         so the list is kept in order */
634         if (ctx->changed_first)
635                 ctx->changed_last->next = changed;
636         else
637                 ctx->changed_first = changed;
638
639         ctx->changed_last = changed;
640
641         CFG_CTX_UNLOCK(ctx);
642
643         if (val_type == CFG_VAR_INT)
644                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
645                         "is going to be changed to %d "
646                         "[context=%p]\n",
647                         group_name->len, group_name->s,
648                         var_name->len, var_name->s,
649                         (int)(long)val,
650                         ctx);
651
652         else if (val_type == CFG_VAR_STRING)
653                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
654                         "is going to be changed to \"%s\" "
655                         "[context=%p]\n",
656                         group_name->len, group_name->s,
657                         var_name->len, var_name->s,
658                         (char *)val,
659                         ctx);
660
661         else /* str type */
662                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
663                         "is going to be changed to \"%.*s\" "
664                         "[context=%p]\n",
665                         group_name->len, group_name->s,
666                         var_name->len, var_name->s,
667                         ((str *)val)->len, ((str *)val)->s,
668                         ctx);
669
670         convert_val_cleanup();
671         return 0;
672
673 error:
674         CFG_CTX_UNLOCK(ctx);
675         if (changed) shm_free(changed);
676 error0:
677         LOG(L_ERR, "ERROR: cfg_set_delayed(): failed to set the variable: %.*s.%.*s\n",
678                         group_name->len, group_name->s,
679                         var_name->len, var_name->s);
680
681         convert_val_cleanup();
682         return -1;
683 }
684
685 /* wrapper function for cfg_set_delayed */
686 int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
687 {
688         return cfg_set_delayed(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
689 }
690
691 /* wrapper function for cfg_set_delayed */
692 int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
693 {
694         return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
695 }
696
697 /* wrapper function for cfg_set_delayed */
698 int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
699 {
700         return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
701 }
702
703 /* commits the previously prepared changes within the context */
704 int cfg_commit(cfg_ctx_t *ctx)
705 {
706         int     replaced_num = 0;
707         cfg_changed_var_t       *changed, *changed2;
708         cfg_block_t     *block;
709         char    **replaced = NULL;
710         cfg_child_cb_t  *child_cb;
711         cfg_child_cb_t  *child_cb_first = NULL;
712         cfg_child_cb_t  *child_cb_last = NULL;
713         int     size;
714         void    *p;
715         str     s, s2;
716
717         if (!ctx) {
718                 LOG(L_ERR, "ERROR: cfg_commit(): context is undefined\n");
719                 return -1;
720         }
721
722         if (!cfg_shmized) return 0; /* nothing to do */
723
724         /* the ctx must be locked while reading and writing
725         the list of changed variables */
726         CFG_CTX_LOCK(ctx);
727
728         /* is there any change? */
729         if (!ctx->changed_first) goto done;
730
731         /* count the number of replaced strings,
732         and prepare the linked list of per-child process
733         callbacks, that will be added to the global list */
734         for (   changed = ctx->changed_first;
735                 changed;
736                 changed = changed->next
737         ) {
738                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
739                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
740                         replaced_num++;
741
742
743                 if (changed->var->def->on_set_child_cb) {
744                         s.s = changed->group->name;
745                         s.len = changed->group->name_len;
746                         s2.s = changed->var->def->name;
747                         s2.len = changed->var->name_len;
748                         child_cb = cfg_child_cb_new(&s, &s2,
749                                         changed->var->def->on_set_child_cb,
750                                         changed->var->def->type);
751                         if (!child_cb) goto error0;
752
753                         if (child_cb_last)
754                                 child_cb_last->next = child_cb;
755                         else
756                                 child_cb_first = child_cb;
757                         child_cb_last = child_cb;
758                 }
759         }
760
761         if (replaced_num) {
762                 /* allocate memory for the replaced string array */
763                 size = sizeof(char *)*(replaced_num + 1);
764                 replaced = (char **)shm_malloc(size);
765                 if (!replaced) {
766                         LOG(L_ERR, "ERROR: cfg_commit(): not enough shm memory\n");
767                         goto error;
768                 }
769                 memset(replaced, 0 , size);
770         }
771
772         /* make sure that nobody else replaces the global config
773         while the new one is prepared */
774         CFG_WRITER_LOCK();
775
776         /* clone the memory block, and prepare the modification */
777         if (!(block = cfg_clone_global())) {
778                 CFG_WRITER_UNLOCK();
779                 goto error;
780         }
781
782         /* apply the modifications to the buffer */
783         replaced_num = 0;
784         for (   changed = ctx->changed_first;
785                 changed;
786                 changed = changed->next
787         ) {
788                 p = block->vars
789                         + changed->group->offset
790                         + changed->var->offset;
791
792                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
793                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
794                         replaced[replaced_num] = *(char **)p;
795                         if (replaced[replaced_num])
796                                 replaced_num++;
797                         /* else do not increase replaced_num, because
798                         the cfg_block_free() will stop at the first
799                         NULL value */
800                 }
801
802                 memcpy( p,
803                         changed->new_val.vraw,
804                         cfg_var_size(changed->var));
805         }
806
807         /* replace the global config with the new one */
808         cfg_install_global(block, replaced, child_cb_first, child_cb_last);
809         CFG_WRITER_UNLOCK();
810
811         /* free the changed list */     
812         for (   changed = ctx->changed_first;
813                 changed;
814                 changed = changed2
815         ) {
816                 changed2 = changed->next;
817                 shm_free(changed);
818         }
819         ctx->changed_first = NULL;
820         ctx->changed_last = NULL;
821
822 done:
823         LOG(L_INFO, "INFO: cfg_commit(): config changes have been applied "
824                         "[context=%p]\n",
825                         ctx);
826
827         CFG_CTX_UNLOCK(ctx);
828         return 0;
829
830 error:
831         CFG_CTX_UNLOCK(ctx);
832
833 error0:
834
835         if (child_cb_first) cfg_child_cb_free(child_cb_first);
836         if (replaced) shm_free(replaced);
837
838         return -1;
839 }
840
841 /* drops the not yet committed changes within the context */
842 int cfg_rollback(cfg_ctx_t *ctx)
843 {
844         cfg_changed_var_t       *changed, *changed2;
845
846         if (!ctx) {
847                 LOG(L_ERR, "ERROR: cfg_rollback(): context is undefined\n");
848                 return -1;
849         }
850
851         if (!cfg_shmized) return 0; /* nothing to do */
852
853         LOG(L_INFO, "INFO: cfg_rollback(): deleting the config changes "
854                         "[context=%p]\n",
855                         ctx);
856
857         /* the ctx must be locked while reading and writing
858         the list of changed variables */
859         CFG_CTX_LOCK(ctx);
860
861         for (   changed = ctx->changed_first;
862                 changed;
863                 changed = changed2
864         ) {
865                 changed2 = changed->next;
866
867                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
868                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
869                         if (changed->new_val.vp)
870                                 shm_free(changed->new_val.vp);
871                 }
872                 shm_free(changed);
873         }
874         ctx->changed_first = NULL;
875         ctx->changed_last = NULL;
876
877         CFG_CTX_UNLOCK(ctx);
878
879         return 0;
880 }
881
882 /* retrieves the value of a variable
883  * Return value:
884  *  0 - success
885  * -1 - error
886  *  1 - variable exists, but it is not readable
887  */
888 int cfg_get_by_name(cfg_ctx_t *ctx, str *group_name, str *var_name,
889                         void **val, unsigned int *val_type)
890 {
891         cfg_group_t     *group;
892         cfg_mapping_t   *var;
893         void            *p;
894         static str      s;      /* we need the value even
895                                 after the function returns */
896
897         /* verify the context even if we do not need it now
898         to make sure that a cfg driver has called the function
899         (very very weak security) */
900         if (!ctx) {
901                 LOG(L_ERR, "ERROR: cfg_get_by_name(): context is undefined\n");
902                 return -1;
903         }
904
905         /* look-up the group and the variable */
906         if (cfg_lookup_var(group_name, var_name, &group, &var))
907                 return -1;
908
909         if (var->def->on_change_cb) {
910                 /* The variable cannot be retrieved, because the fixup
911                 function may have changed it, and it is better to return
912                 an error than an incorrect value */
913                 return 1;
914         }
915
916         /* use the module's handle to access the variable
917         It means that the variable is read from the local config
918         after forking */
919         p = *(group->handle) + var->offset;
920
921         switch (CFG_VAR_TYPE(var)) {
922         case CFG_VAR_INT:
923                 *val = (void *)(long)*(int *)p;
924                 break;
925
926         case CFG_VAR_STRING:
927                 *val = (void *)*(char **)p;
928                 break;
929
930         case CFG_VAR_STR:
931                 memcpy(&s, p, sizeof(str));
932                 *val = (void *)&s;
933                 break;
934
935         case CFG_VAR_POINTER:
936                 *val = *(void **)p;
937                 break;
938
939         }
940         *val_type = CFG_VAR_TYPE(var);
941
942         return 0;
943 }
944
945 /* returns the description of a variable */
946 int cfg_help(cfg_ctx_t *ctx, str *group_name, str *var_name,
947                         char **ch, unsigned int *input_type)
948 {
949         cfg_mapping_t   *var;
950
951         /* verify the context even if we do not need it now
952         to make sure that a cfg driver has called the function
953         (very very weak security) */
954         if (!ctx) {
955                 LOG(L_ERR, "ERROR: cfg_help(): context is undefined\n");
956                 return -1;
957         }
958
959         /* look-up the group and the variable */
960         if (cfg_lookup_var(group_name, var_name, NULL, &var))
961                 return -1;
962
963         *ch = var->def->descr;
964         if (input_type)
965                 *input_type = CFG_INPUT_TYPE(var);
966         return 0;
967 }
968
969 /* return the group name and the cfg structure definition,
970  * and moves the handle to the next group
971  * Return value:
972  *      0: no more group
973  *      1: group exists
974  */
975 int cfg_get_group_next(void **h,
976                         str *gname, cfg_def_t **def)
977 {
978         cfg_group_t     *group;
979
980         group = (cfg_group_t *)(*h);
981         if (group == NULL) return 0;
982
983         gname->s = group->name;
984         gname->len = group->name_len;
985         (*def) = group->mapping->def;
986
987         (*h) = (void *)group->next;
988         return 1;
989 }
990
991 /* Initialize the handle for cfg_diff_next() */
992 int cfg_diff_init(cfg_ctx_t *ctx,
993                 void **h)
994 {
995         if (!ctx) {
996                 LOG(L_ERR, "ERROR: cfg_diff_init(): context is undefined\n");
997                 return -1;
998         }
999
1000         CFG_CTX_LOCK(ctx);
1001         (*h) = (void *)ctx->changed_first;
1002
1003         return 0;
1004 }
1005
1006 /* return the pending changes that have not been
1007  * committed yet
1008  */
1009 int cfg_diff_next(void **h,
1010                         str *gname, str *vname,
1011                         void **old_val, void **new_val,
1012                         unsigned int *val_type)
1013 {
1014         cfg_changed_var_t       *changed;
1015         union cfg_var_value* pval;
1016         static str      old_s, new_s;   /* we need the value even
1017                                         after the function returns */
1018
1019         changed = (cfg_changed_var_t *)(*h);
1020         if (changed == NULL) return 0;
1021
1022         gname->s = changed->group->name;
1023         gname->len = changed->group->name_len;
1024         vname->s = changed->var->def->name;
1025         vname->len = changed->var->name_len;
1026
1027         /* use the module's handle to access the variable
1028         It means that the variable is read from the local config
1029         after forking */
1030         pval = (union cfg_var_value*)
1031                         (*(changed->group->handle) + changed->var->offset);
1032
1033         switch (CFG_VAR_TYPE(changed->var)) {
1034         case CFG_VAR_INT:
1035                 *old_val = (void *)(long)pval->vint;
1036                 *new_val = (void *)(long)changed->new_val.vint;
1037                 break;
1038
1039         case CFG_VAR_STRING:
1040                 *old_val = pval->vp;
1041                 *new_val = changed->new_val.vp;
1042                 break;
1043
1044         case CFG_VAR_STR:
1045                 old_s=pval->vstr;
1046                 *old_val = (void *)&old_s;
1047                 new_s=changed->new_val.vstr;
1048                 *new_val = (void *)&new_s;
1049                 break;
1050
1051         case CFG_VAR_POINTER:
1052                 *old_val = pval->vp;
1053                 *new_val = changed->new_val.vp;
1054                 break;
1055
1056         }
1057         *val_type = CFG_VAR_TYPE(changed->var);
1058
1059         (*h) = (void *)changed->next;
1060         return 1;
1061 }
1062
1063 /* release the handle of cfg_diff_next() */
1064 void cfg_diff_release(cfg_ctx_t *ctx)
1065 {
1066         if (!ctx) {
1067                 LOG(L_ERR, "ERROR: cfg_diff_release(): context is undefined\n");
1068                 return;
1069         }
1070
1071         CFG_CTX_UNLOCK(ctx);
1072 }