1 const char loaders_rcs[] = "$Id: loaders.c,v 1.12 2001/05/31 17:32:31 oes Exp $";
2 /*********************************************************************
4 * File : $Source: /cvsroot/ijbswa/current/loaders.c,v $
6 * Purpose : Functions to load and unload the various
7 * configuration files. Also contains code to manage
8 * the list of active loaders, and to automatically
9 * unload files that are no longer in use.
11 * Copyright : Written by and Copyright (C) 2001 the SourceForge
12 * IJBSWA team. http://ijbswa.sourceforge.net
14 * Based on the Internet Junkbuster originally written
15 * by and Copyright (C) 1997 Anonymous Coders and
16 * Junkbusters Corporation. http://www.junkbusters.com
18 * This program is free software; you can redistribute it
19 * and/or modify it under the terms of the GNU General
20 * Public License as published by the Free Software
21 * Foundation; either version 2 of the License, or (at
22 * your option) any later version.
24 * This program is distributed in the hope that it will
25 * be useful, but WITHOUT ANY WARRANTY; without even the
26 * implied warranty of MERCHANTABILITY or FITNESS FOR A
27 * PARTICULAR PURPOSE. See the GNU General Public
28 * License for more details.
30 * The GNU General Public License should be included with
31 * this file. If not, you can view it at
32 * http://www.gnu.org/copyleft/gpl.html
33 * or write to the Free Software Foundation, Inc., 59
34 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 * Revision 1.12 2001/05/31 17:32:31 oes
40 * - Enhanced domain part globbing with infix and prefix asterisk
41 * matching and optional unanchored operation
43 * Revision 1.11 2001/05/29 23:25:24 oes
45 * - load_config_line() and load_permissions_file() now use chomp()
47 * Revision 1.10 2001/05/29 09:50:24 jongfoster
48 * Unified blocklist/imagelist/permissionslist.
49 * File format is still under discussion, but the internal changes
52 * Also modified interceptor behaviour:
53 * - We now intercept all URLs beginning with one of the following
54 * prefixes (and *only* these prefixes):
56 * * http://ijbswa.sf.net/config/
57 * * http://ijbswa.sourceforge.net/config/
58 * - New interceptors "home page" - go to http://i.j.b/ to see it.
59 * - Internal changes so that intercepted and fast redirect pages
60 * are not replaced with an image.
61 * - Interceptors now have the option to send a binary page direct
62 * to the client. (i.e. ijb-send-banner uses this)
63 * - Implemented show-url-info interceptor. (Which is why I needed
64 * the above interceptors changes - a typical URL is
65 * "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
66 * The previous mechanism would not have intercepted that, and
67 * if it had been intercepted then it then it would have replaced
70 * Revision 1.9 2001/05/26 17:12:07 jongfoster
71 * Fatal errors loading configuration files now give better error messages.
73 * Revision 1.8 2001/05/26 00:55:20 jongfoster
74 * Removing duplicated code. load_forwardfile() now uses create_url_spec()
76 * Revision 1.7 2001/05/26 00:28:36 jongfoster
77 * Automatic reloading of config file.
78 * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
79 * Most of the global variables have been moved to a new
80 * struct configuration_spec, accessed through csp->config->globalname
81 * Most of the globals remaining are used by the Win32 GUI.
83 * Revision 1.6 2001/05/23 12:27:33 oes
85 * Fixed ugly indentation of my last changes
87 * Revision 1.5 2001/05/23 10:39:05 oes
88 * - Added support for escaping the comment character
89 * in config files by a backslash
90 * - Added support for line continuation in config
92 * - Fixed a buffer overflow bug with long config lines
94 * Revision 1.4 2001/05/22 18:56:28 oes
97 * Revision 1.3 2001/05/20 01:21:20 jongfoster
98 * Version 2.9.4 checkin.
99 * - Merged popupfile and cookiefile, and added control over PCRS
100 * filtering, in new "permissionsfile".
101 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
102 * file error you now get a message box (in the Win32 GUI) rather
103 * than the program exiting with no explanation.
104 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
106 * - Removed tabs from "config"
107 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
108 * - Bumped up version number.
110 * Revision 1.2 2001/05/17 23:01:01 oes
111 * - Cleaned CRLF's from the sources and related files
113 * Revision 1.1.1.1 2001/05/15 13:58:59 oes
114 * Initial import of version 2.9.3 source tree
117 *********************************************************************/
124 #include <sys/types.h>
128 #include <sys/stat.h>
143 #include "miscutil.h"
148 #ifndef SPLIT_PROXY_ARGS
150 #include "showargs.h"
151 #endif /* ndef SPLIT_PROXY_ARGS */
153 const char loaders_h_rcs[] = LOADERS_H_VERSION;
155 /* Fix a problem with Solaris. There should be no effect on other
157 * Solaris's isspace() is a macro which uses it's argument directly
158 * as an array index. Therefore we need to make sure that high-bit
159 * characters generate +ve values, and ideally we also want to make
160 * the argument match the declared parameter type of "int".
162 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
166 * Currently active files.
167 * These are also entered in the main linked list of files.
169 static struct file_list *current_forwardfile = NULL;
172 static struct file_list *current_aclfile = NULL;
173 #endif /* def ACL_FILES */
176 static struct file_list *current_trustfile = NULL;
177 #endif /* def TRUST_FILES */
180 static struct file_list *current_re_filterfile = NULL;
181 #endif /* def PCRS */
184 /*********************************************************************
188 * Description : Basically a mark and sweep garbage collector, it is run
189 * (by the parent thread) every once in a while to reclaim memory.
191 * It uses a mark and sweep strategy:
192 * 1) mark all files as inactive
194 * 2) check with each client:
195 * if it is active, mark its files as active
196 * if it is inactive, free its resources
198 * 3) free the resources of all of the files that
199 * are still marked as inactive (and are obsolete).
201 * N.B. files that are not obsolete don't have an unloader defined.
207 *********************************************************************/
210 struct file_list *fl, *nfl;
211 struct client_state *csp, *ncsp;
213 /* clear all of the file's active flags */
214 for ( fl = files->next; NULL != fl; fl = fl->next )
219 for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
223 /* mark this client's files as active */
226 * Always have a configuration file.
227 * (Also note the slightly non-standard extra
230 ncsp->config->config_file_list->active = 1;
232 if (ncsp->actions_list) /* actions files */
234 ncsp->actions_list->active = 1;
237 if (ncsp->flist) /* forward files */
239 ncsp->flist->active = 1;
243 if (ncsp->alist) /* acl files */
245 ncsp->alist->active = 1;
247 #endif /* def ACL_FILES */
250 if (ncsp->rlist) /* perl re files */
252 ncsp->rlist->active = 1;
254 #endif /* def PCRS */
257 if (ncsp->tlist) /* trust files */
259 ncsp->tlist->active = 1;
261 #endif /* def TRUST_FILES */
266 /* this client one is not active, release its resources */
267 csp->next = ncsp->next;
269 freez(ncsp->ip_addr_str);
271 freez(ncsp->referrer);
272 #endif /* def TRUST_FILES */
273 freez(ncsp->x_forwarded);
274 freez(ncsp->iob->buf);
276 free_http_request(ncsp->http);
278 destroy_list(ncsp->headers);
279 destroy_list(ncsp->cookie_list);
281 free_current_action(ncsp->action);
289 #endif /* def STATISTICS */
295 for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
297 if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
299 fl->next = nfl->next;
301 (nfl->unloader)(nfl->f);
303 #ifndef SPLIT_PROXY_ARGS
304 freez(nfl->proxy_args);
305 #endif /* ndef SPLIT_PROXY_ARGS */
307 freez(nfl->filename);
316 /*********************************************************************
318 * Function : create_url_spec
320 * Description : Creates a "url_spec" structure from a string.
321 * When finished, free with unload_url().
324 * 1 : url = Target url_spec to be filled in. Must be
325 * zeroed out before the call (e.g. using zalloc).
326 * 2 : buf = Source pattern, null terminated. NOTE: The
327 * contents of this buffer are destroyed by this
328 * function. If this function succeeds, the
329 * buffer is copied to url->spec. If this
330 * function fails, the contents of the buffer
333 * Returns : 0 => Ok, everything else is an error.
335 *********************************************************************/
336 int create_url_spec(struct url_spec * url, char * buf)
339 struct url_spec tmp_url[1];
341 /* paranoia - should never happen. */
342 if ((url == NULL) || (buf == NULL))
347 /* save a copy of the orignal specification */
348 if ((url->spec = strdup(buf)) == NULL)
353 if ((p = strchr(buf, '/')))
355 if (NULL == (url->path = strdup(p)))
360 url->pathlen = strlen(url->path);
374 if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
381 sprintf(rebuf, "^(%s)", url->path);
383 errcode = regcomp(url->preg, rebuf,
384 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
389 url->preg, buf, sizeof(buf));
393 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
404 if ((p = strchr(buf, ':')) == NULL)
414 if ((url->domain = strdup(buf)) == NULL)
420 #endif /* def REGEX */
424 /* split domain into components */
426 *tmp_url = dsplit(url->domain);
427 url->dbuf = tmp_url->dbuf;
428 url->dcnt = tmp_url->dcnt;
429 url->dvec = tmp_url->dvec;
430 url->unanchored = tmp_url->unanchored;
436 /*********************************************************************
438 * Function : free_url
440 * Description : Called from the "unloaders". Freez the url
441 * structure elements.
444 * 1 : url = pointer to a url_spec structure.
448 *********************************************************************/
449 void free_url(struct url_spec *url)
451 if (url == NULL) return;
470 /*********************************************************************
472 * Function : unload_aclfile
474 * Description : Unloads an aclfile.
477 * 1 : f = the data structure associated with the aclfile.
481 *********************************************************************/
482 static void unload_aclfile(void *f)
484 struct access_control_list *b = (struct access_control_list *)f;
485 if (b == NULL) return;
487 unload_aclfile(b->next);
492 #endif /* def ACL_FILES */
496 /*********************************************************************
498 * Function : unload_trustfile
500 * Description : Unloads a trustfile.
503 * 1 : f = the data structure associated with the trustfile.
507 *********************************************************************/
508 static void unload_trustfile(void *f)
510 struct block_spec *b = (struct block_spec *)f;
511 if (b == NULL) return;
513 unload_trustfile(b->next);
520 #endif /* def TRUST_FILES */
523 /*********************************************************************
525 * Function : unload_forwardfile
527 * Description : Unloads a forwardfile.
530 * 1 : f = the data structure associated with the forwardfile.
534 *********************************************************************/
535 static void unload_forwardfile(void *f)
537 struct forward_spec *b = (struct forward_spec *)f;
538 if (b == NULL) return;
540 unload_forwardfile(b->next);
544 freez(b->gw->gateway_host);
545 freez(b->gw->forward_host);
553 /*********************************************************************
555 * Function : unload_re_filterfile
557 * Description : Unload the re_filter list.
560 * 1 : f = the data structure associated with the filterfile.
564 *********************************************************************/
565 static void unload_re_filterfile(void *f)
568 struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
570 if (b == NULL) return;
572 destroy_list(b->patterns);
574 joblist = b->joblist;
575 while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
580 #endif /* def PCRS */
583 /*********************************************************************
585 * Function : check_file_changed
587 * Description : Helper function to check if a file needs reloading.
588 * If "current" is still current, return it. Otherwise
589 * allocates a new (zeroed) "struct file_list", fills
590 * in the disk file name and timestamp, and returns it.
593 * 1 : current = The file_list currently being used - will
594 * be checked to see if it is out of date.
595 * May be NULL (which is treated as out of
597 * 2 : filename = Name of file to check.
598 * 3 : newfl = New file list. [Output only]
599 * This will be set to NULL, OR a struct
600 * file_list newly allocated on the
601 * heap, with the filename and lastmodified
602 * fields filled, standard header giving file
603 * name in proxy_args, and all others zeroed.
604 * (proxy_args is only filled in if !defined
605 * SPLIT_PROXY_ARGS and !suppress_blocklists).
607 * Returns : If file unchanged: 0 (and sets newfl == NULL)
608 * If file changed: 1 and sets newfl != NULL
609 * On error: 1 and sets newfl == NULL
611 *********************************************************************/
612 int check_file_changed(const struct file_list * current,
613 const char * filename,
614 struct file_list ** newfl)
616 struct file_list *fs;
617 struct stat statbuf[1];
621 if (stat(filename, statbuf) < 0)
623 /* Error, probably file not found. */
628 && (current->lastmodified == statbuf->st_mtime)
629 && (0 == strcmp(current->filename, filename)))
634 fs = (struct file_list *)zalloc(sizeof(struct file_list));
638 /* Out of memory error */
642 fs->filename = strdup(filename);
643 fs->lastmodified = statbuf->st_mtime;
645 if (fs->filename == NULL)
647 /* Out of memory error */
652 #ifndef SPLIT_PROXY_ARGS
653 if (!suppress_blocklists)
655 char * p = html_encode(filename);
658 fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
659 fs->proxy_args = strsav(fs->proxy_args, p);
660 fs->proxy_args = strsav(fs->proxy_args,
661 "' contains the following patterns</h2>\n");
664 fs->proxy_args = strsav(fs->proxy_args, "<pre>");
666 #endif /* ndef SPLIT_PROXY_ARGS */
673 /*********************************************************************
675 * Function : read_config_line
677 * Description : Read a single non-empty line from a file and return
678 * it. Trims comments, leading and trailing whitespace
679 * and respects escaping of newline and comment char.
680 * Also writes the file to fs->proxy_args.
683 * 1 : buf = Buffer to use.
684 * 2 : buflen = Size of buffer in bytes.
685 * 3 : fp = File to read from
686 * 4 : fs = File will be written to fs->proxy_args. May
687 * be NULL to disable this feature.
689 * Returns : NULL on EOF or error
690 * Otherwise, returns buf.
692 *********************************************************************/
693 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
696 char linebuf[BUFSIZ];
701 while (fgets(linebuf, sizeof(linebuf), fp))
703 #ifndef SPLIT_PROXY_ARGS
704 if (fs && !suppress_blocklists)
706 char *html_line = html_encode(linebuf);
707 if (html_line != NULL)
709 fs->proxy_args = strsav(fs->proxy_args, html_line);
712 fs->proxy_args = strsav(fs->proxy_args, "<br>");
714 #endif /* ndef SPLIT_PROXY_ARGS */
716 /* Trim off newline */
717 if ((p = strpbrk(linebuf, "\r\n")) != NULL)
722 /* Line continuation? Trim escape and set flag. */
723 if ((p != linebuf) && (*--p == '\\'))
729 /* If there's a comment char.. */
730 if ((p = strpbrk(linebuf, "#")) != NULL)
732 /* ..and it's escaped, left-shift the line over the escape. */
733 if ((p != linebuf) && (*(p-1) == '\\'))
736 while ((*q++ = *p++) != '\0') /* nop */;
738 /* Else, chop off the rest of the line */
745 /* Remove leading and trailing whitespace */
750 strncat(buf, linebuf, buflen - strlen(buf));
769 /*********************************************************************
771 * Function : load_aclfile
773 * Description : Read and parse an aclfile and add to files list.
776 * 1 : csp = Current client state (buffers, headers, etc...)
778 * Returns : 0 => Ok, everything else is an error.
780 *********************************************************************/
781 int load_aclfile(struct client_state *csp)
784 char buf[BUFSIZ], *v[3], *p;
786 struct access_control_list *a, *bl;
787 struct file_list *fs;
789 if (!check_file_changed(current_aclfile, csp->config->aclfile, &fs))
791 /* No need to load */
794 csp->alist = current_aclfile;
800 goto load_aclfile_error;
803 fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
808 goto load_aclfile_error;
811 fp = fopen(csp->config->aclfile, "r");
815 goto load_aclfile_error;
818 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
820 i = ssplit(buf, " \t", v, SZ(v), 1, 1);
822 /* allocate a new node */
823 a = (struct access_control_list *) zalloc(sizeof(*a));
831 goto load_aclfile_error;
834 /* add it to the list */
841 if (acl_addr(v[2], a->dst) < 0)
843 goto load_aclfile_error;
848 if (acl_addr(v[1], a->src) < 0)
850 goto load_aclfile_error;
854 if (strcmpic(p, "permit") == 0)
856 a->action = ACL_PERMIT;
860 if (strcmpic(p, "deny") == 0)
862 a->action = ACL_DENY;
868 goto load_aclfile_error;
874 #ifndef SPLIT_PROXY_ARGS
875 if (!suppress_blocklists)
877 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
879 #endif /* ndef SPLIT_PROXY_ARGS */
883 current_aclfile->unloader = unload_aclfile;
886 fs->next = files->next;
888 current_aclfile = fs;
898 log_error(LOG_LEVEL_FATAL, "can't load access control list %s: %E",
899 csp->config->aclfile);
903 #endif /* def ACL_FILES */
907 /*********************************************************************
909 * Function : load_trustfile
911 * Description : Read and parse a trustfile and add to files list.
914 * 1 : csp = Current client state (buffers, headers, etc...)
916 * Returns : 0 => Ok, everything else is an error.
918 *********************************************************************/
919 int load_trustfile(struct client_state *csp)
923 struct block_spec *b, *bl;
924 struct url_spec **tl;
926 char buf[BUFSIZ], *p, *q;
928 struct file_list *fs;
930 if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
932 /* No need to load */
935 csp->tlist = current_trustfile;
941 goto load_trustfile_error;
944 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
947 goto load_trustfile_error;
950 if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
952 goto load_trustfile_error;
955 tl = csp->config->trust_list;
957 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
973 while ((*p++ = *q++))
979 /* skip blank lines */
985 /* allocate a new node */
986 if ((b = zalloc(sizeof(*b))) == NULL)
989 goto load_trustfile_error;
992 /* add it to the list */
998 /* Save the URL pattern */
999 if (create_url_spec(b->url, buf))
1002 goto load_trustfile_error;
1006 * save a pointer to URL's spec in the list of trusted URL's, too
1018 #ifndef SPLIT_PROXY_ARGS
1019 if (!suppress_blocklists)
1021 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1023 #endif /* ndef SPLIT_PROXY_ARGS */
1025 /* the old one is now obsolete */
1026 if (current_trustfile)
1028 current_trustfile->unloader = unload_trustfile;
1031 fs->next = files->next;
1033 current_trustfile = fs;
1042 load_trustfile_error:
1043 log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1044 csp->config->trustfile);
1048 #endif /* def TRUST_FILES */
1051 /*********************************************************************
1053 * Function : load_forwardfile
1055 * Description : Read and parse a forwardfile and add to files list.
1058 * 1 : csp = Current client state (buffers, headers, etc...)
1060 * Returns : 0 => Ok, everything else is an error.
1062 *********************************************************************/
1063 int load_forwardfile(struct client_state *csp)
1067 struct forward_spec *b, *bl;
1072 struct file_list *fs;
1073 const struct gateway *gw;
1075 if (!check_file_changed(current_forwardfile, csp->config->forwardfile, &fs))
1077 /* No need to load */
1080 csp->flist = current_forwardfile;
1086 goto load_forwardfile_error;
1089 fs->f = bl = (struct forward_spec *)zalloc(sizeof(*bl));
1091 if ((fs == NULL) || (bl == NULL))
1093 goto load_forwardfile_error;
1096 if ((fp = fopen(csp->config->forwardfile, "r")) == NULL)
1098 goto load_forwardfile_error;
1103 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1109 n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1113 log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1117 strcpy(buf, vec[0]);
1119 /* skip lines containing only ~ */
1125 /* allocate a new node */
1126 if (((b = zalloc(sizeof(*b))) == NULL)
1130 goto load_forwardfile_error;
1133 /* add it to the list */
1137 /* Save the URL pattern */
1138 if (create_url_spec(b->url, buf))
1141 goto load_forwardfile_error;
1144 /* now parse the gateway specs */
1148 for (gw = gateways; gw->name; gw++)
1150 if (strcmp(gw->name, p) == 0)
1156 if (gw->name == NULL)
1158 goto load_forwardfile_error;
1161 /* save this as the gateway type */
1164 /* now parse the gateway host[:port] spec */
1167 if (strcmp(p, ".") != 0)
1169 b->gw->gateway_host = strdup(p);
1171 if ((p = strchr(b->gw->gateway_host, ':')))
1174 b->gw->gateway_port = atoi(p);
1177 if (b->gw->gateway_port <= 0)
1179 goto load_forwardfile_error;
1183 /* now parse the forwarding spec */
1186 if (strcmp(p, ".") != 0)
1188 b->gw->forward_host = strdup(p);
1190 if ((p = strchr(b->gw->forward_host, ':')))
1193 b->gw->forward_port = atoi(p);
1196 if (b->gw->forward_port <= 0)
1198 b->gw->forward_port = 8000;
1207 #ifndef SPLIT_PROXY_ARGS
1208 if (!suppress_blocklists)
1210 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1212 #endif /* ndef SPLIT_PROXY_ARGS */
1214 /* the old one is now obsolete */
1215 if (current_forwardfile)
1217 current_forwardfile->unloader = unload_forwardfile;
1220 fs->next = files->next;
1222 current_forwardfile = fs;
1231 load_forwardfile_error:
1232 log_error(LOG_LEVEL_FATAL, "can't load forwardfile '%s': %E",
1233 csp->config->forwardfile);
1240 /*********************************************************************
1242 * Function : load_re_filterfile
1244 * Description : Load the re_filterfile. Each non-comment, non-empty
1245 * line is instantly added to the joblist, which is
1246 * a chained list of pcrs_job structs.
1249 * 1 : csp = Current client state (buffers, headers, etc...)
1251 * Returns : 0 => Ok, everything else is an error.
1253 *********************************************************************/
1254 int load_re_filterfile(struct client_state *csp)
1258 struct re_filterfile_spec *bl;
1259 struct file_list *fs;
1265 if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1267 /* No need to load */
1270 csp->rlist = current_re_filterfile;
1276 goto load_re_filterfile_error;
1279 fs->f = bl = (struct re_filterfile_spec *)zalloc(sizeof(*bl));
1282 goto load_re_filterfile_error;
1285 /* Open the file or fail */
1286 if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1288 goto load_re_filterfile_error;
1291 /* Read line by line */
1292 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1294 enlist( bl->patterns, buf );
1296 /* We have a meaningful line -> make it a job */
1297 if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1299 log_error(LOG_LEVEL_RE_FILTER,
1300 "Adding re_filter job %s failed with error %d.", buf, error);
1305 dummy->next = bl->joblist;
1306 bl->joblist = dummy;
1307 log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1313 #ifndef SPLIT_PROXY_ARGS
1314 if (!suppress_blocklists)
1316 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1318 #endif /* ndef SPLIT_PROXY_ARGS */
1320 /* the old one is now obsolete */
1321 if ( NULL != current_re_filterfile )
1323 current_re_filterfile->unloader = unload_re_filterfile;
1326 fs->next = files->next;
1328 current_re_filterfile = fs;
1337 load_re_filterfile_error:
1338 log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1339 csp->config->re_filterfile);
1343 #endif /* def PCRS */
1346 /*********************************************************************
1348 * Function : add_loader
1350 * Description : Called from `load_config'. Called once for each input
1351 * file found in config.
1354 * 1 : loader = pointer to a function that can parse and load
1355 * the appropriate config file.
1356 * 2 : config = The configuration_spec to add the loader to.
1360 *********************************************************************/
1361 void add_loader(int (*loader)(struct client_state *),
1362 struct configuration_spec * config)
1366 for (i=0; i < NLOADERS; i++)
1368 if (config->loaders[i] == NULL)
1370 config->loaders[i] = loader;
1378 /*********************************************************************
1380 * Function : run_loader
1382 * Description : Called from `load_config' and `listen_loop'. This
1383 * function keeps the "csp" current with any file mods
1384 * since the last loop. If a file is unchanged, the
1385 * loader functions do NOT reload the file.
1388 * 1 : csp = Current client state (buffers, headers, etc...)
1389 * Must be non-null. Reads: "csp->config"
1390 * Writes: various data members.
1392 * Returns : 0 => Ok, everything else is an error.
1394 *********************************************************************/
1395 int run_loader(struct client_state *csp)
1400 for (i=0; i < NLOADERS; i++)
1402 if (csp->config->loaders[i] == NULL)
1406 ret |= (csp->config->loaders[i])(csp);