Coverage Report

Created: 2023-11-19 07:01

/src/kamailio/src/core/cfg/cfg.c
Line
Count
Source (jump to first uncovered line)
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
 */
36
int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
37
    void **handle)
38
0
{
39
0
  int i, num, size, group_name_len;
40
0
  cfg_mapping_t *mapping = NULL;
41
0
  cfg_group_t *group;
42
0
  int types;
43
44
0
  if(def == NULL || def[0].name == NULL)
45
0
    return -1;
46
47
  /* check the number of the variables */
48
0
  for(num = 0; def[num].name; num++)
49
0
    ;
50
51
0
  mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t) * num);
52
0
  if(!mapping) {
53
0
    PKG_MEM_ERROR;
54
0
    goto error;
55
0
  }
56
0
  memset(mapping, 0, sizeof(cfg_mapping_t) * num);
57
0
  types = 0;
58
  /* calculate the size of the memory block that has to
59
  be allocated for the cfg variables, and set the content of the
60
  cfg_mapping array the same time */
61
0
  for(i = 0, size = 0; i < num; i++) {
62
0
    mapping[i].def = &(def[i]);
63
0
    mapping[i].name_len = strlen(def[i].name);
64
0
    mapping[i].pos = i;
65
    /* record all the types for sanity checks */
66
0
    types |= 1 << CFG_VAR_MASK(def[i].type);
67
68
    /* padding depends on the type of the next variable */
69
0
    switch(CFG_VAR_MASK(def[i].type)) {
70
71
0
      case CFG_VAR_INT:
72
0
        size = ROUND_INT(size);
73
0
        mapping[i].offset = size;
74
0
        size += sizeof(int);
75
0
        break;
76
77
0
      case CFG_VAR_STRING:
78
0
      case CFG_VAR_POINTER:
79
0
        size = ROUND_POINTER(size);
80
0
        mapping[i].offset = size;
81
0
        size += sizeof(char *);
82
0
        break;
83
84
0
      case CFG_VAR_STR:
85
0
        size = ROUND_POINTER(size);
86
0
        mapping[i].offset = size;
87
0
        size += sizeof(str);
88
0
        break;
89
90
0
      default:
91
0
        LM_ERR("%s.%s: unsupported variable type\n", group_name,
92
0
            def[i].name);
93
0
        goto error;
94
0
    }
95
96
    /* verify the type of the input */
97
0
    if(CFG_INPUT_MASK(def[i].type) == 0) {
98
0
      def[i].type |= CFG_VAR_MASK(def[i].type) << CFG_INPUT_SHIFT;
99
0
    } else {
100
0
      if((CFG_INPUT_MASK(def[i].type)
101
0
             != CFG_VAR_MASK(def[i].type) << CFG_INPUT_SHIFT)
102
0
          && (def[i].on_change_cb == 0)) {
103
0
        LM_ERR("%s.%s: variable and input types are "
104
0
             "different, but no callback is defined for conversion\n",
105
0
            group_name, def[i].name);
106
0
        goto error;
107
0
      }
108
0
    }
109
110
0
    if(CFG_INPUT_MASK(def[i].type) > CFG_INPUT_STR) {
111
0
      LM_ERR("%s.%s: unsupported input type\n", group_name, def[i].name);
112
0
      goto error;
113
0
    }
114
115
0
    if(def[i].type & CFG_ATOMIC) {
116
0
      if(CFG_VAR_MASK(def[i].type) != CFG_VAR_INT) {
117
0
        LM_ERR("%s.%s: atomic change is allowed "
118
0
             "only for integer types\n",
119
0
            group_name, def[i].name);
120
0
        goto error;
121
0
      }
122
0
      if(def[i].on_set_child_cb) {
123
0
        LM_ERR("%s.%s: per-child process callback "
124
0
             "does not work together with atomic change\n",
125
0
            group_name, def[i].name);
126
0
        goto error;
127
0
      }
128
0
    }
129
0
  }
130
131
  /* fix the computed size (char*, str or pointer members will force
132
     structure padding to multiple of sizeof(pointer)) */
133
0
  if(types
134
0
      & ((1 << CFG_VAR_STRING) | (1 << CFG_VAR_STR)
135
0
          | (1 << CFG_VAR_POINTER)))
136
0
    size = ROUND_POINTER(size);
137
  /* minor validation */
138
0
  if(size != def_size) {
139
0
    LM_ERR("the specified size (%i) of the config "
140
0
         "structure does not equal with the calculated size (%i), check "
141
0
         "whether "
142
0
         "the variable types are correctly defined!\n",
143
0
        def_size, size);
144
0
    goto error;
145
0
  }
146
147
  /* The cfg variables are ready to use, let us set the handle
148
  before passing the new definitions to the drivers.
149
  We make the interface usable for the fixup functions
150
  at this step
151
  cfg_set_group() and cfg_new_group() need the handle to be set because
152
  they save its original value. */
153
0
  *handle = values;
154
155
0
  group_name_len = strlen(group_name);
156
  /* check for duplicates */
157
0
  if((group = cfg_lookup_group(group_name, group_name_len))) {
158
0
    if(group->dynamic != CFG_GROUP_UNKNOWN) {
159
      /* conflict with another module/core group, or with a dynamic group */
160
0
      LM_ERR("configuration group has been already declared: %s\n",
161
0
          group_name);
162
0
      goto error;
163
0
    }
164
    /* An empty group is found which does not have any variable yet */
165
0
    cfg_set_group(group, num, mapping, values, size, handle);
166
0
  } else {
167
    /* create a new group
168
    I will allocate memory in shm mem for the variables later in a single block,
169
    when we know the size of all the registered groups. */
170
0
    if(!(group = cfg_new_group(group_name, group_name_len, num, mapping,
171
0
           values, size, handle)))
172
0
      goto error;
173
0
  }
174
0
  group->dynamic = CFG_GROUP_STATIC;
175
176
  /* notify the drivers about the new config definition */
177
0
  cfg_notify_drivers(group_name, group_name_len, def);
178
179
0
  LM_DBG("new config group has been registered: '%s' (num=%d, size=%d)\n",
180
0
      group_name, num, size);
181
182
0
  return 0;
183
184
0
error:
185
0
  if(mapping)
186
0
    pkg_free(mapping);
187
0
  LM_ERR("failed to register the config group: %s\n", group_name);
188
189
0
  return -1;
190
0
}
191
192
/* declares a single variable with integer type */
193
int cfg_declare_int(char *group_name, char *var_name, int val, int min, int max,
194
    char *descr)
195
0
{
196
0
  cfg_script_var_t *var;
197
198
0
  if((var = new_cfg_script_var(group_name, var_name, CFG_VAR_INT, descr))
199
0
      == NULL)
200
0
    return -1;
201
202
0
  var->val.i = val;
203
0
  var->min = min;
204
0
  var->max = max;
205
206
0
  return 0;
207
0
}
208
209
/* declares a single variable with str type */
210
int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr)
211
0
{
212
0
  cfg_script_var_t *var;
213
0
  int len;
214
215
0
  if((var = new_cfg_script_var(group_name, var_name, CFG_VAR_STR, descr))
216
0
      == NULL)
217
0
    return -1;
218
219
0
  if(val) {
220
0
    len = strlen(val);
221
0
    var->val.s.s = (char *)pkg_malloc(sizeof(char) * (len + 1));
222
0
    if(!var->val.s.s) {
223
0
      PKG_MEM_ERROR;
224
0
      return -1;
225
0
    }
226
0
    memcpy(var->val.s.s, val, len + 1);
227
0
    var->val.s.len = len;
228
0
  } else {
229
0
    var->val.s.s = NULL;
230
0
    var->val.s.len = 0;
231
0
  }
232
233
0
  return 0;
234
0
}
235
236
/* Add a variable to a group instance with integer type.
237
 * The group instance is created if it does not exist.
238
 * wrapper function for new_add_var()
239
 */
240
int cfg_ginst_var_int(
241
    char *group_name, unsigned int group_id, char *var_name, int val)
242
0
{
243
0
  str gname, vname;
244
245
0
  gname.s = group_name;
246
0
  gname.len = strlen(group_name);
247
0
  vname.s = var_name;
248
0
  vname.len = strlen(var_name);
249
250
0
  return new_add_var(
251
0
      &gname, group_id, &vname, (void *)(long)val, CFG_VAR_INT);
252
0
}
253
254
/* Add a variable to a group instance with string type.
255
 * The group instance is created if it does not exist.
256
 * wrapper function for new_add_var()
257
 */
258
int cfg_ginst_var_string(
259
    char *group_name, unsigned int group_id, char *var_name, char *val)
260
0
{
261
0
  str gname, vname;
262
263
0
  gname.s = group_name;
264
0
  gname.len = strlen(group_name);
265
0
  vname.s = var_name;
266
0
  vname.len = strlen(var_name);
267
268
0
  return new_add_var(&gname, group_id, &vname, (void *)val, CFG_VAR_STRING);
269
0
}
270
271
/* Create a new group instance.
272
 * wrapper function for new_add_var()
273
 */
274
int cfg_new_ginst(char *group_name, unsigned int group_id)
275
0
{
276
0
  str gname;
277
278
0
  gname.s = group_name;
279
0
  gname.len = strlen(group_name);
280
281
0
  return new_add_var(
282
0
      &gname, group_id, NULL /* var */, NULL /* val */, 0 /* type */);
283
0
}
284
285
/* returns the handle of a cfg group */
286
void **cfg_get_handle(char *gname)
287
0
{
288
0
  cfg_group_t *group;
289
290
0
  group = cfg_lookup_group(gname, strlen(gname));
291
0
  if(!group || (group->dynamic != CFG_GROUP_STATIC))
292
0
    return NULL;
293
294
0
  return group->handle;
295
0
}
296
297
298
/* Set the group_id pointer based on the group string.
299
 * The string is either "group_name", or "group_name[group_id]"
300
 * *group_id is set to null in the former case.
301
 * Warning: changes the group string
302
 */
303
int cfg_get_group_id(str *group, unsigned int **group_id)
304
0
{
305
0
  static unsigned int id;
306
0
  str s;
307
308
0
  if(!group->s || (group->s[group->len - 1] != ']')) {
309
0
    *group_id = NULL;
310
0
    return 0;
311
0
  }
312
313
0
  s.s = group->s + group->len - 2;
314
0
  s.len = 0;
315
0
  while((s.s > group->s) && (*s.s != '[')) {
316
0
    s.s--;
317
0
    s.len++;
318
0
  }
319
0
  if(s.s == group->s) /* '[' not found */
320
0
    return -1;
321
0
  group->len = s.s - group->s;
322
0
  s.s++;
323
0
  if(!group->len || !s.len)
324
0
    return -1;
325
0
  if(str2int(&s, &id))
326
0
    return -1;
327
328
0
  *group_id = &id;
329
0
  return 0;
330
0
}