squid.conf is getting pretty large. for people who operate several caches
it is quite timeconsuming to modify each squid.conf file when some change
is made that should be shared by all boxes. I've felt several times that
it would be nice to be able to include other config files from the main
squid.conf. For eg. refresh rules, acl's, or other settings common to all
boxes like timeouts, hierarchy peerings, etc. This way I could put only
host-specific stuff in main config file and the rest could be copied
around without fear of typos.
Here below is a patch to implement a special TAG: "include: /path/to/config"
It splits parseConfigFile() into main startup func and recursive parser.
I implemented it as a recursive procedure. I wonder if this is very bad
style in Squid? I believe its pretty safe, but recursion has never been
used in squid.
This patch works, but is not fully tested. Take at it as a concept patch.
I'm not sure if I can forsee all possible unwanted sideeffects. Please
review and comment on it.
Patch adds a list of inodes where it keeps track of which config files
have been seen. This is to avoid possible infinite include recursion.
To think about it, maybe there's point in adding 2 differing tags for
inclusion, one for required files and other for wanted but not fatal
if not present files. It would be possible to place cache_dir specific
configuration into cache_dir itself (thinking of future hotplugging of
cache_dir disks)
patch is against 2.3-hno@cvs
--- cache_cf.c.orig Wed Aug 30 21:42:29 2000
+++ cache_cf.c Wed Sep 6 13:22:57 2000
@@ -171,18 +171,60 @@
return i;
}
+typedef struct _cfg_tree cfg_tree_node;
+struct _cfg_tree { /* XXX: saves inodes of config files ever seen */
+ ino_t cfg_inode;
+ cfg_tree_node *next;
+};
+cfg_tree_node *cfg_tree = NULL;
+
+static void
+free_cfg_tree(cfg_tree_node ** head)
+{
+ cfg_tree_node *p;
+ while ((p = *head) != NULL) {
+ *head = p->next;
+ safe_free(p);
+ }
+}
+
+int err_count = 0; /* XXX need it as global now */
+
+/* NB! This procedure is recursive, for includes. Keep in mind when modifying */
int
-parseConfigFile(const char *file_name)
+do_parseConfigFile(const char *file_name)
{
FILE *fp = NULL;
+ size_t toklen;
char *token = NULL;
char *tmp_line;
- int err_count = 0;
- free_all();
- default_all();
+ char *my_file_name;
+ char *my_cfg_filename = NULL;
+ char *my_config_input_line = NULL;
+ int my_config_lineno;
+ struct stat sb;
+ cfg_tree_node *head;
+
+ if ((stat(file_name, &sb)) < 0)
+ fatalf("Unable to stat configuration file: %s: %s",
+ file_name, xstrerror());
+
+ head=cfg_tree;
+ while (head != NULL) {
+ if (sb.st_ino==head->cfg_inode)
+ fatalf("Recursive includes in configuration file: %s:%d: '%s'",
+ cfg_filename, config_lineno, config_input_line);
+ head = head->next;
+ }
+ head=xmalloc(sizeof(cfg_tree_node));
+ head->cfg_inode=sb.st_ino;
+ head->next=cfg_tree;
+ cfg_tree = head;
+
if ((fp = fopen(file_name, "r")) == NULL)
fatalf("Unable to open configuration file: %s: %s",
file_name, xstrerror());
+ debug(3, 2) ("do_parseConfigFile: Processing file: '%s'\n", cfg_filename);
cfg_filename = file_name;
if ((token = strrchr(cfg_filename, '/')))
cfg_filename = token + 1;
@@ -198,9 +240,46 @@
if (config_input_line[0] == '\0')
continue;
debug(3, 5) ("Processing: '%s'\n", config_input_line);
+
+ /* XXX can't use strtok here, because of recursive calls */
+ token = config_input_line;
+ token += strspn(token, w_space);
+ toklen = strcspn(token, w_space);
+ if (!toklen)
+ continue;
+ /* Get include filename */
+ if (!strncmp(token,"include:",toklen)) {
+ token+=toklen;
+ token += strspn(token, w_space);
+ toklen = strcspn(token, w_space);
+ if(toklen<1) {
+ debug(3, 0) ("do_parseConfigFile: %s line %d unrecognized: '%s'\n",
+ cfg_filename,
+ config_lineno,
+ config_input_line);
+ err_count++;
+ continue;
+ }
+ token[toklen] = '\0';
+
+ /* Save current file state on stack */
+ my_cfg_filename=cfg_filename;
+ my_config_lineno=config_lineno;
+ my_file_name=xstrdup(token);
+
+ do_parseConfigFile(my_file_name);
+
+ /* Restore current file state from stack */
+ cfg_filename=my_cfg_filename;
+ config_lineno=my_config_lineno;
+ safe_free(my_file_name);
+
+ continue;
+ }
tmp_line = xstrdup(config_input_line);
if (!parse_line(tmp_line)) {
- debug(3, 0) ("parseConfigFile: line %d unrecognized: '%s'\n",
+ debug(3, 0) ("do_parseConfigFile: %s line %d unrecognized: '%s'\n",
+ cfg_filename,
config_lineno,
config_input_line);
err_count++;
@@ -208,6 +287,16 @@
safe_free(tmp_line);
}
fclose(fp);
+}
+
+int
+parseConfigFile(const char *file_name)
+{
+ free_all();
+ default_all();
+ free_cfg_tree(&cfg_tree);
+ http_header_first = 0;
+ do_parseConfigFile(file_name);
defaults_if_none();
configDoConfigure();
cachemgrRegister("config",
------------------------------------
Andres Kroonmaa <andre@online.ee>
Delfi Online
Tel: 6501 731, Fax: 6501 708
Pärnu mnt. 158, Tallinn,
11317 Estonia
Received on Thu Sep 07 2000 - 07:14:56 MDT
This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:12:36 MST