2003-03-28 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / bus / config-parser.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* config-parser.c  XML-library-agnostic configuration file parser
3  *
4  * Copyright (C) 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "config-parser.h"
24 #include "test.h"
25 #include <dbus/dbus-list.h>
26 #include <dbus/dbus-internals.h>
27 #include <string.h>
28
29 typedef enum
30 {
31   ELEMENT_BUSCONFIG,
32   ELEMENT_INCLUDE,
33   ELEMENT_USER,
34   ELEMENT_LISTEN,
35   ELEMENT_AUTH,
36   ELEMENT_POLICY,
37   ELEMENT_LIMIT
38 } ElementType;
39
40 typedef struct
41 {
42   ElementType type;
43
44   union
45   {
46     struct
47     {
48       BusConfigParser *parser;
49     } include;
50
51     struct
52     {
53       char *username;
54     } user;
55
56     struct
57     {
58       char *address;
59     } listen;
60
61     struct
62     {
63       char *mechanism;
64     } auth;
65
66     struct
67     {
68       char *context;
69       char *user;
70       char *group;
71       DBusList *rules;
72     } policy;
73
74     struct
75     {
76       int foo;
77     } limit;
78     
79   } d;
80   
81 } Element;
82
83 struct BusConfigParser
84 {
85   int refcount;
86
87   DBusList *stack; /**< stack of Element */
88
89   char *user;      /**< user to run as */
90 };
91
92
93 static Element*
94 push_element (BusConfigParser *parser,
95               ElementType      type)
96 {
97   Element *e;
98
99   e = dbus_new0 (Element, 1);
100   if (e == NULL)
101     return NULL;
102   
103   e->type = type;
104
105   return e;
106 }
107
108 static void
109 pop_element (BusConfigParser *parser)
110 {
111   Element *e;
112
113   e = _dbus_list_pop_last (&parser->stack);
114
115   dbus_free (e);
116 }
117
118 BusConfigParser*
119 bus_config_parser_new (void)
120 {
121   BusConfigParser *parser;
122
123   parser = dbus_new0 (BusConfigParser, 1);
124   if (parser == NULL)
125     return NULL;
126
127   parser->refcount = 1;
128
129   return parser;
130 }
131
132 void
133 bus_config_parser_ref (BusConfigParser *parser)
134 {
135   _dbus_assert (parser->refcount > 0);
136
137   parser->refcount += 1;
138 }
139
140 void
141 bus_config_parser_unref (BusConfigParser *parser)
142 {
143   _dbus_assert (parser->refcount > 0);
144
145   parser->refcount -= 1;
146
147   if (parser->refcount == 0)
148     {
149       while (parser->stack != NULL)
150         pop_element (parser);
151       
152       dbus_free (parser->user);
153
154       dbus_free (parser);
155     }
156 }
157
158 dbus_bool_t
159 bus_config_parser_check_doctype (BusConfigParser   *parser,
160                                  const char        *doctype,
161                                  DBusError         *error)
162 {
163   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
164   
165   if (strcmp (doctype, "busconfig") != 0)
166     {
167       dbus_set_error (error,
168                       DBUS_ERROR_FAILED,
169                       "Document has the wrong type %s",
170                       doctype);
171       return FALSE;
172     }
173   else
174     return TRUE;
175 }
176
177 dbus_bool_t
178 bus_config_parser_start_element (BusConfigParser   *parser,
179                                  const char        *element_name,
180                                  const char       **attribute_names,
181                                  const char       **attribute_values,
182                                  DBusError         *error)
183 {
184   _DBUS_ASSERT_ERROR_IS_CLEAR (error);  
185
186   return TRUE;
187 }
188
189 dbus_bool_t
190 bus_config_parser_end_element (BusConfigParser   *parser,
191                                const char        *element_name,
192                                DBusError         *error)
193 {
194   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
195
196   return TRUE;
197 }
198
199 dbus_bool_t
200 bus_config_parser_content (BusConfigParser   *parser,
201                            const DBusString  *content,
202                            DBusError         *error)
203 {
204   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
205
206   return TRUE;
207 }
208
209 dbus_bool_t
210 bus_config_parser_finished (BusConfigParser   *parser,
211                             DBusError         *error)
212 {
213   _DBUS_ASSERT_ERROR_IS_CLEAR (error);  
214
215   return TRUE;
216 }
217
218 const char*
219 bus_config_parser_get_user (BusConfigParser *parser)
220 {
221
222
223   return NULL;
224 }
225
226 #ifdef DBUS_BUILD_TESTS
227 #include <stdio.h>
228
229 typedef enum
230 {
231   VALID,
232   INVALID,
233   UNKNOWN
234 } Validity;
235
236 static dbus_bool_t
237 do_load (const DBusString *full_path,
238          Validity          validity,
239          dbus_bool_t       oom_possible)
240 {
241   BusConfigParser *parser;
242   DBusError error;
243
244   dbus_error_init (&error);
245   
246   parser = bus_config_load (full_path, &error);
247   if (parser == NULL)
248     {
249       _DBUS_ASSERT_ERROR_IS_SET (&error);
250       
251       if (oom_possible &&
252           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
253         {
254           _dbus_verbose ("Failed to load valid file due to OOM\n");
255           dbus_error_free (&error);
256           return TRUE;
257         }
258       else if (validity == VALID)
259         {          
260           _dbus_warn ("Failed to load valid file but still had memory: %s\n",
261                       error.message);
262
263           dbus_error_free (&error);
264           return FALSE;
265         }
266       else
267         {
268           dbus_error_free (&error);
269           return TRUE;
270         }
271     }
272   else
273     {
274       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
275       
276       bus_config_parser_unref (parser);
277       
278       if (validity == INVALID)
279         {
280           _dbus_warn ("Accepted invalid file\n");
281           return FALSE;
282         }
283
284       return TRUE;
285     }
286 }
287
288 typedef struct
289 {
290   const DBusString *full_path;
291   Validity          validity;
292 } LoaderOomData;
293
294 static dbus_bool_t
295 check_loader_oom_func (void *data)
296 {
297   LoaderOomData *d = data;
298
299   return do_load (d->full_path, d->validity, TRUE);
300 }
301
302 static dbus_bool_t
303 process_test_subdir (const DBusString *test_base_dir,
304                      const char       *subdir,
305                      Validity          validity)
306 {
307   DBusString test_directory;
308   DBusString filename;
309   DBusDirIter *dir;
310   dbus_bool_t retval;
311   DBusError error;
312
313   retval = FALSE;
314   dir = NULL;
315   
316   if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
317     _dbus_assert_not_reached ("didn't allocate test_directory\n");
318
319   _dbus_string_init_const (&filename, subdir);
320   
321   if (!_dbus_string_copy (test_base_dir, 0,
322                           &test_directory, 0))
323     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
324   
325   if (!_dbus_concat_dir_and_file (&test_directory, &filename))    
326     _dbus_assert_not_reached ("couldn't allocate full path");
327
328   _dbus_string_free (&filename);
329   if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
330     _dbus_assert_not_reached ("didn't allocate filename string\n");
331
332   dbus_error_init (&error);
333   dir = _dbus_directory_open (&test_directory, &error);
334   if (dir == NULL)
335     {
336       const char *s;
337       _dbus_string_get_const_data (&test_directory, &s);
338       _dbus_warn ("Could not open %s: %s\n", s,
339                   error.message);
340       dbus_error_free (&error);
341       goto failed;
342     }
343
344   printf ("Testing:\n");
345   
346  next:
347   while (_dbus_directory_get_next_file (dir, &filename, &error))
348     {
349       DBusString full_path;
350       LoaderOomData d;
351       
352       if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
353         _dbus_assert_not_reached ("couldn't init string");
354
355       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
356         _dbus_assert_not_reached ("couldn't copy dir to full_path");
357
358       if (!_dbus_concat_dir_and_file (&full_path, &filename))
359         _dbus_assert_not_reached ("couldn't concat file to dir");
360
361       if (!_dbus_string_ends_with_c_str (&full_path, ".conf"))
362         {
363           const char *filename_c;
364           _dbus_string_get_const_data (&filename, &filename_c);
365           _dbus_verbose ("Skipping non-.conf file %s\n",
366                          filename_c);
367           _dbus_string_free (&full_path);
368           goto next;
369         }
370
371       {
372         const char *s;
373         _dbus_string_get_const_data (&filename, &s);
374         printf ("    %s\n", s);
375       }
376       
377       _dbus_verbose (" expecting %s\n",
378                      validity == VALID ? "valid" :
379                      (validity == INVALID ? "invalid" :
380                       (validity == UNKNOWN ? "unknown" : "???")));
381
382       d.full_path = &full_path;
383       d.validity = validity;
384       if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d))
385         _dbus_assert_not_reached ("test failed");
386       
387       _dbus_string_free (&full_path);
388     }
389
390   if (dbus_error_is_set (&error))
391     {
392       const char *s;
393       _dbus_string_get_const_data (&test_directory, &s);
394       _dbus_warn ("Could not get next file in %s: %s\n",
395                   s, error.message);
396       dbus_error_free (&error);
397       goto failed;
398     }
399     
400   retval = TRUE;
401   
402  failed:
403
404   if (dir)
405     _dbus_directory_close (dir);
406   _dbus_string_free (&test_directory);
407   _dbus_string_free (&filename);
408
409   return retval;
410 }
411
412 dbus_bool_t
413 bus_config_parser_test (const DBusString *test_data_dir)
414 {
415   if (test_data_dir == NULL ||
416       _dbus_string_get_length (test_data_dir) == 0)
417     {
418       printf ("No test data\n");
419       return TRUE;
420     }
421   
422   if (!process_test_subdir (test_data_dir, "valid-config-files", VALID))
423     return FALSE;
424   
425   return TRUE;
426 }
427
428 #endif /* DBUS_BUILD_TESTS */
429