jabberd2  2.3.4
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  int done, len, end, i, j, attr;
86  char buf[1024], *next;
87  struct nad_elem_st **path;
88  config_elem_t elem;
89  int rv = 0;
90 
91  /* open the file */
92  f = fopen(file, "r");
93  if(f == NULL)
94  {
95  fprintf(stderr, "config_load: couldn't open %s for reading: %s\n", file, strerror(errno));
96  return 1;
97  }
98 
99  /* new parser */
100  p = XML_ParserCreate(NULL);
101  if(p == NULL)
102  {
103  fprintf(stderr, "config_load: couldn't allocate XML parser\n");
104  fclose(f);
105  return 1;
106  }
107 
108  /* nice new nad to parse it into */
109  bd.nad = nad_new();
110  bd.depth = 0;
111 
112  /* setup the parser */
113  XML_SetUserData(p, (void *) &bd);
114  XML_SetElementHandler(p, _config_startElement, _config_endElement);
115  XML_SetCharacterDataHandler(p, _config_charData);
116 
117  for(;;)
118  {
119  /* read that file */
120  len = fread(buf, 1, 1024, f);
121  if(ferror(f))
122  {
123  fprintf(stderr, "config_load: read error: %s\n", strerror(errno));
124  XML_ParserFree(p);
125  fclose(f);
126  nad_free(bd.nad);
127  return 1;
128  }
129  done = feof(f);
130 
131  /* parse it */
132  if(!XML_Parse(p, buf, len, done))
133  {
134  fprintf(stderr, "config_load: parse error at line %llu: %s\n", (unsigned long long) XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p)));
135  XML_ParserFree(p);
136  fclose(f);
137  nad_free(bd.nad);
138  return 1;
139  }
140 
141  if(done)
142  break;
143  }
144 
145  /* done reading */
146  XML_ParserFree(p);
147  fclose(f);
148 
149  // Put id if specified
150  if (id) {
151  elem = pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st));
152  xhash_put(c->hash, pstrdup(xhash_pool(c->hash), "id"), elem);
153  elem->values = calloc(1, sizeof(char *));
154  elem->values[0] = pstrdup(xhash_pool(c->hash), id);
155  elem->nvalues = 1;
156  }
157 
158  /* now, turn the nad into a config hash */
159  path = NULL;
160  len = 0, end = 0;
161  /* start at 1, so we skip the root element */
162  for(i = 1; i < bd.nad->ecur && rv == 0; i++)
163  {
164  /* make sure we have enough room to add this element to our path */
165  if(end <= bd.nad->elems[i].depth)
166  {
167  end = bd.nad->elems[i].depth + 1;
168  path = (struct nad_elem_st **) realloc((void *) path, sizeof(struct nad_elem_st *) * end);
169  }
170 
171  /* save this path element */
172  path[bd.nad->elems[i].depth] = &bd.nad->elems[i];
173  len = bd.nad->elems[i].depth + 1;
174 
175  /* construct the key from the current path */
176  next = buf;
177  for(j = 1; j < len; j++)
178  {
179  strncpy(next, bd.nad->cdata + path[j]->iname, path[j]->lname);
180  next = next + path[j]->lname;
181  *next = '.';
182  next++;
183  }
184  next--;
185  *next = '\0';
186 
187  /* find the config element for this key */
188  elem = xhash_get(c->hash, buf);
189  if(elem == NULL)
190  {
191  /* haven't seen it before, so create it */
192  elem = pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st));
193  xhash_put(c->hash, pstrdup(xhash_pool(c->hash), buf), elem);
194  }
195 
196  /* make room for this value .. can't easily realloc off a pool, so
197  * we do it this way and let _config_reaper clean up */
198  elem->values = realloc((void *) elem->values, sizeof(char *) * (elem->nvalues + 1));
199 
200  /* and copy it in */
201  if(NAD_CDATA_L(bd.nad, i) > 0) {
202  // Expand values
203 
204  const char *val = _config_expandx(c, NAD_CDATA(bd.nad, i), NAD_CDATA_L(bd.nad, i));
205 
206  if (!val) {
207  rv = 1;
208  break;
209  }
210  // Make a copy
211  elem->values[elem->nvalues] = val;
212  } else {
213  elem->values[elem->nvalues] = "1";
214  }
215 
216  /* make room for the attribute lists */
217  elem->attrs = realloc((void *) elem->attrs, sizeof(char **) * (elem->nvalues + 1));
218  elem->attrs[elem->nvalues] = NULL;
219 
220  /* count the attributes */
221  for(attr = bd.nad->elems[i].attr, j = 0; attr >= 0; attr = bd.nad->attrs[attr].next, j++);
222 
223  /* make space */
224  elem->attrs[elem->nvalues] = pmalloc(xhash_pool(c->hash), sizeof(char *) * (j * 2 + 2));
225 
226  /* if we have some */
227  if(j > 0)
228  {
229  /* copy them in */
230  j = 0;
231  attr = bd.nad->elems[i].attr;
232  while(attr >= 0)
233  {
234  elem->attrs[elem->nvalues][j] = pstrdupx(xhash_pool(c->hash), NAD_ANAME(bd.nad, attr), NAD_ANAME_L(bd.nad, attr));
235  elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr));
236 
237  /*
238  * pstrdupx(blob, 0) returns NULL - which means that later
239  * there's no way of telling whether an attribute is defined
240  * as empty, or just not defined. This fixes that by creating
241  * an empty string for attributes which are defined empty
242  */
243  if (NAD_AVAL_L(bd.nad, attr)==0) {
244  elem->attrs[elem->nvalues][j + 1] = pstrdup(xhash_pool(c->hash), "");
245  } else {
246  elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr));
247  }
248  j += 2;
249  attr = bd.nad->attrs[attr].next;
250  }
251  }
252 
253  /* do this and we can use j_attr */
254  elem->attrs[elem->nvalues][j] = NULL;
255  elem->attrs[elem->nvalues][j + 1] = NULL;
256 
257  elem->nvalues++;
258  }
259 
260  if(path != NULL)
261  free(path);
262 
263  if(c->nad != NULL)
264  nad_free(c->nad);
265  c->nad = bd.nad;
266 
267  return rv;
268 }
269 
271 config_elem_t config_get(config_t c, const char *key)
272 {
273  return xhash_get(c->hash, key);
274 }
275 
277 const char *config_get_one(config_t c, const char* key, int num)
278 {
279  config_elem_t elem = xhash_get(c->hash, key);
280 
281  if(elem == NULL)
282  return NULL;
283 
284  if(num >= elem->nvalues)
285  return NULL;
286 
287  return elem->values[num];
288 }
289 
291 const char *config_get_one_default(config_t c, const char *key, int num, const char *default_value)
292 {
293  const char *rv = config_get_one(c, key, num);
294 
295  if (!rv)
296  rv = default_value;
297 
298  return rv;
299 };
300 
301 
303 int config_count(config_t c, const char *key)
304 {
305  config_elem_t elem = xhash_get(c->hash, key);
306 
307  if(elem == NULL)
308  return 0;
309 
310  return elem->nvalues;
311 }
312 
314 char *config_get_attr(config_t c, const char *key, int num, const char *attr)
315 {
316  config_elem_t elem = xhash_get(c->hash, key);
317 
318  if(num >= elem->nvalues || elem->attrs == NULL || elem->attrs[num] == NULL)
319  return NULL;
320 
321  return j_attr((const char **) elem->attrs[num], attr);
322 }
323 
325 static void _config_reaper(const char *key, int keylen, void *val, void *arg)
326 {
327  config_elem_t elem = (config_elem_t) val;
328 
329  free(elem->values);
330  free(elem->attrs);
331 }
332 
333 char *config_expand(config_t c, const char *value)
334 {
335  return _config_expandx(c, value, strlen(value));
336 }
337 
338 static char *_config_expandx(config_t c, const char *value, int l)
339 {
340 #ifdef CONFIGEXPAND_GUARDED
341  static char guard[] = "deadbeaf";
342 #endif
343 
344 // fprintf(stderr, "config_expand: Expanding '%s'\n", value);
345  char *s = strndup(value, l);
346 
347  char *var_start, *var_end;
348 
349  while ((var_start = strstr(s, "${")) != 0) {
350 // fprintf(stderr, "config_expand: processing '%s'\n", s);
351  var_end = strstr(var_start + 2, "}");
352 
353  if (var_end) {
354  char *tail = var_end + 1;
355  char *var = var_start + 2;
356  *var_end = 0;
357 
358 // fprintf(stderr, "config_expand: Var '%s', tail is '%s'\n", var, tail);
359 
360  const char *var_value = config_get_one(c, var, 0);
361 
362  if (var_value) {
363  int len = (var_start - s) + strlen(tail) + strlen(var_value) + 1;
364 
365 #ifdef CONFIGEXPAND_GUARDED
366  len += sizeof(guard);
367 #endif
368  char *expanded_str = calloc(len, 1);
369 
370 #ifdef CONFIGEXPAND_GUARDED
371  char *p_guard = expanded_str + len - sizeof(guard);
372  strncpy(p_guard, guard, sizeof(guard));
373 #endif
374 
375  char *p = expanded_str;
376  strncpy(expanded_str, s, var_start - s);
377  p += var_start - s;
378 
379  strcpy(p, var_value);
380  p += strlen(var_value);
381 
382  strcpy(p, tail);
383 
384  free(s);
385  s = expanded_str;
386  } else {
387  fprintf(stderr, "config_expand: Have no '%s' defined\n", var);
388  free(s);
389  s = 0;
390  break;
391  }
392  } else {
393  fprintf(stderr, "config_expand: } missmatch\n");
394  free(s);
395  s = 0;
396  break;
397  }
398  }
399 
400  if (s) {
401  char *retval = pstrdup(xhash_pool(c->hash), s);
402  free(s);
403  return retval;
404  } else {
405  return 0;
406  }
407 }
408 
411 {
412  xhash_walk(c->hash, _config_reaper, NULL);
413 
414  xhash_free(c->hash);
415 
416  nad_free(c->nad);
417 
418  free(c);
419 }
int attr
Definition: nad.h:74
struct nad_elem_st * elems
Definition: nad.h:95
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:701
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:410
void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
append new cdata to the last elem
Definition: nad.c:709
config_t config_new(void)
new config structure
Definition: config.c:25
int next
Definition: nad.h:84
struct nad_attr_st * attrs
Definition: nad.h:96
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:667
void nad_free(nad_t nad)
free that nad
Definition: nad.c:178
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:314
static void _config_reaper(const char *key, int keylen, void *val, void *arg)
cleanup helper
Definition: config.c:325
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:1269
int ecur
Definition: nad.h:105
#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:338
config_elem_t config_get(config_t c, const char *key)
get the config element for this key
Definition: config.c:271
char * cdata
Definition: nad.h:98
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:333
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
Definition: config.c:277
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:303
int nvalues
Definition: util.h:210
int depth
Definition: nad.h:77
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:291
parse a buffer into a nad
Definition: config.c:36
int iname
Definition: nad.h:71