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