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