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