1 /*
2 * Copyright (C) 2007 iptelorg GmbH
3 *
4 * This file is part of Kamailio, a free SIP server.
5 *
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
10 *
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include <string.h>
23
24 #include "../ut.h"
25 #include "../mem/mem.h"
26 #include "cfg_struct.h"
27 #include "cfg_ctx.h"
28 #include "cfg_script.h"
29 #include "cfg.h"
30
31 /*! \brief declares a new cfg group
32 *
33 * handler is set to the memory area where the variables are stored
34 * \return value is -1 on error
35 */
cfg_declare(char * group_name,cfg_def_t * def,void * values,int def_size,void ** handle)36 int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
37 void **handle)
38 {
39 int i, num, size, group_name_len;
40 cfg_mapping_t *mapping = NULL;
41 cfg_group_t *group;
42 int types;
43
44 if(def==NULL || def[0].name==NULL)
45 return -1;
46
47 /* check the number of the variables */
48 for (num=0; def[num].name; num++);
49
50 mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*num);
51 if (!mapping) {
52 PKG_MEM_ERROR;
53 goto error;
54 }
55 memset(mapping, 0, sizeof(cfg_mapping_t)*num);
56 types=0;
57 /* calculate the size of the memory block that has to
58 be allocated for the cfg variables, and set the content of the
59 cfg_mapping array the same time */
60 for (i=0, size=0; i<num; i++) {
61 mapping[i].def = &(def[i]);
62 mapping[i].name_len = strlen(def[i].name);
63 mapping[i].pos = i;
64 /* record all the types for sanity checks */
65 types|=1 << CFG_VAR_MASK(def[i].type);
66
67 /* padding depends on the type of the next variable */
68 switch (CFG_VAR_MASK(def[i].type)) {
69
70 case CFG_VAR_INT:
71 size = ROUND_INT(size);
72 mapping[i].offset = size;
73 size += sizeof(int);
74 break;
75
76 case CFG_VAR_STRING:
77 case CFG_VAR_POINTER:
78 size = ROUND_POINTER(size);
79 mapping[i].offset = size;
80 size += sizeof(char *);
81 break;
82
83 case CFG_VAR_STR:
84 size = ROUND_POINTER(size);
85 mapping[i].offset = size;
86 size += sizeof(str);
87 break;
88
89 default:
90 LM_ERR("%s.%s: unsupported variable type\n",
91 group_name, def[i].name);
92 goto error;
93 }
94
95 /* verify the type of the input */
96 if (CFG_INPUT_MASK(def[i].type)==0) {
97 def[i].type |= CFG_VAR_MASK(def[i].type) << CFG_INPUT_SHIFT;
98 } else {
99 if ((CFG_INPUT_MASK(def[i].type) != CFG_VAR_MASK(def[i].type) << CFG_INPUT_SHIFT)
100 && (def[i].on_change_cb == 0)) {
101 LM_ERR("%s.%s: variable and input types are "
102 "different, but no callback is defined for conversion\n",
103 group_name, def[i].name);
104 goto error;
105 }
106 }
107
108 if (CFG_INPUT_MASK(def[i].type) > CFG_INPUT_STR) {
109 LM_ERR("%s.%s: unsupported input type\n",
110 group_name, def[i].name);
111 goto error;
112 }
113
114 if (def[i].type & CFG_ATOMIC) {
115 if (CFG_VAR_MASK(def[i].type) != CFG_VAR_INT) {
116 LM_ERR("%s.%s: atomic change is allowed "
117 "only for integer types\n",
118 group_name, def[i].name);
119 goto error;
120 }
121 if (def[i].on_set_child_cb) {
122 LM_ERR("%s.%s: per-child process callback "
123 "does not work together with atomic change\n",
124 group_name, def[i].name);
125 goto error;
126 }
127 }
128 }
129
130 /* fix the computed size (char*, str or pointer members will force
131 structure padding to multiple of sizeof(pointer)) */
132 if (types & ((1<<CFG_VAR_STRING)|(1<<CFG_VAR_STR)|(1<<CFG_VAR_POINTER)))
133 size=ROUND_POINTER(size);
134 /* minor validation */
135 if (size != def_size) {
136 LM_ERR("the specified size (%i) of the config "
137 "structure does not equal with the calculated size (%i), check whether "
138 "the variable types are correctly defined!\n", def_size, size);
139 goto error;
140 }
141
142 /* The cfg variables are ready to use, let us set the handle
143 before passing the new definitions to the drivers.
144 We make the interface usable for the fixup functions
145 at this step
146 cfg_set_group() and cfg_new_group() need the handle to be set because
147 they save its original value. */
148 *handle = values;
149
150 group_name_len = strlen(group_name);
151 /* check for duplicates */
152 if ((group = cfg_lookup_group(group_name, group_name_len))) {
153 if (group->dynamic != CFG_GROUP_UNKNOWN) {
154 /* conflict with another module/core group, or with a dynamic group */
155 LM_ERR("configuration group has been already declared: %s\n",
156 group_name);
157 goto error;
158 }
159 /* An empty group is found which does not have any variable yet */
160 cfg_set_group(group, num, mapping, values, size, handle);
161 } else {
162 /* create a new group
163 I will allocate memory in shm mem for the variables later in a single block,
164 when we know the size of all the registered groups. */
165 if (!(group = cfg_new_group(group_name, group_name_len, num, mapping, values, size, handle)))
166 goto error;
167 }
168 group->dynamic = CFG_GROUP_STATIC;
169
170 /* notify the drivers about the new config definition */
171 cfg_notify_drivers(group_name, group_name_len, def);
172
173 LM_DBG("new config group has been registered: '%s' (num=%d, size=%d)\n",
174 group_name, num, size);
175
176 return 0;
177
178 error:
179 if (mapping) pkg_free(mapping);
180 LM_ERR("failed to register the config group: %s\n",
181 group_name);
182
183 return -1;
184 }
185
186 /* declares a single variable with integer type */
cfg_declare_int(char * group_name,char * var_name,int val,int min,int max,char * descr)187 int cfg_declare_int(char *group_name, char *var_name,
188 int val, int min, int max, char *descr)
189 {
190 cfg_script_var_t *var;
191
192 if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_INT, descr)) == NULL)
193 return -1;
194
195 var->val.i = val;
196 var->min = min;
197 var->max = max;
198
199 return 0;
200 }
201
202 /* declares a single variable with str type */
cfg_declare_str(char * group_name,char * var_name,char * val,char * descr)203 int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr)
204 {
205 cfg_script_var_t *var;
206 int len;
207
208 if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_STR, descr)) == NULL)
209 return -1;
210
211 if (val) {
212 len = strlen(val);
213 var->val.s.s = (char *)pkg_malloc(sizeof(char) * (len + 1));
214 if (!var->val.s.s) {
215 PKG_MEM_ERROR;
216 return -1;
217 }
218 memcpy(var->val.s.s, val, len + 1);
219 var->val.s.len = len;
220 } else {
221 var->val.s.s = NULL;
222 var->val.s.len = 0;
223 }
224
225 return 0;
226 }
227
228 /* Add a varibale to a group instance with integer type.
229 * The group instance is created if it does not exist.
230 * wrapper function for new_add_var()
231 */
cfg_ginst_var_int(char * group_name,unsigned int group_id,char * var_name,int val)232 int cfg_ginst_var_int(char *group_name, unsigned int group_id, char *var_name,
233 int val)
234 {
235 str gname, vname;
236
237 gname.s = group_name;
238 gname.len = strlen(group_name);
239 vname.s = var_name;
240 vname.len = strlen(var_name);
241
242 return new_add_var(&gname, group_id, &vname,
243 (void *)(long)val, CFG_VAR_INT);
244 }
245
246 /* Add a varibale to a group instance with string type.
247 * The group instance is created if it does not exist.
248 * wrapper function for new_add_var()
249 */
cfg_ginst_var_string(char * group_name,unsigned int group_id,char * var_name,char * val)250 int cfg_ginst_var_string(char *group_name, unsigned int group_id, char *var_name,
251 char *val)
252 {
253 str gname, vname;
254
255 gname.s = group_name;
256 gname.len = strlen(group_name);
257 vname.s = var_name;
258 vname.len = strlen(var_name);
259
260 return new_add_var(&gname, group_id, &vname,
261 (void *)val, CFG_VAR_STRING);
262 }
263
264 /* Create a new group instance.
265 * wrapper function for new_add_var()
266 */
cfg_new_ginst(char * group_name,unsigned int group_id)267 int cfg_new_ginst(char *group_name, unsigned int group_id)
268 {
269 str gname;
270
271 gname.s = group_name;
272 gname.len = strlen(group_name);
273
274 return new_add_var(&gname, group_id, NULL /* var */,
275 NULL /* val */, 0 /* type */);
276 }
277
278 /* returns the handle of a cfg group */
cfg_get_handle(char * gname)279 void **cfg_get_handle(char *gname)
280 {
281 cfg_group_t *group;
282
283 group = cfg_lookup_group(gname, strlen(gname));
284 if (!group || (group->dynamic != CFG_GROUP_STATIC)) return NULL;
285
286 return group->handle;
287 }
288