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