1 /* Configuration file parsing.
2 * - by Richard W.M. Jones <rich@annexia.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * $Id: cfg.c,v 1.11 2002/10/15 21:28:32 rich Exp $
26 #ifdef HAVE_SYS_TYPES_H
27 #include <sys/types.h>
55 /* Aliases -- these are only present in the host-specific configuration
56 * files, not in CFG_MAIN.
58 shash aliases; /* Hash of string -> struct alias_data * */
66 static pool cfg_pool = 0;
67 static shash cfg_hosts; /* Hash of string -> struct config_data * */
68 static struct config_data *cfg_main;
70 static struct config_data *read_config (FILE *fp, int is_main, const char *filename);
71 static void config_err (const char *filename, const char *line, const char *msg);
73 /* The PATH argument will point to the base for configuration
74 * files, eg. "/etc/rws". We append "/rws.conf" to get the main
75 * configuration file and "/hosts/" to get the virtual hosts
79 cfg_reread_config (const char *path)
81 const char *config_file;
82 const char *hosts_dir;
88 /* Show the message about reloading the configuration file, but only
89 * the second and subsequent times this function is run.
92 fprintf (stderr, "reloading configuration file ...\n");
94 /* Remove any configuration data from previous configuration run. */
95 if (cfg_pool) delete_pool (cfg_pool);
97 /* Create new data structures. */
98 cfg_pool = new_subpool (global_pool);
99 tmp = new_subpool (cfg_pool);
100 cfg_hosts = new_shash (cfg_pool, struct config_data *);
102 config_file = psprintf (tmp, "%s/rws.conf", path);
103 hosts_dir = psprintf (tmp, "%s/hosts/", path);
105 /* Read in main configuration file. */
106 fp = fopen (config_file, "r");
107 if (fp == 0) { perror (config_file); exit (1); }
108 cfg_main = read_config (fp, 1, config_file);
111 /* Read in each virtual host configuration file. */
112 dir = opendir (hosts_dir);
115 while ((d = readdir (dir)) != 0)
117 struct config_data *c;
119 if (d->d_name[0] != '.') /* Ignore ".", ".." and dotfiles. */
123 p = psprintf (tmp, "%s/%s", hosts_dir, d->d_name);
126 if (fp == 0) { perror (p); exit (1); }
127 c = read_config (fp, 0, p);
130 shash_insert (cfg_hosts, d->d_name, c);
140 /* Read in a config file from FP. */
141 static struct config_data *
142 read_config (FILE *fp, int is_main, const char *filename)
144 pool tmp = new_subpool (cfg_pool);
146 struct config_data *c;
147 struct alias_data *a = 0;
149 c = pmalloc (cfg_pool, sizeof *c);
150 c->data = new_sash (cfg_pool);
151 if (!is_main) c->aliases = new_shash (cfg_pool, struct alias_data *);
154 while ((line = pgetlinec (tmp, fp, line)))
158 if (!is_main && (v = prematch (tmp, line, re_alias_start, 0)))
160 const char *aliasname;
162 if (a) config_err (filename, line, "nested alias");
164 vector_get (v, 1, aliasname);
166 a = pmalloc (cfg_pool, sizeof *a);
167 a->data = new_sash (cfg_pool);
169 if (shash_insert (c->aliases, aliasname, a))
170 config_err (filename, line, "duplicate alias");
172 else if (!is_main && prematch (tmp, line, re_alias_end, 0))
175 config_err (filename, line,
176 "end alias found, but not inside an alias definition");
180 else if ((v = prematch (tmp, line, re_begin, 0)))
183 char *value, *end_line;
186 vector_get (v, 1, key);
188 /* Read the data lines until we get to 'end key' line. */
189 value = pstrdup (tmp, "");
190 end_line = psprintf (tmp, "end %s", key);
191 while ((line = pgetlinec (tmp, fp, line)))
193 if (strcmp (line, end_line) == 0)
196 value = pstrcat (tmp, value, line);
197 value = pstrcat (tmp, value, "\n");
201 config_err (filename, "EOF", "missing end <key> line");
206 if (sash_insert (s, key, value))
207 config_err (filename, line, "duplicate definition");
209 else if ((v = prematch (tmp, line, re_conf_line, 0)))
211 const char *key, *value;
214 vector_get (v, 1, key);
215 vector_get (v, 2, value);
217 /* 'key:' means define key as the empty string (as opposed to
218 * commenting it out which leaves 'key' undefined).
220 if (value == 0) value = "";
225 if (sash_insert (s, key, value))
226 config_err (filename, line, "duplicate definition");
229 config_err (filename, line, "unexpected line");
238 config_err (const char *filename, const char *line, const char *msg)
242 "rws: near ``%s''\n",
249 cfg_get_host (const char *host)
251 struct config_data *c = 0;
253 shash_get (cfg_hosts, host, c);
258 cfg_get_alias (void *host_ptr, const char *path)
260 struct config_data *c = (struct config_data *) host_ptr;
261 struct alias_data *a = 0;
263 shash_get (c->aliases, path, a);
268 cfg_get_string (void *host_ptr, void *alias_ptr,
269 const char *key, const char *default_value)
271 struct config_data *c = (struct config_data *) host_ptr;
272 struct alias_data *a = (struct alias_data *) alias_ptr;
275 if (a && sash_get (a->data, key, value))
277 if (c && sash_get (c->data, key, value))
279 if (sash_get (cfg_main->data, key, value))
282 return default_value;
286 cfg_get_int (void *host_ptr, void *alias_ptr, const char *key, int default_value)
288 const char *value = cfg_get_string (host_ptr, alias_ptr, key, 0);
291 if (!value) return default_value;
293 if (sscanf (value, "%d", &r) != 1) return default_value;
299 cfg_get_bool (void *host_ptr, void *alias_ptr, const char *key, int default_value)
301 const char *value = cfg_get_string (host_ptr, alias_ptr, key, 0);
303 if (!value) return default_value;
305 if (value[0] == '0' ||
306 value[0] == 'f' || value[0] == 'F' ||
307 value[0] == 'n' || value[0] == 'N' ||
308 (value[0] == 'o' && value[1] == 'f') ||
309 (value[0] == 'O' && value[1] == 'F'))
311 else if (value[0] == '1' ||
312 value[0] == 't' || value[0] == 'T' ||
313 value[0] == 'y' || value[0] == 'Y' ||
314 (value[0] == 'o' && value[1] == 'n') ||
315 (value[0] == 'O' && value[1] == 'N'))
318 return default_value;