changing the syntax of cfg_register_ctx() function
[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 /*
129  * Convert an str into signed integer
130  * this function should be moved to ../ut.h
131  */
132 static int str2sint(str* _s, int* _r)
133 {
134         int i;
135         int sign;
136
137         if (_s->len == 0) return -1;
138
139         *_r = 0;
140         sign = 1;
141         i = 0;
142         if (_s->s[0] == '+') {
143                 i++;
144         } else if (_s->s[0] == '-') {
145                 sign = -1;
146                 i++;
147         }
148         for(; i < _s->len; i++) {
149                 if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
150                         *_r *= 10;
151                         *_r += _s->s[i] - '0';
152                 } else {
153                         return -1;
154                 }
155         }
156         *_r *= sign;
157
158         return 0;
159 }
160
161
162 /* placeholder for a temporary string */
163 static char     *temp_string = NULL;
164
165 /* convert the value to the requested type */
166 static int convert_val(unsigned int val_type, void *val,
167                         unsigned int var_type, void **new_val)
168 {
169         static str      s;
170         char            *end;
171         int             i;
172         static char     buf[INT2STR_MAX_LEN];
173
174         /* we have to convert from val_type to var_type */
175         switch (CFG_INPUT_MASK(var_type)) {
176         case CFG_INPUT_INT:
177                 if (val_type == CFG_VAR_INT) {
178                         *new_val = val;
179                         break;
180
181                 } else if (val_type == CFG_VAR_STRING) {
182                         *new_val = (void *)(long)strtol((char *)val, &end, 10);
183                         if (*end != '\0') {
184                                 LOG(L_ERR, "ERROR: convert_val(): "
185                                         "cannot convert string to integer '%s'\n",
186                                         s.s);
187                                 return -1;
188                         }
189                         break;
190
191                 } else if (val_type == CFG_VAR_STR) {
192                         if (str2sint((str *)val, &i)) {
193                                 LOG(L_ERR, "ERROR: convert_val(): "
194                                         "cannot convert string to integer '%.*s'\n",
195                                         ((str *)val)->len, ((str *)val)->s);
196                                 return -1;
197                         }
198                         *new_val = (void *)(long)i;
199                         break;
200                 }
201                 goto error;
202
203         case CFG_INPUT_STRING:
204                 if (val_type == CFG_VAR_INT) {
205                         buf[snprintf(buf, sizeof(buf)-1, "%ld", (long)val)] = '\0';
206                         *new_val = buf;
207                         break;
208
209                 } else if (val_type == CFG_VAR_STRING) {
210                         *new_val = val;
211                         break;
212
213                 } else if (val_type == CFG_VAR_STR) {
214                         /* the value may not be zero-terminated, thus,
215                         a new variable has to be allocated with larger memory space */
216                         if (temp_string) pkg_free(temp_string);
217                         temp_string = (char *)pkg_malloc(sizeof(char) * (((str *)val)->len + 1));
218                         if (!temp_string) {
219                                 LOG(L_ERR, "ERROR: convert_val(): not enough memory\n");
220                                 return -1;
221                         }
222                         memcpy(temp_string, ((str *)val)->s, ((str *)val)->len);
223                         temp_string[((str *)val)->len] = '\0';
224                         *new_val = (void *)temp_string;
225                         break;
226
227                 }
228                 goto error;
229
230         case CFG_INPUT_STR:
231                 if (val_type == CFG_VAR_INT) {
232                         s.len = snprintf(buf, sizeof(buf)-1, "%ld", (long)val);
233                         buf[s.len] = '\0';
234                         s.s = buf;
235                         *new_val = (void *)&s;
236                         break;
237
238                 } else if (val_type == CFG_VAR_STRING) {
239                         s.s = (char *)val;
240                         s.len = strlen(s.s);
241                         *new_val = (void *)&s;
242                         break;
243
244                 } else if (val_type == CFG_VAR_STR) {
245                         *new_val = val;
246                         break;                  
247                 }
248                 goto error;
249         }
250
251         return 0;
252
253 error:
254         LOG(L_ERR, "ERROR: convert_val(): got a value with type %u, but expected %u\n",
255                         val_type, CFG_INPUT_MASK(var_type));
256         return -1;
257 }
258
259 #define convert_val_cleanup() \
260         do { \
261                 if (temp_string) { \
262                         pkg_free(temp_string); \
263                         temp_string = NULL; \
264                 } \
265         } while(0)
266
267 /* sets the value of a variable without the need of commit
268  *
269  * return value:
270  *   0: success
271  *  -1: error
272  *   1: variable has not been found
273  */
274 int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
275                         void *val, unsigned int val_type)
276 {
277         cfg_group_t     *group;
278         cfg_mapping_t   *var;
279         void            *p, *v;
280         cfg_block_t     *block = NULL;
281         str             s;
282         char            *old_string = NULL;
283         char            **replaced = NULL;
284         cfg_child_cb_t  *child_cb = NULL;
285         int             i;
286
287         /* verify the context even if we do not need it now
288         to make sure that a cfg driver has called the function
289         (very very weak security) */
290         if (!ctx) {
291                 LOG(L_ERR, "ERROR: cfg_set_now(): context is undefined\n");
292                 return -1;
293         }
294
295         /* look-up the group and the variable */
296         if (cfg_lookup_var(group_name, var_name, &group, &var))
297                 return 1;
298
299         /* check whether we have to convert the type */
300         if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
301                 goto error0;
302         
303         if (var->def->on_change_cb) {
304                 /* Call the fixup function.
305                 There is no need to set a temporary cfg handle,
306                 becaue a single variable is changed */
307                 if (var->def->on_change_cb(*(group->handle),
308                                                 var_name,
309                                                 &v) < 0) {
310                         LOG(L_ERR, "ERROR: cfg_set_now(): fixup failed\n");
311                         goto error0;
312                 }
313
314         } else if ((CFG_VAR_TYPE(var) == CFG_VAR_INT) 
315         && (var->def->min != var->def->max)) {
316                 /* perform a simple min-max check for integers */
317                 if (((int)(long)v < var->def->min)
318                 || ((int)(long)v > var->def->max)) {
319                         LOG(L_ERR, "ERROR: cfg_set_now(): integer value is out of range\n");
320                         goto error0;
321                 }
322         }
323
324         if (cfg_shmized) {
325                 if (var->def->on_set_child_cb) {
326                         child_cb = cfg_child_cb_new(var_name,
327                                                 var->def->on_set_child_cb);
328                         if (!child_cb) {
329                                 LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
330                                 goto error0;
331                         }
332                 }
333
334                 /* make sure that nobody else replaces the global config
335                 while the new one is prepared */
336                 CFG_WRITER_LOCK();
337
338                 /* clone the memory block, and prepare the modification */
339                 if (!(block = cfg_clone_global())) goto error;
340
341                 p = block->vars+group->offset+var->offset;
342         } else {
343                 /* we are allowed to rewrite the value on-the-fly
344                 The handle either points to group->vars, or to the
345                 shared memory block (dynamic group) */
346                 p = *(group->handle) + var->offset;
347         }
348
349         /* set the new value */
350         switch (CFG_VAR_TYPE(var)) {
351         case CFG_VAR_INT:
352                 i = (int)(long)v;
353                 memcpy(p, &i, sizeof(int));
354                 break;
355
356         case CFG_VAR_STRING:
357                 /* clone the string to shm mem */
358                 s.s = v;
359                 s.len = strlen(v);
360                 if (!(s.s = cfg_clone_str(s))) goto error;
361                 memcpy(&old_string, p, sizeof(char *));
362                 memcpy(p, &s.s, sizeof(char *));
363                 break;
364
365         case CFG_VAR_STR:
366                 /* clone the string to shm mem */
367                 s = *(str *)v;
368                 if (!(s.s = cfg_clone_str(s))) goto error;
369                 memcpy(&old_string, p, sizeof(char *));
370                 memcpy(p, &s, sizeof(str));
371                 break;
372
373         case CFG_VAR_POINTER:
374                 memcpy(p, &v, sizeof(void *));
375                 break;
376
377         }
378
379         if (cfg_shmized) {
380                 if (old_string) {
381                         /* prepare the array of the replaced strings,
382                         they will be freed when the old block is freed */
383                         replaced = (char **)shm_malloc(sizeof(char *)*2);
384                         if (!replaced) {
385                                 LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
386                                 goto error;
387                         }
388                         replaced[0] = old_string;
389                         replaced[1] = NULL;
390                 }
391                 /* replace the global config with the new one */
392                 cfg_install_global(block, replaced, child_cb, child_cb);
393                 CFG_WRITER_UNLOCK();
394         } else {
395                 /* cfg_set() may be called more than once before forking */
396                 if (old_string && (var->flag & cfg_var_shmized))
397                         shm_free(old_string);
398
399                 /* flag the variable because there is no need
400                 to shmize it again */
401                 var->flag |= cfg_var_shmized;
402         }
403
404         if (val_type == CFG_VAR_INT)
405                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
406                         "has been changed to %d\n",
407                         group_name->len, group_name->s,
408                         var_name->len, var_name->s,
409                         (int)(long)val);
410
411         else if (val_type == CFG_VAR_STRING)
412                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
413                         "has been changed to \"%s\"\n",
414                         group_name->len, group_name->s,
415                         var_name->len, var_name->s,
416                         (char *)val);
417
418         else /* str type */
419                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
420                         "has been changed to \"%.*s\"\n",
421                         group_name->len, group_name->s,
422                         var_name->len, var_name->s,
423                         ((str *)val)->len, ((str *)val)->s);
424
425         convert_val_cleanup();
426         return 0;
427
428 error:
429         if (cfg_shmized) CFG_WRITER_UNLOCK();
430         if (block) cfg_block_free(block);
431         if (child_cb) cfg_child_cb_free(child_cb);
432
433 error0:
434         LOG(L_ERR, "ERROR: cfg_set_now(): failed to set the variable: %.*s.%.*s\n",
435                         group_name->len, group_name->s,
436                         var_name->len, var_name->s);
437
438
439         convert_val_cleanup();
440         return -1;
441 }
442
443 /* wrapper function for cfg_set_now */
444 int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
445 {
446         return cfg_set_now(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
447 }
448
449 /* wrapper function for cfg_set_now */
450 int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
451 {
452         return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
453 }
454
455 /* wrapper function for cfg_set_now */
456 int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
457 {
458         return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
459 }
460
461 /* returns the size of the variable */
462 static int cfg_var_size(cfg_mapping_t *var)
463 {
464         switch (CFG_VAR_TYPE(var)) {
465
466         case CFG_VAR_INT:
467                 return sizeof(int);
468
469         case CFG_VAR_STRING:
470                 return sizeof(char *);
471
472         case CFG_VAR_STR:
473                 return sizeof(str);
474
475         case CFG_VAR_POINTER:
476                 return sizeof(void *);
477
478         default:
479                 LOG(L_CRIT, "BUG: cfg_var_sizeK(): unknown type: %u\n",
480                         CFG_VAR_TYPE(var));
481                 return 0;
482         }
483 }
484
485 /* sets the value of a variable but does not commit the change
486  *
487  * return value:
488  *   0: success
489  *  -1: error
490  *   1: variable has not been found
491  */
492 int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
493                         void *val, unsigned int val_type)
494 {
495         cfg_group_t     *group;
496         cfg_mapping_t   *var;
497         void            *v;
498         char            *temp_handle;
499         int             temp_handle_created;
500         cfg_changed_var_t       *changed = NULL;
501         int             i, size;
502         str             s;
503
504         if (!cfg_shmized)
505                 /* the cfg has not been shmized yet, there is no
506                 point in registering the change and committing it later */
507                 return cfg_set_now(ctx, group_name, var_name,
508                                         val, val_type);
509
510         if (!ctx) {
511                 LOG(L_ERR, "ERROR: cfg_set_delayed(): context is undefined\n");
512                 return -1;
513         }
514
515         /* look-up the group and the variable */
516         if (cfg_lookup_var(group_name, var_name, &group, &var))
517                 return 1;
518
519         /* check whether we have to convert the type */
520         if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
521                 goto error0;
522
523         /* the ctx must be locked while reading and writing
524         the list of changed variables */
525         CFG_CTX_LOCK(ctx);
526
527         if (var->def->on_change_cb) {
528                 /* The fixup function must see also the
529                 not yet committed values, so a temporary handle
530                 must be prepared that points to the new config.
531                 Only the values within the group are applied,
532                 other modifications are not visible to the callback.
533                 The local config is the base. */
534
535                 if (ctx->changed_first) {
536                         temp_handle = (char *)pkg_malloc(group->size);
537                         if (!temp_handle) {
538                                 LOG(L_ERR, "ERROR: cfg_set_delayed(): "
539                                         "not enough memory\n");
540                                 goto error;
541                         }
542                         temp_handle_created = 1;
543                         memcpy(temp_handle, *(group->handle), group->size);
544
545                         /* apply the changes */
546                         for (   changed = ctx->changed_first;
547                                 changed;
548                                 changed = changed->next
549                         ) {
550                                 if (changed->group != group) continue;
551
552                                 memcpy( temp_handle + changed->var->offset,
553                                         changed->new_val,
554                                         cfg_var_size(changed->var));
555                         }
556                 } else {
557                         /* there is not any change */
558                         temp_handle = *(group->handle);
559                         temp_handle_created = 0;
560                 }
561                         
562                 if (var->def->on_change_cb(temp_handle,
563                                                 var_name,
564                                                 &v) < 0) {
565                         LOG(L_ERR, "ERROR: cfg_set_delayed(): fixup failed\n");
566                         if (temp_handle_created) pkg_free(temp_handle);
567                         goto error;
568                 }
569                 if (temp_handle_created) pkg_free(temp_handle);
570
571         } else if ((CFG_VAR_TYPE(var) == CFG_VAR_INT) 
572         && (var->def->min != var->def->max)) {
573                 /* perform a simple min-max check for integers */
574                 if (((int)(long)v < var->def->min)
575                 || ((int)(long)v > var->def->max)) {
576                         LOG(L_ERR, "ERROR: cfg_set_delayed(): integer value is out of range\n");
577                         goto error;
578                 }
579         }
580
581         /* everything went ok, we can add the new value to the list */
582         size = sizeof(cfg_changed_var_t) + cfg_var_size(var) - 1;
583         changed = (cfg_changed_var_t *)shm_malloc(size);
584         if (!changed) {
585                 LOG(L_ERR, "ERROR: cfg_set_delayed(): not enough shm memory\n");
586                 goto error;
587         }
588         memset(changed, 0, size);
589         changed->group = group;
590         changed->var = var;
591
592         switch (CFG_VAR_TYPE(var)) {
593
594         case CFG_VAR_INT:
595                 i = (int)(long)v;
596                 memcpy(changed->new_val, &i, sizeof(int));
597                 break;
598
599         case CFG_VAR_STRING:
600                 /* clone the string to shm mem */
601                 s.s = v;
602                 s.len = strlen(v);
603                 if (!(s.s = cfg_clone_str(s))) goto error;
604                 memcpy(changed->new_val, &s.s, sizeof(char *));
605                 break;
606
607         case CFG_VAR_STR:
608                 /* clone the string to shm mem */
609                 s = *(str *)v;
610                 if (!(s.s = cfg_clone_str(s))) goto error;
611                 memcpy(changed->new_val, &s, sizeof(str));
612                 break;
613
614         case CFG_VAR_POINTER:
615                 memcpy(changed->new_val, &v, sizeof(void *));
616                 break;
617
618         }
619
620         /* Add the new item to the end of the linked list,
621         The commit will go though the list from the first item,
622         so the list is kept in order */
623         if (ctx->changed_first)
624                 ctx->changed_last->next = changed;
625         else
626                 ctx->changed_first = changed;
627
628         ctx->changed_last = changed;
629
630         CFG_CTX_UNLOCK(ctx);
631
632         if (val_type == CFG_VAR_INT)
633                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
634                         "is going to be changed to %d "
635                         "[context=%p]\n",
636                         group_name->len, group_name->s,
637                         var_name->len, var_name->s,
638                         (int)(long)val,
639                         ctx);
640
641         else if (val_type == CFG_VAR_STRING)
642                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
643                         "is going to be changed to \"%s\" "
644                         "[context=%p]\n",
645                         group_name->len, group_name->s,
646                         var_name->len, var_name->s,
647                         (char *)val,
648                         ctx);
649
650         else /* str type */
651                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
652                         "is going to be changed to \"%.*s\" "
653                         "[context=%p]\n",
654                         group_name->len, group_name->s,
655                         var_name->len, var_name->s,
656                         ((str *)val)->len, ((str *)val)->s,
657                         ctx);
658
659         convert_val_cleanup();
660         return 0;
661
662 error:
663         CFG_CTX_UNLOCK(ctx);
664         if (changed) shm_free(changed);
665 error0:
666         LOG(L_ERR, "ERROR: cfg_set_delayed(): failed to set the variable: %.*s.%.*s\n",
667                         group_name->len, group_name->s,
668                         var_name->len, var_name->s);
669
670         convert_val_cleanup();
671         return -1;
672 }
673
674 /* wrapper function for cfg_set_delayed */
675 int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
676 {
677         return cfg_set_delayed(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
678 }
679
680 /* wrapper function for cfg_set_delayed */
681 int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
682 {
683         return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
684 }
685
686 /* wrapper function for cfg_set_delayed */
687 int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
688 {
689         return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
690 }
691
692 /* commits the previously prepared changes within the context */
693 int cfg_commit(cfg_ctx_t *ctx)
694 {
695         int     replaced_num = 0;
696         cfg_changed_var_t       *changed, *changed2;
697         cfg_block_t     *block;
698         char    **replaced = NULL;
699         cfg_child_cb_t  *child_cb;
700         cfg_child_cb_t  *child_cb_first = NULL;
701         cfg_child_cb_t  *child_cb_last = NULL;
702         int     size;
703         void    *p;
704         str     s;
705
706         if (!ctx) {
707                 LOG(L_ERR, "ERROR: cfg_commit(): context is undefined\n");
708                 return -1;
709         }
710
711         if (!cfg_shmized) return 0; /* nothing to do */
712
713         /* the ctx must be locked while reading and writing
714         the list of changed variables */
715         CFG_CTX_LOCK(ctx);
716
717         /* is there any change? */
718         if (!ctx->changed_first) goto done;
719
720         /* count the number of replaced strings,
721         and prepare the linked list of per-child process
722         callbacks, that will be added to the global list */
723         for (   changed = ctx->changed_first;
724                 changed;
725                 changed = changed->next
726         ) {
727                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
728                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
729                         replaced_num++;
730
731
732                 if (changed->var->def->on_set_child_cb) {
733                         s.s = changed->var->def->name;
734                         s.len = changed->var->name_len;
735                         child_cb = cfg_child_cb_new(&s,
736                                         changed->var->def->on_set_child_cb);
737                         if (!child_cb) goto error0;
738
739                         if (child_cb_last)
740                                 child_cb_last->next = child_cb;
741                         else
742                                 child_cb_first = child_cb;
743                         child_cb_last = child_cb;
744                 }
745         }
746
747         /* allocate memory for the replaced string array */
748         size = sizeof(char *)*(replaced_num + 1);
749         replaced = (char **)shm_malloc(size);
750         if (!replaced) {
751                 LOG(L_ERR, "ERROR: cfg_commit(): not enough shm memory\n");
752                 goto error;
753         }
754         memset(replaced, 0 , size);
755
756         /* make sure that nobody else replaces the global config
757         while the new one is prepared */
758         CFG_WRITER_LOCK();
759
760         /* clone the memory block, and prepare the modification */
761         if (!(block = cfg_clone_global())) {
762                 CFG_WRITER_UNLOCK();
763                 goto error;
764         }
765
766         /* apply the modifications to the buffer */
767         replaced_num = 0;
768         for (   changed = ctx->changed_first;
769                 changed;
770                 changed = changed->next
771         ) {
772                 p = block->vars
773                         + changed->group->offset
774                         + changed->var->offset;
775
776                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
777                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
778                         memcpy(&(replaced[replaced_num]), p, sizeof(char *));
779                         replaced_num++;
780                 }
781
782                 memcpy( p,
783                         changed->new_val,
784                         cfg_var_size(changed->var));
785         }
786
787         /* replace the global config with the new one */
788         cfg_install_global(block, replaced, child_cb_first, child_cb_last);
789         CFG_WRITER_UNLOCK();
790
791         /* free the changed list */     
792         for (   changed = ctx->changed_first;
793                 changed;
794                 changed = changed2
795         ) {
796                 changed2 = changed->next;
797                 shm_free(changed);
798         }
799         ctx->changed_first = NULL;
800         ctx->changed_last = NULL;
801
802 done:
803         LOG(L_INFO, "INFO: cfg_commit(): config changes have been applied "
804                         "[context=%p]\n",
805                         ctx);
806
807         CFG_CTX_UNLOCK(ctx);
808         return 0;
809
810 error:
811         CFG_CTX_UNLOCK(ctx);
812
813 error0:
814
815         if (child_cb_first) cfg_child_cb_free(child_cb_first);
816         if (replaced) shm_free(replaced);
817
818         return -1;
819 }
820
821 /* drops the not yet committed changes within the context */
822 int cfg_rollback(cfg_ctx_t *ctx)
823 {
824         cfg_changed_var_t       *changed, *changed2;
825         char    *new_string;
826
827         if (!ctx) {
828                 LOG(L_ERR, "ERROR: cfg_rollback(): context is undefined\n");
829                 return -1;
830         }
831
832         if (!cfg_shmized) return 0; /* nothing to do */
833
834         LOG(L_INFO, "INFO: cfg_rollback(): deleting the config changes "
835                         "[context=%p]\n",
836                         ctx);
837
838         /* the ctx must be locked while reading and writing
839         the list of changed variables */
840         CFG_CTX_LOCK(ctx);
841
842         for (   changed = ctx->changed_first;
843                 changed;
844                 changed = changed2
845         ) {
846                 changed2 = changed->next;
847
848                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
849                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
850                         memcpy(&new_string, changed->new_val, sizeof(char *));
851                         shm_free(new_string);
852                 }
853                 shm_free(changed);
854         }
855         ctx->changed_first = NULL;
856         ctx->changed_last = NULL;
857
858         CFG_CTX_UNLOCK(ctx);
859
860         return 0;
861 }
862
863 /* returns the value of a variable */
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 }