eac562a2569b26936c6675035d0523c059460000
[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 (cfg_shmized) {
307                 if (var->def->on_set_child_cb) {
308                         child_cb = cfg_child_cb_new(var_name,
309                                                 var->def->on_set_child_cb);
310                         if (!child_cb) {
311                                 LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
312                                 goto error0;
313                         }
314                 }
315
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
386         if (val_type == CFG_VAR_INT)
387                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
388                         "has been changed to %d\n",
389                         group_name->len, group_name->s,
390                         var_name->len, var_name->s,
391                         (int)(long)val);
392
393         else if (val_type == CFG_VAR_STRING)
394                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
395                         "has been changed to \"%s\"\n",
396                         group_name->len, group_name->s,
397                         var_name->len, var_name->s,
398                         (char *)val);
399
400         else /* str type */
401                 LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
402                         "has been changed to \"%.*s\"\n",
403                         group_name->len, group_name->s,
404                         var_name->len, var_name->s,
405                         ((str *)val)->len, ((str *)val)->s);
406
407         convert_val_cleanup();
408         return 0;
409
410 error:
411         if (cfg_shmized) CFG_WRITER_UNLOCK();
412         if (block) cfg_block_free(block);
413         if (child_cb) cfg_child_cb_free(child_cb);
414
415 error0:
416         LOG(L_ERR, "ERROR: cfg_set_now(): failed to set the variable: %.*s.%.*s\n",
417                         group_name->len, group_name->s,
418                         var_name->len, var_name->s);
419
420
421         convert_val_cleanup();
422         return -1;
423 }
424
425 /* wrapper function for cfg_set_now */
426 int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
427 {
428         return cfg_set_now(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
429 }
430
431 /* wrapper function for cfg_set_now */
432 int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
433 {
434         return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
435 }
436
437 /* wrapper function for cfg_set_now */
438 int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
439 {
440         return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
441 }
442
443 /* returns the size of the variable */
444 static int cfg_var_size(cfg_mapping_t *var)
445 {
446         switch (CFG_VAR_TYPE(var)) {
447
448         case CFG_VAR_INT:
449                 return sizeof(int);
450
451         case CFG_VAR_STRING:
452                 return sizeof(char *);
453
454         case CFG_VAR_STR:
455                 return sizeof(str);
456
457         case CFG_VAR_POINTER:
458                 return sizeof(void *);
459
460         default:
461                 LOG(L_CRIT, "BUG: cfg_var_sizeK(): unknown type: %u\n",
462                         CFG_VAR_TYPE(var));
463                 return 0;
464         }
465 }
466
467 /* sets the value of a variable but does not commit the change
468  *
469  * return value:
470  *   0: success
471  *  -1: error
472  *   1: variable has not been found
473  */
474 int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
475                         void *val, unsigned int val_type)
476 {
477         cfg_group_t     *group;
478         cfg_mapping_t   *var;
479         void            *v;
480         char            *temp_handle;
481         int             temp_handle_created;
482         cfg_changed_var_t       *changed = NULL;
483         int             i, size;
484         str             s;
485
486         if (!cfg_shmized)
487                 /* the cfg has not been shmized yet, there is no
488                 point in registering the change and committing it later */
489                 return cfg_set_now(ctx, group_name, var_name,
490                                         val, val_type);
491
492         if (!ctx) {
493                 LOG(L_ERR, "ERROR: cfg_set_delayed(): context is undefined\n");
494                 return -1;
495         }
496
497         /* look-up the group and the variable */
498         if (cfg_lookup_var(group_name, var_name, &group, &var))
499                 return 1;
500
501         /* check whether we have to convert the type */
502         if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
503                 goto error0;
504
505         if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT) 
506         && (var->def->min || var->def->max)) {
507                 /* perform a simple min-max check for integers */
508                 if (((int)(long)v < var->def->min)
509                 || ((int)(long)v > var->def->max)) {
510                         LOG(L_ERR, "ERROR: cfg_set_delayed(): integer value is out of range\n");
511                         goto error0;
512                 }
513         }
514
515         /* the ctx must be locked while reading and writing
516         the list of changed variables */
517         CFG_CTX_LOCK(ctx);
518
519         if (var->def->on_change_cb) {
520                 /* The fixup function must see also the
521                 not yet committed values, so a temporary handle
522                 must be prepared that points to the new config.
523                 Only the values within the group are applied,
524                 other modifications are not visible to the callback.
525                 The local config is the base. */
526
527                 if (ctx->changed_first) {
528                         temp_handle = (char *)pkg_malloc(group->size);
529                         if (!temp_handle) {
530                                 LOG(L_ERR, "ERROR: cfg_set_delayed(): "
531                                         "not enough memory\n");
532                                 goto error;
533                         }
534                         temp_handle_created = 1;
535                         memcpy(temp_handle, *(group->handle), group->size);
536
537                         /* apply the changes */
538                         for (   changed = ctx->changed_first;
539                                 changed;
540                                 changed = changed->next
541                         ) {
542                                 if (changed->group != group) continue;
543
544                                 memcpy( temp_handle + changed->var->offset,
545                                         changed->new_val,
546                                         cfg_var_size(changed->var));
547                         }
548                 } else {
549                         /* there is not any change */
550                         temp_handle = *(group->handle);
551                         temp_handle_created = 0;
552                 }
553                         
554                 if (var->def->on_change_cb(temp_handle,
555                                                 var_name,
556                                                 &v) < 0) {
557                         LOG(L_ERR, "ERROR: cfg_set_delayed(): fixup failed\n");
558                         if (temp_handle_created) pkg_free(temp_handle);
559                         goto error;
560                 }
561                 if (temp_handle_created) pkg_free(temp_handle);
562
563         }
564
565         /* everything went ok, we can add the new value to the list */
566         size = sizeof(cfg_changed_var_t) + cfg_var_size(var) - 1;
567         changed = (cfg_changed_var_t *)shm_malloc(size);
568         if (!changed) {
569                 LOG(L_ERR, "ERROR: cfg_set_delayed(): not enough shm memory\n");
570                 goto error;
571         }
572         memset(changed, 0, size);
573         changed->group = group;
574         changed->var = var;
575
576         switch (CFG_VAR_TYPE(var)) {
577
578         case CFG_VAR_INT:
579                 i = (int)(long)v;
580                 memcpy(changed->new_val, &i, sizeof(int));
581                 break;
582
583         case CFG_VAR_STRING:
584                 /* clone the string to shm mem */
585                 s.s = v;
586                 s.len = (s.s) ? strlen(s.s) : 0;
587                 if (cfg_clone_str(&s, &s)) goto error;
588                 memcpy(changed->new_val, &s.s, sizeof(char *));
589                 break;
590
591         case CFG_VAR_STR:
592                 /* clone the string to shm mem */
593                 s = *(str *)v;
594                 if (cfg_clone_str(&s, &s)) goto error;
595                 memcpy(changed->new_val, &s, sizeof(str));
596                 break;
597
598         case CFG_VAR_POINTER:
599                 memcpy(changed->new_val, &v, sizeof(void *));
600                 break;
601
602         }
603
604         /* Add the new item to the end of the linked list,
605         The commit will go though the list from the first item,
606         so the list is kept in order */
607         if (ctx->changed_first)
608                 ctx->changed_last->next = changed;
609         else
610                 ctx->changed_first = changed;
611
612         ctx->changed_last = changed;
613
614         CFG_CTX_UNLOCK(ctx);
615
616         if (val_type == CFG_VAR_INT)
617                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
618                         "is going to be changed to %d "
619                         "[context=%p]\n",
620                         group_name->len, group_name->s,
621                         var_name->len, var_name->s,
622                         (int)(long)val,
623                         ctx);
624
625         else if (val_type == CFG_VAR_STRING)
626                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
627                         "is going to be changed to \"%s\" "
628                         "[context=%p]\n",
629                         group_name->len, group_name->s,
630                         var_name->len, var_name->s,
631                         (char *)val,
632                         ctx);
633
634         else /* str type */
635                 LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
636                         "is going to be changed to \"%.*s\" "
637                         "[context=%p]\n",
638                         group_name->len, group_name->s,
639                         var_name->len, var_name->s,
640                         ((str *)val)->len, ((str *)val)->s,
641                         ctx);
642
643         convert_val_cleanup();
644         return 0;
645
646 error:
647         CFG_CTX_UNLOCK(ctx);
648         if (changed) shm_free(changed);
649 error0:
650         LOG(L_ERR, "ERROR: cfg_set_delayed(): failed to set the variable: %.*s.%.*s\n",
651                         group_name->len, group_name->s,
652                         var_name->len, var_name->s);
653
654         convert_val_cleanup();
655         return -1;
656 }
657
658 /* wrapper function for cfg_set_delayed */
659 int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
660 {
661         return cfg_set_delayed(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
662 }
663
664 /* wrapper function for cfg_set_delayed */
665 int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
666 {
667         return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
668 }
669
670 /* wrapper function for cfg_set_delayed */
671 int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
672 {
673         return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
674 }
675
676 /* commits the previously prepared changes within the context */
677 int cfg_commit(cfg_ctx_t *ctx)
678 {
679         int     replaced_num = 0;
680         cfg_changed_var_t       *changed, *changed2;
681         cfg_block_t     *block;
682         char    **replaced = NULL;
683         cfg_child_cb_t  *child_cb;
684         cfg_child_cb_t  *child_cb_first = NULL;
685         cfg_child_cb_t  *child_cb_last = NULL;
686         int     size;
687         void    *p;
688         str     s;
689
690         if (!ctx) {
691                 LOG(L_ERR, "ERROR: cfg_commit(): context is undefined\n");
692                 return -1;
693         }
694
695         if (!cfg_shmized) return 0; /* nothing to do */
696
697         /* the ctx must be locked while reading and writing
698         the list of changed variables */
699         CFG_CTX_LOCK(ctx);
700
701         /* is there any change? */
702         if (!ctx->changed_first) goto done;
703
704         /* count the number of replaced strings,
705         and prepare the linked list of per-child process
706         callbacks, that will be added to the global list */
707         for (   changed = ctx->changed_first;
708                 changed;
709                 changed = changed->next
710         ) {
711                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
712                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
713                         replaced_num++;
714
715
716                 if (changed->var->def->on_set_child_cb) {
717                         s.s = changed->var->def->name;
718                         s.len = changed->var->name_len;
719                         child_cb = cfg_child_cb_new(&s,
720                                         changed->var->def->on_set_child_cb);
721                         if (!child_cb) goto error0;
722
723                         if (child_cb_last)
724                                 child_cb_last->next = child_cb;
725                         else
726                                 child_cb_first = child_cb;
727                         child_cb_last = child_cb;
728                 }
729         }
730
731         if (replaced_num) {
732                 /* allocate memory for the replaced string array */
733                 size = sizeof(char *)*(replaced_num + 1);
734                 replaced = (char **)shm_malloc(size);
735                 if (!replaced) {
736                         LOG(L_ERR, "ERROR: cfg_commit(): not enough shm memory\n");
737                         goto error;
738                 }
739                 memset(replaced, 0 , size);
740         }
741
742         /* make sure that nobody else replaces the global config
743         while the new one is prepared */
744         CFG_WRITER_LOCK();
745
746         /* clone the memory block, and prepare the modification */
747         if (!(block = cfg_clone_global())) {
748                 CFG_WRITER_UNLOCK();
749                 goto error;
750         }
751
752         /* apply the modifications to the buffer */
753         replaced_num = 0;
754         for (   changed = ctx->changed_first;
755                 changed;
756                 changed = changed->next
757         ) {
758                 p = block->vars
759                         + changed->group->offset
760                         + changed->var->offset;
761
762                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
763                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
764                         memcpy(&(replaced[replaced_num]), p, sizeof(char *));
765                         if (replaced[replaced_num])
766                                 replaced_num++;
767                         /* else do not increase replaced_num, because
768                         the cfg_block_free() will stop at the first
769                         NULL value */
770                 }
771
772                 memcpy( p,
773                         changed->new_val,
774                         cfg_var_size(changed->var));
775         }
776
777         /* replace the global config with the new one */
778         cfg_install_global(block, replaced, child_cb_first, child_cb_last);
779         CFG_WRITER_UNLOCK();
780
781         /* free the changed list */     
782         for (   changed = ctx->changed_first;
783                 changed;
784                 changed = changed2
785         ) {
786                 changed2 = changed->next;
787                 shm_free(changed);
788         }
789         ctx->changed_first = NULL;
790         ctx->changed_last = NULL;
791
792 done:
793         LOG(L_INFO, "INFO: cfg_commit(): config changes have been applied "
794                         "[context=%p]\n",
795                         ctx);
796
797         CFG_CTX_UNLOCK(ctx);
798         return 0;
799
800 error:
801         CFG_CTX_UNLOCK(ctx);
802
803 error0:
804
805         if (child_cb_first) cfg_child_cb_free(child_cb_first);
806         if (replaced) shm_free(replaced);
807
808         return -1;
809 }
810
811 /* drops the not yet committed changes within the context */
812 int cfg_rollback(cfg_ctx_t *ctx)
813 {
814         cfg_changed_var_t       *changed, *changed2;
815         char    *new_string;
816
817         if (!ctx) {
818                 LOG(L_ERR, "ERROR: cfg_rollback(): context is undefined\n");
819                 return -1;
820         }
821
822         if (!cfg_shmized) return 0; /* nothing to do */
823
824         LOG(L_INFO, "INFO: cfg_rollback(): deleting the config changes "
825                         "[context=%p]\n",
826                         ctx);
827
828         /* the ctx must be locked while reading and writing
829         the list of changed variables */
830         CFG_CTX_LOCK(ctx);
831
832         for (   changed = ctx->changed_first;
833                 changed;
834                 changed = changed2
835         ) {
836                 changed2 = changed->next;
837
838                 if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
839                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR)) {
840                         memcpy(&new_string, changed->new_val, sizeof(char *));
841                         if (new_string) shm_free(new_string);
842                 }
843                 shm_free(changed);
844         }
845         ctx->changed_first = NULL;
846         ctx->changed_last = NULL;
847
848         CFG_CTX_UNLOCK(ctx);
849
850         return 0;
851 }
852
853 /* retrieves the value of a variable
854  * Return value:
855  *  0 - success
856  * -1 - error
857  *  1 - variable exists, but it is not readable
858  */
859 int cfg_get_by_name(cfg_ctx_t *ctx, str *group_name, str *var_name,
860                         void **val, unsigned int *val_type)
861 {
862         cfg_group_t     *group;
863         cfg_mapping_t   *var;
864         void            *p;
865         static str      s;      /* we need the value even
866                                 after the function returns */
867         int             i;
868         char            *ch;
869
870         /* verify the context even if we do not need it now
871         to make sure that a cfg driver has called the function
872         (very very weak security) */
873         if (!ctx) {
874                 LOG(L_ERR, "ERROR: cfg_get_by_name(): context is undefined\n");
875                 return -1;
876         }
877
878         /* look-up the group and the variable */
879         if (cfg_lookup_var(group_name, var_name, &group, &var))
880                 return -1;
881
882         if (var->def->on_change_cb) {
883                 /* The variable cannot be retrieved, because the fixup
884                 function may have changed it, and it is better to return
885                 an error than an incorrect value */
886                 return 1;
887         }
888
889         /* use the module's handle to access the variable
890         It means that the variable is read from the local config
891         after forking */
892         p = *(group->handle) + var->offset;
893
894         switch (CFG_VAR_TYPE(var)) {
895         case CFG_VAR_INT:
896                 memcpy(&i, p, sizeof(int));
897                 *val = (void *)(long)i;
898                 break;
899
900         case CFG_VAR_STRING:
901                 memcpy(&ch, p, sizeof(char *));
902                 *val = (void *)ch;
903                 break;
904
905         case CFG_VAR_STR:
906                 memcpy(&s, p, sizeof(str));
907                 *val = (void *)&s;
908                 break;
909
910         case CFG_VAR_POINTER:
911                 memcpy(val, &p, sizeof(void *));
912                 break;
913
914         }
915         *val_type = CFG_VAR_TYPE(var);
916
917         return 0;
918 }
919
920 /* returns the description of a variable */
921 int cfg_help(cfg_ctx_t *ctx, str *group_name, str *var_name,
922                         char **ch, unsigned int *input_type)
923 {
924         cfg_mapping_t   *var;
925
926         /* verify the context even if we do not need it now
927         to make sure that a cfg driver has called the function
928         (very very weak security) */
929         if (!ctx) {
930                 LOG(L_ERR, "ERROR: cfg_help(): context is undefined\n");
931                 return -1;
932         }
933
934         /* look-up the group and the variable */
935         if (cfg_lookup_var(group_name, var_name, NULL, &var))
936                 return -1;
937
938         *ch = var->def->descr;
939         if (input_type)
940                 *input_type = CFG_INPUT_TYPE(var);
941         return 0;
942 }
943
944 /* return the group name and the cfg structure definition,
945  * and moves the handle to the next group
946  * Return value:
947  *      0: no more group
948  *      1: group exists
949  */
950 int cfg_get_group_next(void **h,
951                         str *gname, cfg_def_t **def)
952 {
953         cfg_group_t     *group;
954
955         group = (cfg_group_t *)(*h);
956         if (group == NULL) return 0;
957
958         gname->s = group->name;
959         gname->len = group->name_len;
960         (*def) = group->mapping->def;
961
962         (*h) = (void *)group->next;
963         return 1;
964 }
965
966 /* Initialize the handle for cfg_diff_next() */
967 int cfg_diff_init(cfg_ctx_t *ctx,
968                 void **h)
969 {
970         if (!ctx) {
971                 LOG(L_ERR, "ERROR: cfg_diff_init(): context is undefined\n");
972                 return -1;
973         }
974
975         CFG_CTX_LOCK(ctx);
976         (*h) = (void *)ctx->changed_first;
977
978         return 0;
979 }
980
981 /* return the pending changes that have not been
982  * committed yet
983  */
984 int cfg_diff_next(void **h,
985                         str *gname, str *vname,
986                         void **old_val, void **new_val,
987                         unsigned int *val_type)
988 {
989         cfg_changed_var_t       *changed;
990         void    *p;
991         static str      old_s, new_s;   /* we need the value even
992                                         after the function returns */
993         int             i;
994         char            *ch;
995
996         changed = (cfg_changed_var_t *)(*h);
997         if (changed == NULL) return 0;
998
999         gname->s = changed->group->name;
1000         gname->len = changed->group->name_len;
1001         vname->s = changed->var->def->name;
1002         vname->len = changed->var->name_len;
1003
1004         /* use the module's handle to access the variable
1005         It means that the variable is read from the local config
1006         after forking */
1007         p = *(changed->group->handle) + changed->var->offset;
1008
1009         switch (CFG_VAR_TYPE(changed->var)) {
1010         case CFG_VAR_INT:
1011                 memcpy(&i, p, sizeof(int));
1012                 *old_val = (void *)(long)i;
1013                 memcpy(&i, changed->new_val, sizeof(int));
1014                 *new_val = (void *)(long)i;
1015                 break;
1016
1017         case CFG_VAR_STRING:
1018                 memcpy(&ch, p, sizeof(char *));
1019                 *old_val = (void *)ch;
1020                 memcpy(&ch, changed->new_val, sizeof(char *));
1021                 *new_val = (void *)ch;
1022                 break;
1023
1024         case CFG_VAR_STR:
1025                 memcpy(&old_s, p, sizeof(str));
1026                 *old_val = (void *)&old_s;
1027                 memcpy(&new_s, changed->new_val, sizeof(str));
1028                 *new_val = (void *)&new_s;
1029                 break;
1030
1031         case CFG_VAR_POINTER:
1032                 memcpy(old_val, &p, sizeof(void *));
1033                 memcpy(new_val, &changed->new_val, sizeof(void *));
1034                 break;
1035
1036         }
1037         *val_type = CFG_VAR_TYPE(changed->var);
1038
1039         (*h) = (void *)changed->next;
1040         return 1;
1041 }
1042
1043 /* release the handle of cfg_diff_next() */
1044 void cfg_diff_release(cfg_ctx_t *ctx)
1045 {
1046         if (!ctx) {
1047                 LOG(L_ERR, "ERROR: cfg_diff_release(): context is undefined\n");
1048                 return;
1049         }
1050
1051         CFG_CTX_UNLOCK(ctx);
1052 }