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