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