]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cache_cf.cc
hno squid-2.3.DEVEL3.httpd_accel_single_host-2.patch
[thirdparty/squid.git] / src / cache_cf.cc
CommitLineData
be335c22 1
30a4f2a8 2/*
987de783 3 * $Id: cache_cf.cc,v 1.339 2000/05/02 18:51:50 hno Exp $
30a4f2a8 4 *
5 * DEBUG: section 3 Configuration File Parsing
6 * AUTHOR: Harvest Derived
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
e25c139f 13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
efd900cb 15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
30a4f2a8 34 */
cf5fd929 35
44a47c6e 36#include "squid.h"
1df370e3 37
38#if SQUID_SNMP
a97cfa48 39#include "snmp.h"
1df370e3 40#endif
090089c4 41
8813e606 42static const char *const T_SECOND_STR = "second";
43static const char *const T_MINUTE_STR = "minute";
44static const char *const T_HOUR_STR = "hour";
45static const char *const T_DAY_STR = "day";
46static const char *const T_WEEK_STR = "week";
47static const char *const T_FORTNIGHT_STR = "fortnight";
48static const char *const T_MONTH_STR = "month";
49static const char *const T_YEAR_STR = "year";
50static const char *const T_DECADE_STR = "decade";
aa0a0c7c 51
9906e724 52static const char *const B_BYTES_STR = "bytes";
53static const char *const B_KBYTES_STR = "KB";
54static const char *const B_MBYTES_STR = "MB";
55static const char *const B_GBYTES_STR = "GB";
56
4db43fab 57static const char *const list_sep = ", \t\n\r";
efd900cb 58static int http_header_first;
59static int http_header_allowed = 0;
97474590 60
f5b8bbc4 61static void configDoConfigure(void);
62static void parse_refreshpattern(refresh_t **);
63static int parseTimeUnits(const char *unit);
64static void parseTimeLine(time_t * tptr, const char *units);
59715b38 65static void parse_ushort(u_short * var);
f5b8bbc4 66static void parse_string(char **);
67static void parse_wordlist(wordlist **);
68static void default_all(void);
69static void defaults_if_none(void);
70static int parse_line(char *);
71static void parseBytesLine(size_t * bptr, const char *units);
72static size_t parseBytesUnits(const char *unit);
f5b8bbc4 73static void free_all(void);
f0b19334 74static void requirePathnameExists(const char *name, const char *path);
ed7f5615 75static OBJH dump_config;
97474590 76static void dump_http_header(StoreEntry * entry, const char *name, HttpHeaderMask header);
77static void parse_http_header(HttpHeaderMask * header);
e3dd531e 78static void free_http_header(HttpHeaderMask * header);
7e3ce7b9 79static void parse_sockaddr_in_list(sockaddr_in_list **);
80static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
81static void free_sockaddr_in_list(sockaddr_in_list **);
82static int check_null_sockaddr_in_list(const sockaddr_in_list *);
270b86af 83
0e4e0e7d 84void
0673c0ba 85self_destruct(void)
090089c4 86{
137ee196 87 fatalf("Bungled %s line %d: %s",
b8de7ebe 88 cfg_filename, config_lineno, config_input_line);
090089c4 89}
90
8203a132 91void
92wordlistDestroy(wordlist ** list)
0ffd22bc 93{
94 wordlist *w = NULL;
79d39a72 95 while ((w = *list) != NULL) {
b5639035 96 *list = w->next;
0ffd22bc 97 safe_free(w->key);
db1cd23c 98 memFree(w, MEM_WORDLIST);
0ffd22bc 99 }
100 *list = NULL;
101}
102
c68e9c6b 103wordlist *
fe4e214f 104wordlistAdd(wordlist ** list, const char *key)
090089c4 105{
c68e9c6b 106 while (*list)
107 list = &(*list)->next;
108 *list = memAllocate(MEM_WORDLIST);
109 (*list)->key = xstrdup(key);
110 (*list)->next = NULL;
111 return *list;
090089c4 112}
113
137ee196 114void
eeb423fb 115wordlistCat(const wordlist * w, MemBuf * mb)
5da06f20 116{
5da06f20 117 while (NULL != w) {
137ee196 118 memBufPrintf(mb, "%s\n", w->key);
5da06f20 119 w = w->next;
120 }
5da06f20 121}
122
6b8e7481 123wordlist *
124wordlistDup(const wordlist * w)
125{
126 wordlist *D = NULL;
127 while (NULL != w) {
128 wordlistAdd(&D, w->key);
129 w = w->next;
130 }
131 return D;
132}
133
8203a132 134void
135intlistDestroy(intlist ** list)
92a6f4b1 136{
137 intlist *w = NULL;
138 intlist *n = NULL;
92a6f4b1 139 for (w = *list; w; w = n) {
140 n = w->next;
db1cd23c 141 memFree(w, MEM_INTLIST);
92a6f4b1 142 }
143 *list = NULL;
144}
145
5db53b8f 146int
147intlistFind(intlist * list, int i)
148{
149 intlist *w = NULL;
150 for (w = list; w; w = w->next)
151 if (w->i == i)
152 return 1;
153 return 0;
154}
155
403279e0 156
3c5557f9 157/*
158 * Use this #define in all the parse*() functions. Assumes char *token is
159 * defined
160 */
090089c4 161
0e4e0e7d 162int
163GetInteger(void)
164{
165 char *token = strtok(NULL, w_space);
166 int i;
167 if (token == NULL)
168 self_destruct();
169 if (sscanf(token, "%d", &i) != 1)
170 self_destruct();
171 return i;
172}
090089c4 173
270b86af 174int
175parseConfigFile(const char *file_name)
2546fcb3 176{
270b86af 177 FILE *fp = NULL;
178 char *token = NULL;
72121e8b 179 char *tmp_line;
e13ee7ad 180 int err_count = 0;
0153d498 181 free_all();
182 default_all();
137ee196 183 if ((fp = fopen(file_name, "r")) == NULL)
184 fatalf("Unable to open configuration file: %s: %s",
270b86af 185 file_name, xstrerror());
270b86af 186 cfg_filename = file_name;
187 if ((token = strrchr(cfg_filename, '/')))
188 cfg_filename = token + 1;
189 memset(config_input_line, '\0', BUFSIZ);
190 config_lineno = 0;
efd900cb 191 http_header_first = 0;
270b86af 192 while (fgets(config_input_line, BUFSIZ, fp)) {
193 config_lineno++;
194 if ((token = strchr(config_input_line, '\n')))
195 *token = '\0';
196 if (config_input_line[0] == '#')
197 continue;
198 if (config_input_line[0] == '\0')
199 continue;
200 debug(3, 5) ("Processing: '%s'\n", config_input_line);
72121e8b 201 tmp_line = xstrdup(config_input_line);
270b86af 202 if (!parse_line(tmp_line)) {
203 debug(3, 0) ("parseConfigFile: line %d unrecognized: '%s'\n",
204 config_lineno,
205 config_input_line);
e13ee7ad 206 err_count++;
270b86af 207 }
72121e8b 208 safe_free(tmp_line);
270b86af 209 }
f0b19334 210 fclose(fp);
211 defaults_if_none();
212 configDoConfigure();
22f3fd98 213 cachemgrRegister("config",
214 "Current Squid Configuration",
215 dump_config,
1da3b90b 216 1, 1);
e13ee7ad 217 return err_count;
f0b19334 218}
270b86af 219
f0b19334 220static void
221configDoConfigure(void)
222{
223 LOCAL_ARRAY(char, buf, BUFSIZ);
224 memset(&Config2, '\0', sizeof(SquidConfig2));
7021844c 225 /* init memory as early as possible */
226 memConfigure();
270b86af 227 /* Sanity checks */
a95856a0 228 if (Config.cacheSwap.swapDirs == NULL)
229 fatal("No cache_dir's specified in config file");
9fa8263f 230 /* calculate Config.Swap.maxSize */
f4e3fa54 231 storeDirConfigure();
43a70238 232 if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
f0b19334 233 fatal("cache_swap is lower than cache_mem");
84f42bac 234 if (Config.Announce.period > 0) {
235 Config.onoff.announce = 1;
236 } else if (Config.Announce.period < 1) {
f1dc9b30 237 Config.Announce.period = 86400 * 365; /* one year */
17a0a4ee 238 Config.onoff.announce = 0;
270b86af 239 }
efd900cb 240#if USE_DNSSERVER
f0b19334 241 if (Config.dnsChildren < 1)
242 fatal("No dnsservers allocated");
243 if (Config.dnsChildren > DefaultDnsChildrenMax) {
244 debug(3, 0) ("WARNING: dns_children was set to a bad value: %d\n",
270b86af 245 Config.dnsChildren);
f0b19334 246 debug(3, 0) ("Setting it to the maximum (%d).\n",
247 DefaultDnsChildrenMax);
270b86af 248 Config.dnsChildren = DefaultDnsChildrenMax;
249 }
efd900cb 250#endif
270b86af 251 if (Config.Program.redirect) {
252 if (Config.redirectChildren < 1) {
253 Config.redirectChildren = 0;
c6d5b87b 254 wordlistDestroy(&Config.Program.redirect);
270b86af 255 } else if (Config.redirectChildren > DefaultRedirectChildrenMax) {
f0b19334 256 debug(3, 0) ("WARNING: redirect_children was set to a bad value: %d\n",
270b86af 257 Config.redirectChildren);
f0b19334 258 debug(3, 0) ("Setting it to the maximum (%d).\n", DefaultRedirectChildrenMax);
270b86af 259 Config.redirectChildren = DefaultRedirectChildrenMax;
260 }
fea2e6e0 261 }
73e67ee0 262 if (Config.Program.authenticate) {
263 if (Config.authenticateChildren < 1) {
264 Config.authenticateChildren = 0;
6c20b822 265 wordlistDestroy(&Config.Program.authenticate);
73e67ee0 266 } else if (Config.authenticateChildren > DefaultAuthenticateChildrenMax) {
267 debug(3, 0) ("WARNING: authenticate_children was set to a bad value: %d\n",
268 Config.authenticateChildren);
269 debug(3, 0) ("Setting it to the maximum (%d).\n", DefaultAuthenticateChildrenMax);
270 Config.authenticateChildren = DefaultAuthenticateChildrenMax;
271 }
272 }
f1dc9b30 273 if (Config.Accel.host) {
a47b9029 274 snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
275 Config2.Accel.prefix = xstrdup(buf);
276 Config2.Accel.on = 1;
f1dc9b30 277 }
278 if (Config.appendDomain)
279 if (*Config.appendDomain != '.')
280 fatal("append_domain must begin with a '.'");
270b86af 281 if (Config.errHtmlText == NULL)
282 Config.errHtmlText = xstrdup(null_string);
283 storeConfigure();
f1dc9b30 284 if (Config2.Accel.on && !strcmp(Config.Accel.host, "virtual"))
270b86af 285 vhost_mode = 1;
7e3ce7b9 286 if (Config.Sockaddr.http == NULL)
270b86af 287 fatal("No http_port specified!");
137ee196 288 snprintf(ThisCache, sizeof(ThisCache), "%s:%d (%s)",
98829f69 289 uniqueHostname(),
7e3ce7b9 290 (int) ntohs(Config.Sockaddr.http->s.sin_port),
137ee196 291 full_appname_string);
38a6c74e 292 /*
293 * the extra space is for loop detection in client_side.c -- we search
294 * for substrings in the Via header.
295 */
296 snprintf(ThisCache2, sizeof(ThisCache), " %s:%d (%s)",
297 uniqueHostname(),
7e3ce7b9 298 (int) ntohs(Config.Sockaddr.http->s.sin_port),
38a6c74e 299 full_appname_string);
270b86af 300 if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
301 Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
302 if (Config.appendDomain)
303 Config.appendDomainLen = strlen(Config.appendDomain);
304 else
305 Config.appendDomainLen = 0;
f1dc9b30 306 safe_free(debug_options)
307 debug_options = xstrdup(Config.debugOptions);
22c653cd 308 if (Config.retry.timeout < 5)
309 fatal("minimum_retry_timeout must be at least 5 seconds");
310 if (Config.retry.maxtries > 10)
311 fatal("maximum_single_addr_tries cannot be larger than 10");
312 if (Config.retry.maxtries < 1) {
22c653cd 313 debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
5210854d 314 Config.retry.maxtries = 1;
315 }
2b906e48 316#if HEAP_REPLACEMENT
317 /* The non-LRU policies do not use referenceAge */
318#else
5210854d 319 if (Config.referenceAge < 300) {
320 debug(3, 0) ("WARNING: resetting 'reference_age' to 1 week\n");
321 Config.referenceAge = 86400 * 7;
22c653cd 322 }
2b906e48 323#endif
f0b19334 324 requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
efd900cb 325#if USE_DNSSERVER
f0b19334 326 requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
efd900cb 327#endif
f0b19334 328 requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
329 if (Config.Program.redirect)
c6d5b87b 330 requirePathnameExists("redirect_program", Config.Program.redirect->key);
73e67ee0 331 if (Config.Program.authenticate)
6c20b822 332 requirePathnameExists("authenticate_program", Config.Program.authenticate->key);
f0b19334 333 requirePathnameExists("Icon Directory", Config.icons.directory);
334 requirePathnameExists("Error Directory", Config.errorDirectory);
9f60cfdf 335#if HTTP_VIOLATIONS
336 {
49c0f46d 337 const refresh_t *R;
338 for (R = Config.Refresh; R; R = R->next) {
339 if (!R->flags.override_expire)
340 continue;
341 debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
342 break;
343 }
344 for (R = Config.Refresh; R; R = R->next) {
345 if (!R->flags.override_lastmod)
346 continue;
347 debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
348 break;
349 }
9f60cfdf 350 }
351#endif
db1cd23c 352 if (Config.Wais.relayHost) {
353 if (Config.Wais.peer)
354 cbdataFree(Config.Wais.peer);
355 Config.Wais.peer = memAllocate(MEM_PEER);
356 cbdataAdd(Config.Wais.peer, peerDestroy, MEM_PEER);
b6a2f15e 357 Config.Wais.peer->host = xstrdup(Config.Wais.relayHost);
db1cd23c 358 Config.Wais.peer->http_port = Config.Wais.relayPort;
359 }
53cb32a9 360 if (aclPurgeMethodInUse(Config.accessList.http))
361 Config2.onoff.enable_purge = 1;
090089c4 362}
363
270b86af 364/* Parse a time specification from the config file. Store the
f1dc9b30 365 * result in 'tptr', after converting it to 'units' */
8203a132 366static void
a47b9029 367parseTimeLine(time_t * tptr, const char *units)
090089c4 368{
369 char *token;
270b86af 370 double d;
f1dc9b30 371 time_t m;
372 time_t u;
270b86af 373 if ((u = parseTimeUnits(units)) == 0)
3003c0f3 374 self_destruct();
270b86af 375 if ((token = strtok(NULL, w_space)) == NULL)
3003c0f3 376 self_destruct();
270b86af 377 d = atof(token);
378 m = u; /* default to 'units' if none specified */
10738561 379 if (0 == d)
380 (void) 0;
381 else if ((token = strtok(NULL, w_space)) == NULL)
a47b9029 382 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
383 config_input_line, d, units);
9e975e4e 384 else if ((m = parseTimeUnits(token)) == 0)
a47b9029 385 self_destruct();
f1dc9b30 386 *tptr = m * d / u;
090089c4 387}
388
270b86af 389static int
390parseTimeUnits(const char *unit)
391{
392 if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
393 return 1;
394 if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
395 return 60;
396 if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
397 return 3600;
398 if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
399 return 86400;
400 if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
401 return 86400 * 7;
402 if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
403 return 86400 * 14;
404 if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
405 return 86400 * 30;
406 if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
407 return 86400 * 365.2522;
408 if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
409 return 86400 * 365.2522 * 10;
410 debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit);
411 return 0;
412}
413
9906e724 414static void
9e975e4e 415parseBytesLine(size_t * bptr, const char *units)
9906e724 416{
417 char *token;
418 double d;
419 size_t m;
420 size_t u;
421 if ((u = parseBytesUnits(units)) == 0)
422 self_destruct();
423 if ((token = strtok(NULL, w_space)) == NULL)
424 self_destruct();
425 d = atof(token);
426 m = u; /* default to 'units' if none specified */
343f47a3 427 if (0.0 == d)
10738561 428 (void) 0;
4860dc1b 429 else if ((token = strtok(NULL, w_space)) == NULL)
9e975e4e 430 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
431 config_input_line, d, units);
432 else if ((m = parseBytesUnits(token)) == 0)
433 self_destruct();
9906e724 434 *bptr = m * d / u;
435}
436
437static size_t
438parseBytesUnits(const char *unit)
439{
440 if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
441 return 1;
442 if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
a47b9029 443 return 1 << 10;
9906e724 444 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
a47b9029 445 return 1 << 20;
9906e724 446 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
a47b9029 447 return 1 << 30;
9906e724 448 debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
449 return 0;
450}
451
270b86af 452/*****************************************************************************
453 * Max
454 *****************************************************************************/
455
8203a132 456static void
9ef28b60 457dump_acl(StoreEntry * entry, const char *name, acl * ae)
090089c4 458{
56b63fa1 459 wordlist *w;
460 wordlist *v;
9ef28b60 461 while (ae != NULL) {
c68e9c6b 462 debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
9ef28b60 463 v = w = aclDumpGeneric(ae);
56b63fa1 464 while (v != NULL) {
c68e9c6b 465 debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
16300b58 466 storeAppendPrintf(entry, "%s %s %s %s\n",
467 name,
9ef28b60 468 ae->name,
469 aclTypeToStr(ae->type),
16300b58 470 v->key);
56b63fa1 471 v = v->next;
472 }
473 wordlistDestroy(&w);
9ef28b60 474 ae = ae->next;
56b63fa1 475 }
090089c4 476}
477
8203a132 478static void
9ef28b60 479parse_acl(acl ** ae)
090089c4 480{
9ef28b60 481 aclParseAclLine(ae);
f1dc9b30 482}
483
484static void
9ef28b60 485free_acl(acl ** ae)
f1dc9b30 486{
9ef28b60 487 aclDestroyAcls(ae);
090089c4 488}
489
8203a132 490static void
16300b58 491dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
30a4f2a8 492{
56b63fa1 493 acl_list *l;
494 while (head != NULL) {
505e35db 495 storeAppendPrintf(entry, "%s %s",
0cdcddb9 496 name,
505e35db 497 head->allow ? "Allow" : "Deny");
498 for (l = head->acl_list; l != NULL; l = l->next) {
499 storeAppendPrintf(entry, " %s%s",
500 l->op ? null_string : "!",
56b63fa1 501 l->acl->name);
16300b58 502 }
505e35db 503 storeAppendPrintf(entry, "\n");
56b63fa1 504 head = head->next;
505 }
30a4f2a8 506}
090089c4 507
8203a132 508static void
16300b58 509parse_acl_access(acl_access ** head)
090089c4 510{
270b86af 511 aclParseAccessLine(head);
090089c4 512}
513
0153d498 514static void
16300b58 515free_acl_access(acl_access ** head)
0153d498 516{
a47b9029 517 aclDestroyAccessList(head);
0153d498 518}
519
8203a132 520static void
a7d59104 521dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
270b86af 522{
f53b06f9 523 storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
270b86af 524}
525
526static void
527parse_address(struct in_addr *addr)
090089c4 528{
0ee4272b 529 const struct hostent *hp;
270b86af 530 char *token = strtok(NULL, w_space);
531
30a4f2a8 532 if (token == NULL)
533 self_destruct();
429fdbec 534 if (safe_inet_addr(token, addr) == 1)
535 (void) 0;
ceb8994e 536 else if ((hp = gethostbyname(token))) /* dont use ipcache */
1d73e33a 537 *addr = inaddrFromHostent(hp);
30a4f2a8 538 else
3003c0f3 539 self_destruct();
090089c4 540}
541
0153d498 542static void
543free_address(struct in_addr *addr)
544{
a47b9029 545 memset(addr, '\0', sizeof(struct in_addr));
0153d498 546}
547
59715b38 548#if DELAY_POOLS
549
550/* do nothing - free_delay_pool_count is the magic free function.
551 * this is why delay_pool_count isn't just marked TYPE: ushort
552 */
553#define free_delay_pool_class(X)
554#define free_delay_pool_access(X)
555#define free_delay_pool_rates(X)
556#define dump_delay_pool_class(X, Y, Z)
557#define dump_delay_pool_access(X, Y, Z)
558#define dump_delay_pool_rates(X, Y, Z)
559
560static void
561free_delay_pool_count(delayConfig * cfg)
562{
563 int i;
564
565 if (!cfg->pools)
566 return;
567 for (i = 0; i < cfg->pools; i++) {
568 if (cfg->class[i]) {
569 delayFreeDelayPool(i);
570 safe_free(cfg->rates[i]);
571 }
572 aclDestroyAccessList(&cfg->access[i]);
573 }
574 delayFreeDelayData();
575 xfree(cfg->class);
576 xfree(cfg->rates);
577 xfree(cfg->access);
578 memset(cfg, 0, sizeof(*cfg));
579}
580
581static void
582dump_delay_pool_count(StoreEntry * entry, const char *name, delayConfig cfg)
583{
584 int i;
585 LOCAL_ARRAY(char, nom, 32);
586
587 if (!cfg.pools) {
588 storeAppendPrintf(entry, "%s 0\n", name);
589 return;
590 }
591 storeAppendPrintf(entry, "%s %d\n", name, cfg.pools);
592 for (i = 0; i < cfg.pools; i++) {
593 storeAppendPrintf(entry, "delay_class %d %d\n", i + 1, cfg.class[i]);
594 snprintf(nom, 32, "delay_access %d", i + 1);
595 dump_acl_access(entry, nom, cfg.access[i]);
596 if (cfg.class[i] >= 1)
597 storeAppendPrintf(entry, "delay_parameters %d %d/%d", i + 1,
598 cfg.rates[i]->aggregate.restore_bps,
599 cfg.rates[i]->aggregate.max_bytes);
600 if (cfg.class[i] >= 3)
601 storeAppendPrintf(entry, " %d/%d",
602 cfg.rates[i]->network.restore_bps,
603 cfg.rates[i]->network.max_bytes);
604 if (cfg.class[i] >= 2)
605 storeAppendPrintf(entry, " %d/%d",
606 cfg.rates[i]->individual.restore_bps,
607 cfg.rates[i]->individual.max_bytes);
608 if (cfg.class[i] >= 1)
609 storeAppendPrintf(entry, "\n");
610 }
611}
612
613static void
614parse_delay_pool_count(delayConfig * cfg)
615{
616 if (cfg->pools) {
617 debug(3, 0) ("parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config\n");
618 free_delay_pool_count(cfg);
619 }
620 parse_ushort(&cfg->pools);
621 delayInitDelayData(cfg->pools);
622 cfg->class = xcalloc(cfg->pools, sizeof(u_char));
623 cfg->rates = xcalloc(cfg->pools, sizeof(delaySpecSet *));
624 cfg->access = xcalloc(cfg->pools, sizeof(acl_access *));
625}
626
627static void
628parse_delay_pool_class(delayConfig * cfg)
629{
630 ushort pool, class;
631
632 parse_ushort(&pool);
633 if (pool < 1 || pool > cfg->pools) {
634 debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
635 return;
636 }
637 parse_ushort(&class);
638 if (class < 1 || class > 3) {
639 debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d class %d not in 1 .. 3\n", pool, class);
640 return;
641 }
642 pool--;
643 if (cfg->class[pool]) {
644 delayFreeDelayPool(pool);
645 safe_free(cfg->rates[pool]);
646 }
647 cfg->rates[pool] = xmalloc(class * sizeof(delaySpec));
648 cfg->class[pool] = class;
649 cfg->rates[pool]->aggregate.restore_bps = cfg->rates[pool]->aggregate.max_bytes = -1;
650 if (cfg->class[pool] >= 3)
651 cfg->rates[pool]->network.restore_bps = cfg->rates[pool]->network.max_bytes = -1;
652 if (cfg->class[pool] >= 2)
653 cfg->rates[pool]->individual.restore_bps = cfg->rates[pool]->individual.max_bytes = -1;
654 delayCreateDelayPool(pool, class);
655}
656
657static void
658parse_delay_pool_rates(delayConfig * cfg)
659{
660 ushort pool, class;
661 int i;
662 delaySpec *ptr;
663 char *token;
664
665 parse_ushort(&pool);
666 if (pool < 1 || pool > cfg->pools) {
667 debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
668 return;
669 }
670 pool--;
671 class = cfg->class[pool];
672 if (class == 0) {
673 debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d attempt to set rates with class not set\n", pool + 1);
674 return;
675 }
676 ptr = (delaySpec *) cfg->rates[pool];
677 /* read in "class" sets of restore,max pairs */
678 while (class--) {
679 token = strtok(NULL, "/");
680 if (token == NULL)
681 self_destruct();
682 if (sscanf(token, "%d", &i) != 1)
683 self_destruct();
684 ptr->restore_bps = i;
0e4e0e7d 685 i = GetInteger();
59715b38 686 ptr->max_bytes = i;
687 ptr++;
688 }
689 class = cfg->class[pool];
690 /* if class is 3, swap around network and individual */
691 if (class == 3) {
692 delaySpec tmp;
693
694 tmp = cfg->rates[pool]->individual;
695 cfg->rates[pool]->individual = cfg->rates[pool]->network;
696 cfg->rates[pool]->network = tmp;
697 }
698 /* initialize the delay pools */
699 delayInitDelayPool(pool, class, cfg->rates[pool]);
700}
701
702static void
703parse_delay_pool_access(delayConfig * cfg)
704{
705 ushort pool;
706
707 parse_ushort(&pool);
708 if (pool < 1 || pool > cfg->pools) {
709 debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
710 return;
711 }
712 aclParseAccessLine(&cfg->access[pool - 1]);
713}
714#endif
715
97474590 716static void
717dump_http_header(StoreEntry * entry, const char *name, HttpHeaderMask header)
e3dd531e 718{
efd900cb 719 int i;
720 for (i = 0; i < HDR_OTHER; i++) {
721 if (http_header_allowed && !CBIT_TEST(header, i))
722 storeAppendPrintf(entry, "%s allow %s\n", name, httpHeaderNameById(i));
723 else if (!http_header_allowed && CBIT_TEST(header, i))
724 storeAppendPrintf(entry, "%s deny %s\n", name, httpHeaderNameById(i));
725 }
97474590 726}
e3dd531e 727
97474590 728static void
729parse_http_header(HttpHeaderMask * header)
730{
731 int allowed, id;
732 char *t = NULL;
97474590 733 if ((t = strtok(NULL, w_space)) == NULL) {
734 debug(3, 0) ("%s line %d: %s\n",
735 cfg_filename, config_lineno, config_input_line);
736 debug(3, 0) ("parse_http_header: missing 'allow' or 'deny'.\n");
737 return;
738 }
739 if (!strcmp(t, "allow"))
740 allowed = 1;
741 else if (!strcmp(t, "deny"))
742 allowed = 0;
743 else {
744 debug(3, 0) ("%s line %d: %s\n",
745 cfg_filename, config_lineno, config_input_line);
746 debug(3, 0) ("parse_http_header: expecting 'allow' or 'deny', got '%s'.\n", t);
747 return;
748 }
e3dd531e 749 if (!http_header_first) {
97474590 750 http_header_first = 1;
efd900cb 751 if (allowed) {
752 http_header_allowed = 1;
97474590 753 httpHeaderMaskInit(header, 0xFF);
efd900cb 754 } else {
755 http_header_allowed = 0;
756 httpHeaderMaskInit(header, 0);
757 }
97474590 758 }
97474590 759 while ((t = strtok(NULL, w_space))) {
760 if ((id = httpHeaderIdByNameDef(t, strlen(t))) == -1)
efd900cb 761 debug(3, 0) ("parse_http_header: Ignoring unknown header '%s'\n", t);
762 else if (allowed)
97474590 763 CBIT_CLR(*header, id);
764 else
765 CBIT_SET(*header, id);
766 }
767}
e3dd531e 768
97474590 769static void
e3dd531e 770free_http_header(HttpHeaderMask * header)
771{
97474590 772 httpHeaderMaskInit(header, 0);
773}
774
e90100aa 775static void
56b63fa1 776dump_cachedir(StoreEntry * entry, const char *name, cacheSwap swap)
e90100aa 777{
f53b06f9 778 SwapDir *s;
779 int i;
a7d59104 780 for (i = 0; i < swap.n_configured; i++) {
781 s = swap.swapDirs + i;
0e4e0e7d 782 switch (s->type) {
783 case SWAPDIR_UFS:
53fa92a5 784 case SWAPDIR_ASYNCUFS:
0e4e0e7d 785 storeUfsDirDump(entry, name, s);
786 break;
787 default:
788 debug(0, 0) ("dump_cachedir doesn't know about type %d\n",
789 (int) s->type);
790 break;
791 }
f53b06f9 792 }
793}
794
795static int
56b63fa1 796check_null_cachedir(cacheSwap swap)
f53b06f9 797{
798 return swap.swapDirs == NULL;
e90100aa 799}
800
53ad48e6 801static int
802check_null_string(char *s)
803{
804 return s == NULL;
805}
806
0e4e0e7d 807void
808allocate_new_swapdir(cacheSwap * swap)
090089c4 809{
f1dc9b30 810 if (swap->swapDirs == NULL) {
811 swap->n_allocated = 4;
812 swap->swapDirs = xcalloc(swap->n_allocated, sizeof(SwapDir));
813 }
814 if (swap->n_allocated == swap->n_configured) {
0e4e0e7d 815 SwapDir *tmp;
f1dc9b30 816 swap->n_allocated <<= 1;
817 tmp = xcalloc(swap->n_allocated, sizeof(SwapDir));
818 xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir));
819 xfree(swap->swapDirs);
820 swap->swapDirs = tmp;
821 }
0e4e0e7d 822}
823
824static void
825parse_cachedir(cacheSwap * swap)
826{
827 char *type_str;
828 if ((type_str = strtok(NULL, w_space)) == NULL)
829 self_destruct();
830 if (0 == strcasecmp(type_str, "ufs")) {
831 storeUfsDirParse(swap);
1c5f4bc9 832#if USE_ASYNC_IO
53fa92a5 833 } else if (0 == strcasecmp(type_str, "asyncufs")) {
834 storeAufsDirParse(swap);
8798ad05 835#endif
836#if USE_DISKD
837 } else if (0 == strcasecmp(type_str, "diskd")) {
838 storeDiskdDirParse(swap);
1c5f4bc9 839#endif
0e4e0e7d 840 } else {
841 fatalf("Unknown cache_dir type '%s'\n", type_str);
842 }
752c3b27 843}
844
8203a132 845static void
16300b58 846free_cachedir(cacheSwap * swap)
f1dc9b30 847{
a47b9029 848 SwapDir *s;
849 int i;
860ee7e3 850 /* DON'T FREE THESE FOR RECONFIGURE */
5cd39a10 851 if (reconfiguring)
860ee7e3 852 return;
a47b9029 853 for (i = 0; i < swap->n_configured; i++) {
854 s = swap->swapDirs + i;
0e4e0e7d 855 switch (s->type) {
856 case SWAPDIR_UFS:
53fa92a5 857 case SWAPDIR_ASYNCUFS:
0e4e0e7d 858 storeUfsDirFree(s);
859 break;
860 default:
861 debug(0, 0) ("dump_cachedir doesn't know about type %d\n",
862 (int) s->type);
863 break;
f150dd4b 864 }
a47b9029 865 xfree(s->path);
866 filemapFreeMemory(s->map);
867 }
868 safe_free(swap->swapDirs);
869 swap->swapDirs = NULL;
870 swap->n_allocated = 0;
871 swap->n_configured = 0;
f1dc9b30 872}
873
505e35db 874const char *
875peer_type_str(const peer_t type)
876{
0cdcddb9 877 switch (type) {
505e35db 878 case PEER_PARENT:
879 return "parent";
880 break;
881 case PEER_SIBLING:
882 return "sibling";
883 break;
884 case PEER_MULTICAST:
885 return "multicast";
886 break;
887 default:
888 return "unknown";
889 break;
890 }
891}
892
f1dc9b30 893static void
a7d59104 894dump_peer(StoreEntry * entry, const char *name, peer * p)
98ffb7e4 895{
505e35db 896 domain_ping *d;
897 acl_access *a;
898 domain_type *t;
899 LOCAL_ARRAY(char, xname, 128);
d41de3c1 900 while (p != NULL) {
901 storeAppendPrintf(entry, "%s %s %s %d %d",
902 name,
903 p->host,
904 neighborTypeStr(p),
905 p->http_port,
399cabec 906 p->icp.port);
a369131d 907 dump_peer_options(entry, p);
b6a2f15e 908 for (d = p->peer_domain; d; d = d->next) {
505e35db 909 storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
910 p->host,
911 d->do_ping ? null_string : "!",
912 d->domain);
913 }
914 if ((a = p->access)) {
915 snprintf(xname, 128, "cache_peer_access %s", p->host);
916 dump_acl_access(entry, xname, p->access);
917 }
918 for (t = p->typelist; t; t = t->next) {
919 storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
920 p->host,
921 peer_type_str(t->type),
922 t->domain);
923 }
d41de3c1 924 p = p->next;
925 }
98ffb7e4 926}
927
8203a132 928static void
40a1495e 929parse_peer(peer ** head)
7813c6d5 930{
270b86af 931 char *token = NULL;
40a1495e 932 peer *p;
7813c6d5 933 int i;
7e3ce7b9 934 sockaddr_in_list *s;
f9e5a344 935 const char *me = null_string; /* XXX */
e13ee7ad 936 p = memAllocate(MEM_PEER);
40a1495e 937 p->http_port = CACHE_HTTP_PORT;
399cabec 938 p->icp.port = CACHE_ICP_PORT;
40a1495e 939 p->weight = 1;
dc835977 940 p->stats.logged_state = PEER_ALIVE;
e481c2dc 941 if ((token = strtok(NULL, w_space)) == NULL)
270b86af 942 self_destruct();
40a1495e 943 p->host = xstrdup(token);
e481c2dc 944 if ((token = strtok(NULL, w_space)) == NULL)
270b86af 945 self_destruct();
40a1495e 946 p->type = parseNeighborType(token);
0e4e0e7d 947 i = GetInteger();
40a1495e 948 p->http_port = (u_short) i;
0e4e0e7d 949 i = GetInteger();
399cabec 950 p->icp.port = (u_short) i;
40a1495e 951 if (strcmp(p->host, me) == 0) {
7e3ce7b9 952 for (s = Config.Sockaddr.http; s; s = s->next) {
953 if (p->http_port != ntohs(s->s.sin_port))
40a1495e 954 continue;
955 debug(15, 0) ("parse_peer: Peer looks like myself: %s %s/%d/%d\n",
399cabec 956 p->type, p->host, p->http_port, p->icp.port);
40a1495e 957 self_destruct();
958 }
959 }
270b86af 960 while ((token = strtok(NULL, w_space))) {
961 if (!strcasecmp(token, "proxy-only")) {
cd196bc8 962 p->options.proxy_only = 1;
270b86af 963 } else if (!strcasecmp(token, "no-query")) {
cd196bc8 964 p->options.no_query = 1;
8638fc66 965 } else if (!strcasecmp(token, "no-digest")) {
cd196bc8 966 p->options.no_digest = 1;
270b86af 967 } else if (!strcasecmp(token, "multicast-responder")) {
cd196bc8 968 p->options.mcast_responder = 1;
270b86af 969 } else if (!strncasecmp(token, "weight=", 7)) {
40a1495e 970 p->weight = atoi(token + 7);
0103c4c1 971 } else if (!strcasecmp(token, "closest-only")) {
cd196bc8 972 p->options.closest_only = 1;
270b86af 973 } else if (!strncasecmp(token, "ttl=", 4)) {
40a1495e 974 p->mcast.ttl = atoi(token + 4);
975 if (p->mcast.ttl < 0)
976 p->mcast.ttl = 0;
977 if (p->mcast.ttl > 128)
978 p->mcast.ttl = 128;
0103c4c1 979 } else if (!strcasecmp(token, "default")) {
cd196bc8 980 p->options.default_parent = 1;
0103c4c1 981 } else if (!strcasecmp(token, "round-robin")) {
cd196bc8 982 p->options.roundrobin = 1;
dc9d133b 983#if USE_HTCP
0103c4c1 984 } else if (!strcasecmp(token, "htcp")) {
cd196bc8 985 p->options.htcp = 1;
dc9d133b 986#endif
0103c4c1 987 } else if (!strcasecmp(token, "no-netdb-exchange")) {
cd196bc8 988 p->options.no_netdb_exchange = 1;
afd88fbe 989#if USE_CARP
990 } else if (!strncasecmp(token, "carp-load-factor=", 17)) {
991 if (p->type != PEER_PARENT)
0cdcddb9 992 debug(3, 0) ("parse_peer: Ignoring carp-load-factor for non-parent %s/%d\n", p->host, p->http_port);
993 else
994 p->carp.load_factor = atof(token + 17);
95e36d02 995#endif
996#if DELAY_POOLS
997 } else if (!strcasecmp(token, "no-delay")) {
cd196bc8 998 p->options.no_delay = 1;
afd88fbe 999#endif
c68e9c6b 1000 } else if (!strncasecmp(token, "login=", 6)) {
1001 p->login = xstrdup(token + 6);
3f62decd 1002 } else if (!strncasecmp(token, "connect-timeout=", 16)) {
1003 p->connect_timeout = atoi(token + 16);
7e3ce7b9 1004#if USE_CACHE_DIGESTS
1005 } else if (!strncasecmp(token, "digest-url=", 11)) {
1006 p->digest_url = xstrdup(token + 11);
1007#endif
987de783 1008 } else if (!strcasecmp(token, "allow-miss")) {
1009 p->options.allow_miss = 1;
270b86af 1010 } else {
40a1495e 1011 debug(3, 0) ("parse_peer: token='%s'\n", token);
270b86af 1012 self_destruct();
1013 }
1014 }
40a1495e 1015 if (p->weight < 1)
1016 p->weight = 1;
399cabec 1017 p->icp.version = ICP_VERSION_CURRENT;
98829f69 1018 p->tcp_up = PEER_TCP_MAGIC_COUNT;
eb406bb7 1019 p->test_fd = -1;
afd88fbe 1020#if USE_CARP
1021 if (p->carp.load_factor) {
e13ee7ad 1022 /* calculate this peers hash for use in CARP */
0cdcddb9 1023 p->carp.hash = 0;
1024 for (token = p->host; *token != 0; token++)
1025 p->carp.hash += (p->carp.hash << 19) + *token;
afd88fbe 1026 }
1027#endif
b6a2f15e 1028 /* This must preceed peerDigestCreate */
1029 cbdataAdd(p, peerDestroy, MEM_PEER);
e13ee7ad 1030#if USE_CACHE_DIGESTS
1031 if (!p->options.no_digest) {
1032 p->digest = peerDigestCreate(p);
8a6218c6 1033 cbdataLock(p->digest); /* so we know when/if digest disappears */
1034 }
e13ee7ad 1035#endif
0153d498 1036 while (*head != NULL)
1037 head = &(*head)->next;
1038 *head = p;
40a1495e 1039 Config.npeers++;
0153d498 1040}
1041
1042static void
40a1495e 1043free_peer(peer ** P)
0153d498 1044{
40a1495e 1045 peer *p;
79d39a72 1046 while ((p = *P) != NULL) {
a47b9029 1047 *P = p->next;
3855c318 1048#if USE_CACHE_DIGESTS
1049 if (p->digest)
1050 cbdataUnlock(p->digest);
1051 p->digest = NULL;
1052#endif
41042c81 1053 cbdataFree(p);
a47b9029 1054 }
987c67d1 1055 Config.npeers = 0;
270b86af 1056}
1057
1058static void
a7d59104 1059dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
270b86af 1060{
d41de3c1 1061 wordlist *w;
1062 while (list != NULL) {
74aa8456 1063 if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
1064 storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
1065 else
1066 storeAppendPrintf(entry, "%s %s", name, list->passwd);
d41de3c1 1067 for (w = list->actions; w != NULL; w = w->next) {
1068 storeAppendPrintf(entry, " %s", w->key);
1069 }
1070 storeAppendPrintf(entry, "\n");
1071 list = list->next;
1072 }
270b86af 1073}
1074
1075static void
a47b9029 1076parse_cachemgrpasswd(cachemgr_passwd ** head)
270b86af 1077{
1078 char *passwd = NULL;
1079 wordlist *actions = NULL;
22f3fd98 1080 cachemgr_passwd *p;
1081 cachemgr_passwd **P;
270b86af 1082 parse_string(&passwd);
1083 parse_wordlist(&actions);
22f3fd98 1084 p = xcalloc(1, sizeof(cachemgr_passwd));
1085 p->passwd = passwd;
1086 p->actions = actions;
1087 for (P = head; *P; P = &(*P)->next);
1088 *P = p;
270b86af 1089}
1090
1091static void
a47b9029 1092free_cachemgrpasswd(cachemgr_passwd ** head)
270b86af 1093{
a47b9029 1094 cachemgr_passwd *p;
79d39a72 1095 while ((p = *head) != NULL) {
a47b9029 1096 *head = p->next;
1097 xfree(p->passwd);
22f3fd98 1098 wordlistDestroy(&p->actions);
a47b9029 1099 xfree(p);
1100 }
270b86af 1101}
1102
8203a132 1103static void
16300b58 1104dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
270b86af 1105{
d41de3c1 1106 acl_name_list *a;
1107 while (var != NULL) {
02922e76 1108 storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
d41de3c1 1109 for (a = var->acl_list; a != NULL; a = a->next)
1110 storeAppendPrintf(entry, " %s", a->name);
1111 storeAppendPrintf(entry, "\n");
1112 var = var->next;
1113 }
270b86af 1114}
1115
1116static void
16300b58 1117parse_denyinfo(acl_deny_info_list ** var)
6e40f263 1118{
f1dc9b30 1119 aclParseDenyInfoLine(var);
6e40f263 1120}
403279e0 1121
1273d501 1122void
a47b9029 1123free_denyinfo(acl_deny_info_list ** list)
3c5557f9 1124{
56b63fa1 1125 acl_deny_info_list *a = NULL;
1126 acl_deny_info_list *a_next = NULL;
1127 acl_name_list *l = NULL;
1128 acl_name_list *l_next = NULL;
1273d501 1129 for (a = *list; a; a = a_next) {
a47b9029 1130 for (l = a->acl_list; l; l = l_next) {
1131 l_next = l->next;
1132 safe_free(l);
1133 }
1134 a_next = a->next;
1135 safe_free(a);
1273d501 1136 }
1137 *list = NULL;
270b86af 1138}
1139
1140static void
505e35db 1141parse_peer_access(void)
270b86af 1142{
1143 char *host = NULL;
505e35db 1144 peer *p;
270b86af 1145 if (!(host = strtok(NULL, w_space)))
1146 self_destruct();
0cdcddb9 1147 if ((p = peerFindByName(host)) == NULL) {
1148 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1149 cfg_filename, config_lineno, host);
1150 return;
1151 }
505e35db 1152 aclParseAccessLine(&p->access);
270b86af 1153}
1154
270b86af 1155static void
1156parse_hostdomain(void)
1157{
1158 char *host = NULL;
1159 char *domain = NULL;
1160 if (!(host = strtok(NULL, w_space)))
1161 self_destruct();
f1dc9b30 1162 while ((domain = strtok(NULL, list_sep))) {
1163 domain_ping *l = NULL;
1164 domain_ping **L = NULL;
40a1495e 1165 peer *p;
1166 if ((p = peerFindByName(host)) == NULL) {
43c3424b 1167 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
f1dc9b30 1168 cfg_filename, config_lineno, host);
1169 continue;
1170 }
56b63fa1 1171 l = xcalloc(1, sizeof(domain_ping));
f1dc9b30 1172 l->do_ping = 1;
1173 if (*domain == '!') { /* check for !.edu */
1174 l->do_ping = 0;
1175 domain++;
1176 }
1177 l->domain = xstrdup(domain);
b6a2f15e 1178 for (L = &(p->peer_domain); *L; L = &((*L)->next));
f1dc9b30 1179 *L = l;
1180 }
270b86af 1181}
1182
1183static void
1184parse_hostdomaintype(void)
1185{
1186 char *host = NULL;
1187 char *type = NULL;
1188 char *domain = NULL;
1189 if (!(host = strtok(NULL, w_space)))
1190 self_destruct();
1191 if (!(type = strtok(NULL, w_space)))
1192 self_destruct();
f1dc9b30 1193 while ((domain = strtok(NULL, list_sep))) {
1194 domain_type *l = NULL;
1195 domain_type **L = NULL;
40a1495e 1196 peer *p;
1197 if ((p = peerFindByName(host)) == NULL) {
43c3424b 1198 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
f1dc9b30 1199 cfg_filename, config_lineno, host);
1200 return;
1201 }
56b63fa1 1202 l = xcalloc(1, sizeof(domain_type));
f1dc9b30 1203 l->type = parseNeighborType(type);
1204 l->domain = xstrdup(domain);
1205 for (L = &(p->typelist); *L; L = &((*L)->next));
1206 *L = l;
1207 }
270b86af 1208}
1209
7e3ce7b9 1210#if UNUSED_CODE
270b86af 1211static void
a7d59104 1212dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
090089c4 1213{
270b86af 1214 while (u) {
f53b06f9 1215 storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
270b86af 1216 u = u->next;
1217 }
1218}
090089c4 1219
f53b06f9 1220static int
1221check_null_ushortlist(ushortlist * u)
1222{
1223 return u == NULL;
1224}
1225
270b86af 1226static void
1227parse_ushortlist(ushortlist ** P)
1228{
1229 char *token;
1230 int i;
1231 ushortlist *u;
1232 ushortlist **U;
1233 while ((token = strtok(NULL, w_space))) {
1234 if (sscanf(token, "%d", &i) != 1)
1235 self_destruct();
1236 if (i < 0)
1237 i = 0;
1238 u = xcalloc(1, sizeof(ushortlist));
1239 u->i = (u_short) i;
1240 for (U = P; *U; U = &(*U)->next);
1241 *U = u;
090089c4 1242 }
270b86af 1243}
090089c4 1244
0153d498 1245static void
a47b9029 1246free_ushortlist(ushortlist ** P)
0153d498 1247{
a47b9029 1248 ushortlist *u;
79d39a72 1249 while ((u = *P) != NULL) {
a47b9029 1250 *P = u->next;
1251 xfree(u);
1252 }
0153d498 1253}
7e3ce7b9 1254#endif
0153d498 1255
270b86af 1256static void
a7d59104 1257dump_int(StoreEntry * entry, const char *name, int var)
270b86af 1258{
f53b06f9 1259 storeAppendPrintf(entry, "%s %d\n", name, var);
270b86af 1260}
c1c29eb6 1261
270b86af 1262static void
1263parse_int(int *var)
1264{
270b86af 1265 int i;
0e4e0e7d 1266 i = GetInteger();
270b86af 1267 *var = i;
1268}
090089c4 1269
0153d498 1270static void
1271free_int(int *var)
1272{
a47b9029 1273 *var = 0;
0153d498 1274}
1275
270b86af 1276static void
a7d59104 1277dump_onoff(StoreEntry * entry, const char *name, int var)
270b86af 1278{
f53b06f9 1279 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
270b86af 1280}
090089c4 1281
270b86af 1282static void
1283parse_onoff(int *var)
1284{
1285 char *token = strtok(NULL, w_space);
090089c4 1286
270b86af 1287 if (token == NULL)
1288 self_destruct();
1289 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
1290 *var = 1;
1291 else
1292 *var = 0;
1293}
e90100aa 1294
0153d498 1295#define free_onoff free_int
f1dc9b30 1296#define dump_eol dump_string
1297#define free_eol free_string
30a4f2a8 1298
270b86af 1299static void
a7d59104 1300dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
270b86af 1301{
d41de3c1 1302 while (head != NULL) {
9f60cfdf 1303 storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
c3f6d204 1304 name,
1305 head->flags.icase ? " -i" : null_string,
1306 head->pattern,
1307 (int) head->min / 60,
1308 (int) (100.0 * head->pct + 0.5),
9f60cfdf 1309 (int) head->max / 60);
1310#if HTTP_VIOLATIONS
1311 if (head->flags.override_expire)
1312 storeAppendPrintf(entry, " override-expire");
1313 if (head->flags.override_lastmod)
1314 storeAppendPrintf(entry, " override-lastmod");
1315 if (head->flags.reload_into_ims)
1316 storeAppendPrintf(entry, " reload-into-ims");
1317 if (head->flags.ignore_reload)
1318 storeAppendPrintf(entry, " ignore-reload");
1319#endif
1320 storeAppendPrintf(entry, "\n");
d41de3c1 1321 head = head->next;
1322 }
270b86af 1323}
090089c4 1324
270b86af 1325static void
f1dc9b30 1326parse_refreshpattern(refresh_t ** head)
270b86af 1327{
f1dc9b30 1328 char *token;
1329 char *pattern;
1330 time_t min = 0;
c3f6d204 1331 double pct = 0.0;
f1dc9b30 1332 time_t max = 0;
9f60cfdf 1333#if HTTP_VIOLATIONS
1dfa1d81 1334 int override_expire = 0;
1335 int override_lastmod = 0;
cbe3a719 1336 int reload_into_ims = 0;
1337 int ignore_reload = 0;
9f60cfdf 1338#endif
f1dc9b30 1339 int i;
1340 refresh_t *t;
1341 regex_t comp;
1342 int errcode;
1343 int flags = REG_EXTENDED | REG_NOSUB;
1344 if ((token = strtok(NULL, w_space)) == NULL)
1345 self_destruct();
1346 if (strcmp(token, "-i") == 0) {
1347 flags |= REG_ICASE;
1348 token = strtok(NULL, w_space);
1349 } else if (strcmp(token, "+i") == 0) {
1350 flags &= ~REG_ICASE;
1351 token = strtok(NULL, w_space);
1352 }
1353 if (token == NULL)
1354 self_destruct();
1355 pattern = xstrdup(token);
0e4e0e7d 1356 i = GetInteger(); /* token: min */
f1dc9b30 1357 min = (time_t) (i * 60); /* convert minutes to seconds */
0e4e0e7d 1358 i = GetInteger(); /* token: pct */
c3f6d204 1359 pct = (double) i / 100.0;
0e4e0e7d 1360 i = GetInteger(); /* token: max */
f1dc9b30 1361 max = (time_t) (i * 60); /* convert minutes to seconds */
1dfa1d81 1362 /* Options */
1363 while ((token = strtok(NULL, w_space)) != NULL) {
9f60cfdf 1364#if HTTP_VIOLATIONS
1dfa1d81 1365 if (!strcmp(token, "override-expire"))
1366 override_expire = 1;
255d6021 1367 else if (!strcmp(token, "override-lastmod"))
1dfa1d81 1368 override_lastmod = 1;
cbe3a719 1369 else if (!strcmp(token, "reload-into-ims")) {
1370 reload_into_ims = 1;
1371 refresh_nocache_hack = 1;
1372 /* tell client_side.c that this is used */
1373 } else if (!strcmp(token, "ignore-reload")) {
1374 ignore_reload = 1;
1375 refresh_nocache_hack = 1;
1376 /* tell client_side.c that this is used */
1377 } else
9f60cfdf 1378#endif
cbe3a719 1379 debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
1dfa1d81 1380 pattern, token);
1381 }
f1dc9b30 1382 if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
1383 char errbuf[256];
1384 regerror(errcode, &comp, errbuf, sizeof errbuf);
1385 debug(22, 0) ("%s line %d: %s\n",
1386 cfg_filename, config_lineno, config_input_line);
1387 debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %s\n",
1388 pattern, errbuf);
1389 return;
1390 }
c3f6d204 1391 pct = pct < 0.0 ? 0.0 : pct;
f1dc9b30 1392 max = max < 0 ? 0 : max;
1393 t = xcalloc(1, sizeof(refresh_t));
1394 t->pattern = (char *) xstrdup(pattern);
1395 t->compiled_pattern = comp;
1396 t->min = min;
c3f6d204 1397 t->pct = pct;
f1dc9b30 1398 t->max = max;
c3f6d204 1399 if (flags & REG_ICASE)
1400 t->flags.icase = 1;
9f60cfdf 1401#if HTTP_VIOLATIONS
1dfa1d81 1402 if (override_expire)
1403 t->flags.override_expire = 1;
1404 if (override_lastmod)
1405 t->flags.override_lastmod = 1;
cbe3a719 1406 if (reload_into_ims)
1407 t->flags.reload_into_ims = 1;
1408 if (ignore_reload)
1409 t->flags.ignore_reload = 1;
9f60cfdf 1410#endif
f1dc9b30 1411 t->next = NULL;
1412 while (*head)
1413 head = &(*head)->next;
1414 *head = t;
1415 safe_free(pattern);
270b86af 1416}
090089c4 1417
270b86af 1418static void
a47b9029 1419free_refreshpattern(refresh_t ** head)
270b86af 1420{
f1dc9b30 1421 refresh_t *t;
79d39a72 1422 while ((t = *head) != NULL) {
f1dc9b30 1423 *head = t->next;
1424 safe_free(t->pattern);
1425 regfree(&t->compiled_pattern);
1426 safe_free(t);
1427 }
270b86af 1428}
12b9e9b1 1429
270b86af 1430static void
a7d59104 1431dump_string(StoreEntry * entry, const char *name, char *var)
270b86af 1432{
f53b06f9 1433 if (var != NULL)
a7d59104 1434 storeAppendPrintf(entry, "%s %s\n", name, var);
270b86af 1435}
98ffb7e4 1436
270b86af 1437static void
0153d498 1438parse_string(char **var)
270b86af 1439{
1440 char *token = strtok(NULL, w_space);
270b86af 1441 safe_free(*var);
1442 if (token == NULL)
1443 self_destruct();
1444 *var = xstrdup(token);
1445}
b15e6857 1446
0153d498 1447static void
1448free_string(char **var)
1449{
027acbaf 1450 safe_free(*var);
0153d498 1451}
caebbe00 1452
270b86af 1453static void
f1dc9b30 1454parse_eol(char *volatile *var)
270b86af 1455{
1456 char *token = strtok(NULL, null_string);
270b86af 1457 safe_free(*var);
f1dc9b30 1458 if (token == NULL)
1459 self_destruct();
270b86af 1460 *var = xstrdup(token);
1461}
090089c4 1462
270b86af 1463static void
a7d59104 1464dump_time_t(StoreEntry * entry, const char *name, time_t var)
090089c4 1465{
f53b06f9 1466 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
090089c4 1467}
1468
270b86af 1469static void
a47b9029 1470parse_time_t(time_t * var)
0ffd22bc 1471{
f1dc9b30 1472 parseTimeLine(var, T_SECOND_STR);
0ffd22bc 1473}
1474
270b86af 1475static void
a47b9029 1476free_time_t(time_t * var)
270b86af 1477{
a47b9029 1478 *var = 0;
270b86af 1479}
9906e724 1480
1481static void
a7d59104 1482dump_size_t(StoreEntry * entry, const char *name, size_t var)
1b635117 1483{
f53b06f9 1484 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
1b635117 1485}
1486
1487static void
a7d59104 1488dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
9906e724 1489{
f53b06f9 1490 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
9906e724 1491}
1492
1493static void
a7d59104 1494dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
9906e724 1495{
f53b06f9 1496 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
9906e724 1497}
1498
1499static void
a47b9029 1500parse_size_t(size_t * var)
1b635117 1501{
1b635117 1502 int i;
0e4e0e7d 1503 i = GetInteger();
1b635117 1504 *var = (size_t) i;
1505}
1506
1507static void
1508parse_b_size_t(size_t * var)
9906e724 1509{
1510 parseBytesLine(var, B_BYTES_STR);
1511}
1512
1513static void
a47b9029 1514parse_kb_size_t(size_t * var)
9906e724 1515{
1516 parseBytesLine(var, B_KBYTES_STR);
1517}
1518
1519static void
a47b9029 1520free_size_t(size_t * var)
9906e724 1521{
a47b9029 1522 *var = 0;
9906e724 1523}
1524
1b635117 1525#define free_b_size_t free_size_t
9906e724 1526#define free_kb_size_t free_size_t
1527#define free_mb_size_t free_size_t
1528#define free_gb_size_t free_size_t
090089c4 1529
8203a132 1530static void
a7d59104 1531dump_ushort(StoreEntry * entry, const char *name, u_short var)
090089c4 1532{
f53b06f9 1533 storeAppendPrintf(entry, "%s %d\n", name, var);
270b86af 1534}
090089c4 1535
0153d498 1536static void
a47b9029 1537free_ushort(u_short * u)
0153d498 1538{
1539 *u = 0;
1540}
1541
270b86af 1542static void
1543parse_ushort(u_short * var)
1544{
270b86af 1545 int i;
090089c4 1546
0e4e0e7d 1547 i = GetInteger();
270b86af 1548 if (i < 0)
1549 i = 0;
1550 *var = (u_short) i;
090089c4 1551}
1552
270b86af 1553static void
a7d59104 1554dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
270b86af 1555{
270b86af 1556 while (list != NULL) {
f53b06f9 1557 storeAppendPrintf(entry, "%s %s\n", name, list->key);
270b86af 1558 list = list->next;
429fdbec 1559 }
429fdbec 1560}
1561
270b86af 1562static void
1563parse_wordlist(wordlist ** list)
429fdbec 1564{
270b86af 1565 char *token;
270b86af 1566 while ((token = strtok(NULL, w_space)))
1567 wordlistAdd(list, token);
429fdbec 1568}
270b86af 1569
f8d9f54a 1570static int
5da06f20 1571check_null_wordlist(wordlist * w)
f8d9f54a 1572{
1573 return w == NULL;
1574}
1575
63e9d884 1576static int
c6d5b87b 1577check_null_acl_access(acl_access * a)
63e9d884 1578{
1579 return a == NULL;
1580}
1581
0153d498 1582#define free_wordlist wordlistDestroy
270b86af 1583
d548ee64 1584#define free_uri_whitespace free_int
1585
1586static void
1587parse_uri_whitespace(int *var)
1588{
1589 char *token = strtok(NULL, w_space);
1590 if (token == NULL)
1591 self_destruct();
7e3ce7b9 1592 if (!strcasecmp(token, "strip"))
1593 *var = URI_WHITESPACE_STRIP;
1594 else if (!strcasecmp(token, "deny"))
d548ee64 1595 *var = URI_WHITESPACE_DENY;
1596 else if (!strcasecmp(token, "allow"))
1597 *var = URI_WHITESPACE_ALLOW;
1598 else if (!strcasecmp(token, "encode"))
1599 *var = URI_WHITESPACE_ENCODE;
1600 else if (!strcasecmp(token, "chop"))
1601 *var = URI_WHITESPACE_CHOP;
1602 else
1603 self_destruct();
1604}
1605
1606
1607static void
1608dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
1609{
1610 char *s;
1611 if (var == URI_WHITESPACE_ALLOW)
1612 s = "allow";
1613 else if (var == URI_WHITESPACE_ENCODE)
1614 s = "encode";
1615 else if (var == URI_WHITESPACE_CHOP)
1616 s = "chop";
7e3ce7b9 1617 else if (var == URI_WHITESPACE_DENY)
d548ee64 1618 s = "deny";
7e3ce7b9 1619 else
1620 s = "strip";
d548ee64 1621 storeAppendPrintf(entry, "%s %s\n", name, s);
1622}
1623
270b86af 1624#include "cf_parser.c"
f1dc9b30 1625
1626peer_t
1627parseNeighborType(const char *s)
1628{
1629 if (!strcasecmp(s, "parent"))
1630 return PEER_PARENT;
1631 if (!strcasecmp(s, "neighbor"))
1632 return PEER_SIBLING;
1633 if (!strcasecmp(s, "neighbour"))
1634 return PEER_SIBLING;
1635 if (!strcasecmp(s, "sibling"))
1636 return PEER_SIBLING;
1637 if (!strcasecmp(s, "multicast"))
1638 return PEER_MULTICAST;
1639 debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s);
1640 return PEER_SIBLING;
1641}
f150dd4b 1642
7e3ce7b9 1643static void
1644parse_sockaddr_in_list(sockaddr_in_list ** head)
1645{
1646 char *token;
1647 char *t;
efd900cb 1648 char *host;
7e3ce7b9 1649 const struct hostent *hp;
efd900cb 1650 unsigned short port;
7e3ce7b9 1651 sockaddr_in_list *s;
1652 while ((token = strtok(NULL, w_space))) {
efd900cb 1653 host = NULL;
1654 port = 0;
7e3ce7b9 1655 if ((t = strchr(token, ':'))) {
1656 /* host:port */
1657 host = token;
1658 *t = '\0';
efd900cb 1659 port = (unsigned short) atoi(t + 1);
1660 if (0 == port)
7e3ce7b9 1661 self_destruct();
efd900cb 1662 } else if ((port = atoi(token)) > 0) {
7e3ce7b9 1663 /* port */
1664 } else {
1665 self_destruct();
1666 }
1667 s = xcalloc(1, sizeof(*s));
efd900cb 1668 s->s.sin_port = htons(port);
7e3ce7b9 1669 if (NULL == host)
1670 s->s.sin_addr = any_addr;
1671 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
1672 (void) 0;
efd900cb 1673 else if ((hp = gethostbyname(host))) /* dont use ipcache */
7e3ce7b9 1674 s->s.sin_addr = inaddrFromHostent(hp);
1675 else
1676 self_destruct();
1677 while (*head)
1678 head = &(*head)->next;
1679 *head = s;
1680 }
1681}
1682
1683static void
1684dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
1685{
1686 while (s) {
1687 storeAppendPrintf(e, "%s %s:%d\n",
1688 n,
1689 inet_ntoa(s->s.sin_addr),
1690 ntohs(s->s.sin_port));
1691 s = s->next;
1692 }
1693}
1694
1695static void
1696free_sockaddr_in_list(sockaddr_in_list ** head)
1697{
1698 sockaddr_in_list *s;
1699 while ((s = *head) != NULL) {
1700 *head = s->next;
1701 xfree(s);
1702 }
1703}
1704
1705static int
1706check_null_sockaddr_in_list(const sockaddr_in_list * s)
1707{
1708 return NULL == s;
1709}
1710
f150dd4b 1711void
1712configFreeMemory(void)
1713{
23ff6968 1714 free_all();
f150dd4b 1715}
f0b19334 1716
1717static void
1718requirePathnameExists(const char *name, const char *path)
1719{
1720 struct stat sb;
f0b19334 1721 assert(path != NULL);
137ee196 1722 if (stat(path, &sb) < 0)
1723 fatalf("%s: %s", path, xstrerror());
f0b19334 1724}