core: increased verbosity of error log message
[sip-router] / cfg / cfg.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
34 #include "../ut.h"
35 #include "../mem/mem.h"
36 #include "cfg_struct.h"
37 #include "cfg_ctx.h"
38 #include "cfg_script.h"
39 #include "cfg.h"
40
41 /* declares a new cfg group
42  * handler is set to the memory area where the variables are stored
43  * return value is -1 on error
44  */
45 int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
46                         void **handle)
47 {
48         int     i, num, size, group_name_len;
49         cfg_mapping_t   *mapping = NULL;
50
51         /* check the number of the variables */
52         for (num=0; def[num].name; num++);
53
54         mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*num);
55         if (!mapping) {
56                 LOG(L_ERR, "ERROR: register_cfg_def(): not enough memory\n");
57                 goto error;
58         }
59         memset(mapping, 0, sizeof(cfg_mapping_t)*num);
60
61         /* calculate the size of the memory block that has to
62         be allocated for the cfg variables, and set the content of the 
63         cfg_mapping array the same time */
64         for (i=0, size=0; i<num; i++) {
65                 mapping[i].def = &(def[i]);
66                 mapping[i].name_len = strlen(def[i].name);
67
68                 /* padding depends on the type of the next variable */
69                 switch (CFG_VAR_MASK(def[i].type)) {
70
71                 case CFG_VAR_INT:
72                         size = ROUND_INT(size);
73                         mapping[i].offset = size;
74                         size += sizeof(int);
75                         break;
76
77                 case CFG_VAR_STRING:
78                 case CFG_VAR_POINTER:
79                         size = ROUND_POINTER(size);
80                         mapping[i].offset = size;
81                         size += sizeof(char *);
82                         break;
83
84                 case CFG_VAR_STR:
85                         size = ROUND_POINTER(size);
86                         mapping[i].offset = size;
87                         size += sizeof(str);
88                         break;
89
90                 default:
91                         LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: unsupported variable type\n",
92                                         group_name, def[i].name);
93                         goto error;
94                 }
95
96                 /* verify the type of the input */
97                 if (CFG_INPUT_MASK(def[i].type)==0) {
98                         def[i].type |= def[i].type << CFG_INPUT_SHIFT;
99                 } else {
100                         if ((CFG_INPUT_MASK(def[i].type) != CFG_VAR_MASK(def[i].type) << CFG_INPUT_SHIFT)
101                         && (def[i].on_change_cb == 0)) {
102                                 LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: variable and input types are "
103                                         "different, but no callback is defined for conversion\n",
104                                         group_name, def[i].name);
105                                 goto error;
106                         }
107                 }
108
109                 if (CFG_INPUT_MASK(def[i].type) > CFG_INPUT_STR) {
110                         LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: unsupported input type\n",
111                                         group_name, def[i].name);
112                         goto error;
113                 }
114
115                 if (def[i].type & CFG_ATOMIC) {
116                         if (CFG_VAR_MASK(def[i].type) != CFG_VAR_INT) {
117                                 LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: atomic change is allowed "
118                                                 "only for integer types\n",
119                                                 group_name, def[i].name);
120                                 goto error;
121                         }
122                         if (def[i].on_set_child_cb) {
123                                 LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: per-child process callback "
124                                                 "does not work together with atomic change\n",
125                                                 group_name, def[i].name);
126                                 goto error;
127                         }
128                 }
129         }
130
131         /* minor validation */
132         if (size != def_size) {
133                 LOG(L_ERR, "ERROR: register_cfg_def(): the specified size (%i) of the config "
134                         "structure does not equal with the calculated size (%i), check whether "
135                         "the variable types are correctly defined!\n", def_size, size);
136                 goto error;
137         }
138
139         group_name_len = strlen(group_name);
140         /* check for duplicates */
141         if (cfg_lookup_group(group_name, group_name_len)) {
142                 LOG(L_ERR, "ERROR: register_cfg_def(): "
143                         "configuration group has been already declared: %s\n",
144                         group_name);
145                 goto error;
146         }
147
148         /* create a new group
149         I will allocate memory in shm mem for the variables later in a single block,
150         when we know the size of all the registered groups. */
151         if (!cfg_new_group(group_name, group_name_len, num, mapping, values, size, handle))
152                 goto error;
153
154         /* The cfg variables are ready to use, let us set the handle
155         before passing the new definitions to the drivers.
156         We make the interface usable for the fixup functions
157         at this step */
158         *handle = values;
159
160         /* notify the drivers about the new config definition */
161         cfg_notify_drivers(group_name, group_name_len, def);
162
163         LOG(L_DBG, "DEBUG: register_cfg_def(): "
164                 "new config group has been registered: '%s' (num=%d, size=%d)\n",
165                 group_name, num, size);
166
167         return 0;
168
169 error:
170         if (mapping) pkg_free(mapping);
171         LOG(L_ERR, "ERROR: register_cfg_def(): Failed to register the config group: %s\n",
172                         group_name);
173
174         return -1;
175 }
176
177 /* declares a single variable with integer type */
178 int cfg_declare_int(char *group_name, char *var_name,
179                 int val, int min, int max, char *descr)
180 {
181         cfg_script_var_t        *var;
182
183         if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_INT, descr)) == NULL)
184                 return -1;
185
186         var->val.i = val;
187         var->min = min;
188         var->max = max;
189
190         return 0;
191 }
192
193 /* declares a single variable with str type */
194 int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr)
195 {
196         cfg_script_var_t        *var;
197         int     len;
198
199         if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_STR, descr)) == NULL)
200                 return -1;
201
202         if (val) {
203                 len = strlen(val);
204                 var->val.s.s = (char *)pkg_malloc(sizeof(char) * (len + 1));
205                 if (!var->val.s.s) {
206                         LOG(L_ERR, "ERROR: cfg_declare_str(): not enough memory\n");
207                         return -1;
208                 }
209                 memcpy(var->val.s.s, val, len + 1);
210                 var->val.s.len = len;
211         } else {        
212                 var->val.s.s = NULL;
213                 var->val.s.len = 0;
214         }
215
216         return 0;
217 }
218
219 /* returns the handle of a cfg group */
220 void **cfg_get_handle(char *gname)
221 {
222         cfg_group_t     *group;
223
224         group = cfg_lookup_group(gname, strlen(gname));
225         if (!group || group->dynamic) return NULL;
226
227         return group->handle;
228 }