squid.conf and include files

From: Andres Kroonmaa <andre@dont-contact.us>
Date: Thu, 7 Sep 2000 15:11:39 +0200

 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