jabberd2  2.7.0
config.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program 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  * This program 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., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "util.h"
22 #include "expat.h"
23 
26 {
27  config_t c;
28 
29  c = (config_t) calloc(1, sizeof(struct config_st));
30 
31  c->hash = xhash_new(501);
32 
33  return c;
34 }
35 
36 struct build_data
37 {
39  int depth;
40 };
41 
42 static void _config_startElement(void *arg, const char *name, const char **atts)
43 {
44  struct build_data *bd = (struct build_data *) arg;
45  int i = 0;
46 
47  nad_append_elem(bd->nad, -1, (char *) name, bd->depth);
48  while(atts[i] != NULL)
49  {
50  nad_append_attr(bd->nad, -1, (char *) atts[i], (char *) atts[i + 1]);
51  i += 2;
52  }
53 
54  bd->depth++;
55 }
56 
57 static void _config_endElement(void *arg, const char *name)
58 {
59  struct build_data *bd = (struct build_data *) arg;
60 
61  bd->depth--;
62 }
63 
64 static void _config_charData(void *arg, const char *str, int len)
65 {
66  struct build_data *bd = (struct build_data *) arg;
67 
68  nad_append_cdata(bd->nad, (char *) str, len, bd->depth);
69 }
70 
71 static char *_config_expandx(config_t c, const char *value, int l);
72 
74 int config_load(config_t c, const char *file)
75 {
76  return config_load_with_id(c, file, 0);
77 }
78 
80 int config_load_with_id(config_t c, const char *file, const char *id)
81 {
82  struct build_data bd;
83  FILE *f;
84  XML_Parser p;
85  unsigned int done, len, end, i, j;
86  int attr;
87  char buf[1024], *next;
88  struct nad_elem_st **path;
89  config_elem_t elem;
90  int rv = 0;
91 
92  /* open the file */
93  f = fopen(file, "r");
94  if(f == NULL)
95  {
96  fprintf(stderr, "config_load: couldn't open %s for reading: %s\n", file, strerror(errno));
97  return 1;
98  }
99 
100  /* new parser */
101  p = XML_ParserCreate(NULL);
102  if(p == NULL)
103  {
104  fprintf(stderr, "config_load: couldn't allocate XML parser\n");
105  fclose(f);
106  return 1;
107  }
108 
109  /* nice new nad to parse it into */
110  bd.nad = nad_new();
111  bd.depth = 0;
112 
113  /* setup the parser */
114  XML_SetUserData(p, (void *) &bd);
115  XML_SetElementHandler(p, _config_startElement, _config_endElement);
116  XML_SetCharacterDataHandler(p, _config_charData);
117 
118  for(;;)
119  {
120  /* read that file */
121  len = fread(buf, 1, 1024, f);
122  if(ferror(f))
123  {
124  fprintf(stderr, "config_load: read error: %s\n", strerror(errno));
125  XML_ParserFree(p);
126  fclose(f);
127  nad_free(bd.nad);
128  return 1;
129  }
130  done = feof(f);
131 
132  /* parse it */
133  if(!XML_Parse(p, buf, len, done))
134  {
135  fprintf(stderr, "config_load: parse error at line %llu: %s\n", (unsigned long long) XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p)));
136  XML_ParserFree(p);
137  fclose(f);
138  nad_free(bd.nad);
139  return 1;
140  }
141 
142  if(done)
143  break;
144  }
145 
146  /* done reading */
147  XML_ParserFree(p);
148  fclose(f);
149 
150  // Put id if specified
151  if (id) {
152  elem = pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st));
153  xhash_put(c->hash, pstrdup(xhash_pool(c->hash), "id"), elem);
154  elem->values = calloc(1, sizeof(char *));
155  elem->values[0] = pstrdup(xhash_pool(c->hash), id);
156  elem->nvalues = 1;
157  }
158 
159  /* now, turn the nad into a config hash */
160  path = NULL;
161  len = 0, end = 0;
162  /* start at 1, so we skip the root element */
163  for(i = 1; i < bd.nad->ecur && rv == 0; i++)
164  {
165  /* make sure we have enough room to add this element to our path */
166  if(end <= bd.nad->elems[i].depth)
167  {
168  end = bd.nad->elems[i].depth + 1;
169  path = (struct nad_elem_st **) realloc((void *) path, sizeof(struct nad_elem_st *) * end);
170  }
171 
172  /* save this path element */
173  path[bd.nad->elems[i].depth] = &bd.nad->elems[i];
174  len = bd.nad->elems[i].depth + 1;
175 
176  /* construct the key from the current path */
177  next = buf;
178  for(j = 1; j < len; j++)
179  {
180  strncpy(next, bd.nad->cdata + path[j]->iname, path[j]->lname);
181  next = next + path[j]->lname;
182  *next = '.';
183  next++;
184  }
185  next--;
186  *next = '\0';
187 
188  /* find the config element for this key */
189  elem = xhash_get(c->hash, buf);
190  if(elem == NULL)
191  {
192  /* haven't seen it before, so create it */
193  elem = pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st));
194  xhash_put(c->hash, pstrdup(xhash_pool(c->hash), buf), elem);
195  }
196 
197  /* make room for this value .. can't easily realloc off a pool, so
198  * we do it this way and let _config_reaper clean up */
199  elem->values = realloc((void *) elem->values, sizeof(char *) * (elem->nvalues + 1));
200 
201  /* and copy it in */
202  if(NAD_CDATA_L(bd.nad, i) > 0) {
203  // Expand values
204 
205  const char *val = _config_expandx(c, NAD_CDATA(bd.nad, i), NAD_CDATA_L(bd.nad, i));
206 
207  if (!val) {
208  rv = 1;
209  break;
210  }
211  // Make a copy
212  elem->values[elem->nvalues] = val;
213  } else {
214  elem->values[elem->nvalues] = "1";
215  }
216 
217  /* make room for the attribute lists */
218  elem->attrs = realloc((void *) elem->attrs, sizeof(char **) * (elem->nvalues + 1));
219  elem->attrs[elem->nvalues] = NULL;
220 
221  /* count the attributes */
222  for(attr = bd.nad->elems[i].attr, j = 0; attr >= 0; attr = bd.nad->attrs[attr].next, j++);
223 
224  /* make space */
225  elem->attrs[elem->nvalues] = pmalloc(xhash_pool(c->hash), sizeof(char *) * (j * 2 + 2));
226 
227  /* if we have some */
228  if(j > 0)
229  {
230  /* copy them in */
231  j = 0;
232  attr = bd.nad->elems[i].attr;
233  while(attr >= 0)
234  {
235  elem->attrs[elem->nvalues][j] = pstrdupx(xhash_pool(c->hash), NAD_ANAME(bd.nad, attr), NAD_ANAME_L(bd.nad, attr));
236  elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr));
237 
238  /*
239  * pstrdupx(blob, 0) returns NULL - which means that later
240  * there's no way of telling whether an attribute is defined
241  * as empty, or just not defined. This fixes that by creating
242  * an empty string for attributes which are defined empty
243  */
244  if (NAD_AVAL_L(bd.nad, attr)==0) {
245  elem->attrs[elem->nvalues][j + 1] = pstrdup(xhash_pool(c->hash), "");
246  } else {
247  elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr));
248  }
249  j += 2;
250  attr = bd.nad->attrs[attr].next;
251  }
252  }
253 
254  /* do this and we can use j_attr */
255  elem->attrs[elem->nvalues][j] = NULL;
256  elem->attrs[elem->nvalues][j + 1] = NULL;
257 
258  elem->nvalues++;
259  }
260 
261  if(path != NULL)
262  free(path);
263 
264  if(c->nad != NULL)
265  nad_free(c->nad);
266  c->nad = bd.nad;
267 
268  return rv;
269 }
270 
272 config_elem_t config_get(config_t c, const char *key)
273 {
274  return xhash_get(c->hash, key);
275 }
276 
278 const char *config_get_one(config_t c, const char* key, int num)
279 {
280  config_elem_t elem = xhash_get(c->hash, key);
281 
282  if(elem == NULL)
283  return NULL;
284 
285  if(num >= elem->nvalues)
286  return NULL;
287 
288  return elem->values[num];
289 }
290 
292 const char *config_get_one_default(config_t c, const char *key, int num, const char *default_value)
293 {
294  const char *rv = config_get_one(c, key, num);
295 
296  if (!rv)
297  rv = default_value;
298 
299  return rv;
300 };
301 
302 
304 int config_count(config_t c, const char *key)
305 {
306  config_elem_t elem = xhash_get(c->hash, key);
307 
308  if(elem == NULL)
309  return 0;
310 
311  return elem->nvalues;
312 }
313 
315 char *config_get_attr(config_t c, const char *key, int num, const char *attr)
316 {
317  config_elem_t elem = xhash_get(c->hash, key);
318 
319  if(elem == NULL || num >= elem->nvalues || elem->attrs == NULL || elem->attrs[num] == NULL)
320  return NULL;
321 
322  return j_attr((const char **) elem->attrs[num], attr);
323 }
324 
326 static void _config_reaper(const char *key, int keylen, void *val, void *arg)
327 {
328  config_elem_t elem = (config_elem_t) val;
329 
330  free(elem->values);
331  free(elem->attrs);
332 }
333 
334 char *config_expand(config_t c, const char *value)
335 {
336  return _config_expandx(c, value, strlen(value));
337 }
338 
339 static char *_config_expandx(config_t c, const char *value, int l)
340 {
341 #ifdef CONFIGEXPAND_GUARDED
342  static char guard[] = "deadbeaf";
343 #endif
344 
345 // fprintf(stderr, "config_expand: Expanding '%s'\n", value);
346  char *s = strndup(value, l);
347 
348  char *var_start, *var_end;
349 
350  while ((var_start = strstr(s, "${")) != 0) {
351 // fprintf(stderr, "config_expand: processing '%s'\n", s);
352  var_end = strstr(var_start + 2, "}");
353 
354  if (var_end) {
355  char *tail = var_end + 1;
356  char *var = var_start + 2;
357  *var_end = 0;
358 
359 // fprintf(stderr, "config_expand: Var '%s', tail is '%s'\n", var, tail);
360 
361  const char *var_value = config_get_one(c, var, 0);
362 
363  if (var_value) {
364  int len = (var_start - s) + strlen(tail) + strlen(var_value) + 1;
365 
366 #ifdef CONFIGEXPAND_GUARDED
367  len += sizeof(guard);
368 #endif
369  char *expanded_str = calloc(len, 1);
370 
371 #ifdef CONFIGEXPAND_GUARDED
372  char *p_guard = expanded_str + len - sizeof(guard);
373  strncpy(p_guard, guard, sizeof(guard));
374 #endif
375 
376  char *p = expanded_str;
377  strncpy(expanded_str, s, var_start - s);
378  p += var_start - s;
379 
380  strcpy(p, var_value);
381  p += strlen(var_value);
382 
383  strcpy(p, tail);
384 
385  free(s);
386  s = expanded_str;
387  } else {
388  fprintf(stderr, "config_expand: Have no '%s' defined\n", var);
389  free(s);
390  s = 0;
391  break;
392  }
393  } else {
394  fprintf(stderr, "config_expand: } mismatch\n");
395  free(s);
396  s = 0;
397  break;
398  }
399  }
400 
401  if (s) {
402  char *retval = pstrdup(xhash_pool(c->hash), s);
403  free(s);
404  return retval;
405  } else {
406  return 0;
407  }
408 }
409 
412 {
413  xhash_walk(c->hash, _config_reaper, NULL);
414 
415  xhash_free(c->hash);
416 
417  nad_free(c->nad);
418 
419  free(c);
420 }
int attr
Definition: nad.h:74
Definition: nad.h:93
nad_t nad_new(void)
create a new nad
Definition: nad.c:125
int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
attach new attr to the last elem
Definition: nad.c:745
const char ** values
Definition: util.h:209
int config_load_with_id(config_t c, const char *file, const char *id)
turn an xml file into a config hash
Definition: config.c:80
#define NAD_CDATA_L(N, E)
Definition: nad.h:186
void * pmalloc(pool_t p, int size)
Definition: pool.c:141
void xhash_free(xht h)
Definition: xhash.c:241
int depth
Definition: config.c:39
void config_free(config_t c)
cleanup
Definition: config.c:411
void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
append new cdata to the last elem
Definition: nad.c:753
config_t config_new(void)
new config structure
Definition: config.c:25
holder for the config hash and nad
Definition: util.h:200
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
create a new elem on the list
Definition: nad.c:711
void nad_free(nad_t nad)
free that nad
Definition: nad.c:180
int lname
Definition: nad.h:71
#define NAD_ANAME_L(N, A)
Definition: nad.h:188
static void _config_endElement(void *arg, const char *name)
Definition: config.c:57
char * config_get_attr(config_t c, const char *key, int num, const char *attr)
get an attr for this value
Definition: config.c:315
static void _config_reaper(const char *key, int keylen, void *val, void *arg)
cleanup helper
Definition: config.c:326
unsigned int depth
Definition: nad.h:77
nad_t nad
Definition: util.h:203
void * pmalloco(pool_t p, int size)
easy safety utility (for creating blank mem for structs, etc)
Definition: pool.c:183
char * pstrdupx(pool_t p, const char *src, int len)
use given size
Definition: pool.c:205
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
XML_Parser p
Definition: nad.c:1313
#define NAD_ANAME(N, A)
Definition: nad.h:187
#define NAD_AVAL_L(N, A)
Definition: nad.h:190
#define NAD_AVAL(N, A)
Definition: nad.h:189
nad_t nad
Definition: config.c:38
static char * _config_expandx(config_t c, const char *value, int l)
Definition: config.c:339
config_elem_t config_get(config_t c, const char *key)
get the config element for this key
Definition: config.c:272
struct config_elem_st * config_elem_t
Definition: util.h:196
void xhash_walk(xht h, xhash_walker w, void *arg)
Definition: xhash.c:268
int config_load(config_t c, const char *file)
turn an xml file into a config hash
Definition: config.c:74
const char *** attrs
Definition: util.h:211
pool_t xhash_pool(xht h)
get our pool
Definition: xhash.c:305
struct config_st * config_t
Definition: util.h:197
xht hash
Definition: util.h:202
static void _config_startElement(void *arg, const char *name, const char **atts)
Definition: config.c:42
char * pstrdup(pool_t p, const char *src)
XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is wit...
Definition: pool.c:191
#define NAD_CDATA(N, E)
Definition: nad.h:185
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
char * j_attr(const char **atts, const char *attr)
Definition: str.c:95
char * config_expand(config_t c, const char *value)
Definition: config.c:334
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
Definition: config.c:278
xht xhash_new(int prime)
Definition: xhash.c:96
static void _config_charData(void *arg, const char *str, int len)
Definition: config.c:64
a single element
Definition: util.h:207
int config_count(config_t c, const char *key)
how many values for this key?
Definition: config.c:304
int nvalues
Definition: util.h:210
const char * config_get_one_default(config_t c, const char *key, int num, const char *default_value)
get config value n for this key, returns default_value if not found
Definition: config.c:292
parse a buffer into a nad
Definition: config.c:36
int iname
Definition: nad.h:71