solaris-fixes branch: Applied the swap-patch by Christophe Kalt.
[collectd.git] / src / libconfig / conf_apache.c
1 #include "compat.h"
2 #include "libconfig.h"
3 #include "libconfig_private.h"
4 #include "conf_apache.h"
5
6 #ifdef HAVE_CTYPE_H
7 #include <ctype.h>
8 #endif
9
10 #ifdef HAVE_STDIO_H
11 #include <stdio.h>
12 #endif
13
14 #ifdef HAVE_STRING_H
15 #include <string.h>
16 #endif
17
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21
22 #ifdef HAVE_SYS_STAT_H
23 #include <sys/stat.h>
24 #endif
25
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 #ifdef HAVE_DIRENT_H
31 #include <dirent.h>
32 #endif
33
34 static int lc_process_conf_apache_file(const char *configfile, const char *pathprefix);
35
36 static int lc_process_conf_apache_include(const char *pathname, const char *pathprefix) {
37         struct stat pathinfo;
38         struct dirent *dinfo = NULL;
39         char includepath[LC_LINEBUF_LEN] = {0};
40         DIR *dh = NULL;
41         int statret = -1, lcpcafret = -1;
42         int retval = 0;
43
44         statret = stat(pathname, &pathinfo);
45         if (statret < 0) {
46                 return(-1);
47         }
48
49         if (S_ISDIR(pathinfo.st_mode)) {
50                 dh = opendir(pathname);
51                 if (dh == NULL) {
52                         return(-1);
53                 }
54
55                 while (1) {
56                         dinfo = readdir(dh);
57                         if (dinfo == NULL) {
58                                 break;
59                         }
60
61                         /* Skip files that begin with a dot ('.') */
62                         if (dinfo->d_name[0] == '.') continue;
63
64                         snprintf(includepath, sizeof(includepath) - 1, "%s/%s", pathname, dinfo->d_name);
65                         lcpcafret = lc_process_conf_apache_include(includepath, pathprefix);
66                         if (lcpcafret < 0) {
67                                 retval = -1;
68                                 /* XXX: should we break here (abort further including of files from a directory if one fails ?) */
69                         }
70                 }
71
72                 closedir(dh);
73         } else {
74                 lcpcafret = lc_process_conf_apache_file(pathname, pathprefix);
75                 if (lcpcafret < 0) {
76                         retval = -1;
77                 }
78         }
79
80         return(retval);
81 }
82
83 static int lc_process_conf_apache_file(const char *configfile, const char *pathprefix) {
84         LC_FILE *configfp = NULL;
85         const char *local_lc_errfile;
86         char linebuf[LC_LINEBUF_LEN] = {0}, *linebuf_ptr = NULL, *tmp_ptr = NULL;
87         char *lastsection = NULL;
88         char qualifbuf[LC_LINEBUF_LEN] = {0};
89         char *cmd = NULL, *value = NULL, *sep = NULL, *cmdend = NULL;
90         char *fgetsret = NULL;
91         int lcpvret = -1, lpcafret = -1;
92         int invalid_section = 0, ignore_section = 0;
93         int local_lc_errline;
94         int retval = 0;
95         lc_err_t save_lc_errno = LC_ERR_NONE;
96
97         if (pathprefix != NULL) {
98                 /* Copy the prefix, if specified. */
99                 strncpy(qualifbuf, pathprefix, sizeof(qualifbuf) - 1);
100         }
101
102         local_lc_errfile = configfile;
103         local_lc_errline = 0;
104
105         if (configfile == NULL) {
106                 lc_errfile = local_lc_errfile;
107                 lc_errline = local_lc_errline;
108                 lc_errno = LC_ERR_INVDATA;
109                 return(-1);
110         }
111
112         configfp = lc_fopen(configfile, "r");
113
114         if (configfp == NULL) {
115                 lc_errfile = local_lc_errfile;
116                 lc_errline = local_lc_errline;
117                 lc_errno = LC_ERR_CANTOPEN;
118                 return(-1);
119         }
120
121         while (1) {
122                 fgetsret = lc_fgets(linebuf, sizeof(linebuf) - 1, configfp);
123                 if (fgetsret == NULL) {
124                         break;
125                 }
126                 if (lc_feof(configfp)) {
127                         break;
128                 }
129
130                 local_lc_errline++;
131
132                 /* Remove trailing crap (but not spaces). */
133                 linebuf_ptr = &linebuf[strlen(linebuf) - 1];
134                 while (*linebuf_ptr < ' ' && linebuf_ptr >= linebuf) {
135                         *linebuf_ptr = '\0';
136                         linebuf_ptr--;
137                 }
138
139                 /* Remove leading spaces. */
140                 linebuf_ptr = &linebuf[0];
141                 while (*linebuf_ptr == ' ' || *linebuf_ptr == '\t') {
142                         linebuf_ptr++;
143                 }
144
145                 /* Handle section header. */
146                 if (linebuf_ptr[0] == '<' && linebuf_ptr[strlen(linebuf_ptr) - 1] == '>') {
147                         /* Remove < and > from around the data. */
148                         linebuf_ptr[strlen(linebuf_ptr) - 1] = '\0';
149                         linebuf_ptr++;
150
151                         /* Lowercase the command part of the section. */
152                         tmp_ptr = linebuf_ptr;
153                         while (*tmp_ptr != '\0' && *tmp_ptr != ' ') {
154                                 *tmp_ptr = tolower(*tmp_ptr);
155                                 tmp_ptr++;
156                         }
157
158                         /* If this is a close section command, handle it */
159                         if (linebuf_ptr[0] == '/') {
160                                 linebuf_ptr++;
161                                 cmd = linebuf_ptr; 
162
163                                 /* Find the last section closed. */
164                                 tmp_ptr = strrchr(qualifbuf, '.');
165                                 if (tmp_ptr == NULL) {
166                                         lastsection = qualifbuf;
167                                         tmp_ptr = qualifbuf;
168                                 } else {
169                                         lastsection = tmp_ptr + 1;
170                                 }
171
172                                 if (strcmp(cmd, lastsection) != 0) {
173 #ifdef DEBUG
174                                         fprintf(stderr, "Section closing does not match last opened section.\n");
175                                         fprintf(stderr, "Last opened = \"%s\", Closing = \"%s\"\n", lastsection, cmd);
176 #endif
177                                         retval = -1;
178                                         lc_errfile = local_lc_errfile;
179                                         lc_errline = local_lc_errline;
180                                         lc_errno = LC_ERR_BADFORMAT;
181
182                                         /* For this error, we abort immediately. */
183                                         break;
184                                 }
185
186                                 lcpvret = lc_process_var(qualifbuf, NULL, NULL, LC_FLAGS_SECTIONEND);
187                                 if (lcpvret < 0) {
188 #ifdef DEBUG
189                                         fprintf(stderr, "Invalid section terminating: \"%s\"\n", qualifbuf);
190 #endif
191                                 }
192
193                                 /* Remove the "lastsection" part.. */
194                                 *tmp_ptr = '\0';
195
196                                 /* We just sucessfully closed the last section opened,
197                                    we must be in a valid section now since we only open
198                                    sections from within valid sections. */
199                                 invalid_section = 0;
200                                 ignore_section = 0;
201
202                                 continue;
203                         }
204                         /* Otherwise, open a new section. */
205
206                         /* Don't open a section from an invalid section. */
207                         if (invalid_section == 1 || ignore_section == 1) {
208                                 continue;
209                         }
210
211                         /* Parse out any argument passed. */
212                         sep = strpbrk(linebuf_ptr, " \t");
213
214                         if (sep != NULL) {
215                                 cmdend = sep;
216                                 /* Delete space at the end of the command. */
217                                 cmdend--; /* It currently derefs to the seperator.. */
218                                 while (*cmdend <= ' ') {
219                                         *cmdend = '\0';
220                                         cmdend--;
221                                 }
222
223                                 /* Delete the seperator char and any leading space. */
224                                 *sep = '\0';
225                                 sep++;
226                                 while (*sep == ' ' || *sep == '\t') {
227                                         sep++;
228                                 }
229                                 value = sep;
230                         } else {
231                                 /* XXX: should this be "" or NULL ? */
232                                 value = "";
233                         }
234
235                         cmd = linebuf_ptr;
236
237                         if (qualifbuf[0] != '\0') {
238                                 strncat(qualifbuf, ".", sizeof(qualifbuf) - strlen(qualifbuf) - 1);
239                         }
240                         strncat(qualifbuf, cmd, sizeof(qualifbuf) - strlen(qualifbuf) - 1);
241
242                         lcpvret = lc_process_var(qualifbuf, value, NULL, LC_FLAGS_SECTIONSTART);
243                         if (lcpvret < 0) {
244 #ifdef DEBUG
245                                 fprintf(stderr, "Invalid section: \"%s\"\n", qualifbuf);
246 #endif
247                                 invalid_section = 1;
248                                 lc_errfile = local_lc_errfile;
249                                 lc_errline = local_lc_errline;
250                                 lc_errno = LC_ERR_INVSECTION;
251                                 retval = -1;
252                         }
253                         if (lcpvret == LC_CBRET_IGNORESECTION) {
254                                 ignore_section = 1;
255                         }
256                         continue;
257                 }
258
259                 /* Drop comments and blank lines. */
260                 if (*linebuf_ptr == '#' || *linebuf_ptr == '\0') {
261                         continue;
262                 }
263
264                 /* Don't handle things for a section that doesn't exist. */
265                 if (invalid_section == 1) {
266 #ifdef DEBUG
267                         fprintf(stderr, "Ignoring line (because invalid section): %s\n", linebuf);
268 #endif
269                         continue;
270                 }
271                 if (ignore_section == 1) {
272 #ifdef DEBUG
273                         fprintf(stderr, "Ignoring line (because ignored section): %s\n", linebuf);
274 #endif
275                         continue;
276                 }
277
278                 /* Find the command and the data in the line. */
279                 sep = strpbrk(linebuf_ptr, " \t");
280                 if (sep != NULL) {
281                         cmdend = sep;
282
283                         /* Delete space at the end of the command. */
284                         cmdend--; /* It currently derefs to the seperator.. */
285                         while (*cmdend <= ' ') {
286                                 *cmdend = '\0';
287                                 cmdend--;
288                         }
289
290                         /* Delete the seperator char and any leading space. */
291                         *sep = '\0';
292                         sep++;
293                         while (*sep == ' ' || *sep == '\t') {
294                                 sep++;
295                         }
296                         value = sep;
297                 } else {
298                         value = NULL;
299                 }
300
301                 cmd = linebuf_ptr;
302
303                 /* Handle special commands. */
304                 if (strcasecmp(cmd, "include") == 0) {
305                         if (value == NULL) {
306                                 lc_errfile = local_lc_errfile;
307                                 lc_errline = local_lc_errline;
308                                 lc_errno = LC_ERR_BADFORMAT;
309                                 retval = -1;
310 #ifdef DEBUG
311                                 fprintf(stderr, "Invalid include command.\n");
312 #endif
313                                 continue;
314                         }
315
316                         lpcafret = lc_process_conf_apache_include(value, qualifbuf);
317                         if (lpcafret < 0) {
318 #ifdef DEBUG
319                                 fprintf(stderr, "Error in included file.\n");
320 #endif
321                                 retval = -1;
322                         }
323                         continue;
324                 }
325
326                 /* Create the fully qualified variable name. */
327                 if (qualifbuf[0] != '\0') {
328                         strncat(qualifbuf, ".", sizeof(qualifbuf) - strlen(qualifbuf) - 1);
329                 }
330                 strncat(qualifbuf, cmd, sizeof(qualifbuf) - strlen(qualifbuf) - 1);
331
332                 /* Call the parent and tell them we have data. */
333                 save_lc_errno = lc_errno;
334                 lc_errno = LC_ERR_NONE;
335                 lcpvret = lc_process_var(qualifbuf, NULL, value, LC_FLAGS_VAR);
336                 if (lcpvret < 0) {
337                         if (lc_errno == LC_ERR_NONE) {
338 #ifdef DEBUG
339                                 fprintf(stderr, "Invalid command: \"%s\"\n", cmd);
340 #endif
341                                 lc_errfile = local_lc_errfile;
342                                 lc_errline = local_lc_errline;
343                                 lc_errno = LC_ERR_INVCMD;
344                         } else {
345 #ifdef DEBUG
346                                 fprintf(stderr, "Error processing command (command was valid, but an error occured, errno was set)\n");
347 #endif
348                         }
349                         lc_errfile = local_lc_errfile;
350                         lc_errline = local_lc_errline;
351                         retval = -1;
352                 } else {
353                         lc_errno = save_lc_errno;
354                 }
355
356                 /* Remove the "cmd" part of the buffer. */
357                 tmp_ptr = strrchr(qualifbuf, '.');
358                 if (tmp_ptr == NULL) {
359                         tmp_ptr = qualifbuf;
360                 }
361                 *tmp_ptr = '\0';
362         }
363
364         lc_fclose(configfp);
365
366         return(retval);
367 }
368
369 int lc_process_conf_apache(const char *appname, const char *configfile) {
370         return(lc_process_conf_apache_file(configfile, NULL));
371 }