]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_cf.cc
MODIO_1 commit. This change (including documentation) implements a more
[thirdparty/squid.git] / src / cache_cf.cc
1
2 /*
3 * $Id: cache_cf.cc,v 1.343 2000/05/03 17:15:41 adrian Exp $
4 *
5 * DEBUG: section 3 Configuration File Parsing
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37
38 #if SQUID_SNMP
39 #include "snmp.h"
40 #endif
41
42 static const char *const T_SECOND_STR = "second";
43 static const char *const T_MINUTE_STR = "minute";
44 static const char *const T_HOUR_STR = "hour";
45 static const char *const T_DAY_STR = "day";
46 static const char *const T_WEEK_STR = "week";
47 static const char *const T_FORTNIGHT_STR = "fortnight";
48 static const char *const T_MONTH_STR = "month";
49 static const char *const T_YEAR_STR = "year";
50 static const char *const T_DECADE_STR = "decade";
51
52 static const char *const B_BYTES_STR = "bytes";
53 static const char *const B_KBYTES_STR = "KB";
54 static const char *const B_MBYTES_STR = "MB";
55 static const char *const B_GBYTES_STR = "GB";
56
57 static const char *const list_sep = ", \t\n\r";
58 static int http_header_first;
59 static int http_header_allowed = 0;
60
61 static void update_maxobjsize(void);
62 static void configDoConfigure(void);
63 static void parse_refreshpattern(refresh_t **);
64 static int parseTimeUnits(const char *unit);
65 static void parseTimeLine(time_t * tptr, const char *units);
66 static void parse_ushort(u_short * var);
67 static void parse_string(char **);
68 static void parse_wordlist(wordlist **);
69 static void default_all(void);
70 static void defaults_if_none(void);
71 static int parse_line(char *);
72 static void parseBytesLine(size_t * bptr, const char *units);
73 static size_t parseBytesUnits(const char *unit);
74 static void free_all(void);
75 static void requirePathnameExists(const char *name, const char *path);
76 static OBJH dump_config;
77 static void dump_http_header(StoreEntry * entry, const char *name, HttpHeaderMask header);
78 static void parse_http_header(HttpHeaderMask * header);
79 static void free_http_header(HttpHeaderMask * header);
80 static void parse_sockaddr_in_list(sockaddr_in_list **);
81 static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
82 static void free_sockaddr_in_list(sockaddr_in_list **);
83 static int check_null_sockaddr_in_list(const sockaddr_in_list *);
84
85 void
86 self_destruct(void)
87 {
88 fatalf("Bungled %s line %d: %s",
89 cfg_filename, config_lineno, config_input_line);
90 }
91
92 void
93 wordlistDestroy(wordlist ** list)
94 {
95 wordlist *w = NULL;
96 while ((w = *list) != NULL) {
97 *list = w->next;
98 safe_free(w->key);
99 memFree(w, MEM_WORDLIST);
100 }
101 *list = NULL;
102 }
103
104 const char *
105 wordlistAdd(wordlist ** list, const char *key)
106 {
107 while (*list)
108 list = &(*list)->next;
109 *list = memAllocate(MEM_WORDLIST);
110 (*list)->key = xstrdup(key);
111 (*list)->next = NULL;
112 return (*list)->key;
113 }
114
115 void
116 wordlistJoin(wordlist ** list, wordlist **wl)
117 {
118 while (*list)
119 list = &(*list)->next;
120 *list = *wl;
121 *wl = NULL;
122 }
123
124 void
125 wordlistAddWl(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 }
134 }
135
136 void
137 wordlistCat(const wordlist * w, MemBuf * mb)
138 {
139 while (NULL != w) {
140 memBufPrintf(mb, "%s\n", w->key);
141 w = w->next;
142 }
143 }
144
145 wordlist *
146 wordlistDup(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
156 void
157 intlistDestroy(intlist ** list)
158 {
159 intlist *w = NULL;
160 intlist *n = NULL;
161 for (w = *list; w; w = n) {
162 n = w->next;
163 memFree(w, MEM_INTLIST);
164 }
165 *list = NULL;
166 }
167
168 int
169 intlistFind(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
178
179 /*
180 * Use this #define in all the parse*() functions. Assumes char *token is
181 * defined
182 */
183
184 int
185 GetInteger(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 }
195
196 static void
197 update_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
209 int
210 parseConfigFile(const char *file_name)
211 {
212 FILE *fp = NULL;
213 char *token = NULL;
214 char *tmp_line;
215 int err_count = 0;
216 free_all();
217 default_all();
218 if ((fp = fopen(file_name, "r")) == NULL)
219 fatalf("Unable to open configuration file: %s: %s",
220 file_name, xstrerror());
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;
226 http_header_first = 0;
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);
236 tmp_line = xstrdup(config_input_line);
237 if (!parse_line(tmp_line)) {
238 debug(3, 0) ("parseConfigFile: line %d unrecognized: '%s'\n",
239 config_lineno,
240 config_input_line);
241 err_count++;
242 }
243 safe_free(tmp_line);
244 }
245 fclose(fp);
246 defaults_if_none();
247 configDoConfigure();
248 cachemgrRegister("config",
249 "Current Squid Configuration",
250 dump_config,
251 1, 1);
252 return err_count;
253 }
254
255 static void
256 configDoConfigure(void)
257 {
258 LOCAL_ARRAY(char, buf, BUFSIZ);
259 memset(&Config2, '\0', sizeof(SquidConfig2));
260 /* init memory as early as possible */
261 memConfigure();
262 /* Sanity checks */
263 if (Config.cacheSwap.swapDirs == NULL)
264 fatal("No cache_dir's specified in config file");
265 /* calculate Config.Swap.maxSize */
266 storeDirConfigure();
267 if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
268 fatal("cache_swap is lower than cache_mem");
269 if (Config.Announce.period > 0) {
270 Config.onoff.announce = 1;
271 } else if (Config.Announce.period < 1) {
272 Config.Announce.period = 86400 * 365; /* one year */
273 Config.onoff.announce = 0;
274 }
275 #if USE_DNSSERVERS
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",
280 Config.dnsChildren);
281 debug(3, 0) ("Setting it to the maximum (%d).\n",
282 DefaultDnsChildrenMax);
283 Config.dnsChildren = DefaultDnsChildrenMax;
284 }
285 #endif
286 if (Config.Program.redirect) {
287 if (Config.redirectChildren < 1) {
288 Config.redirectChildren = 0;
289 wordlistDestroy(&Config.Program.redirect);
290 } else if (Config.redirectChildren > DefaultRedirectChildrenMax) {
291 debug(3, 0) ("WARNING: redirect_children was set to a bad value: %d\n",
292 Config.redirectChildren);
293 debug(3, 0) ("Setting it to the maximum (%d).\n", DefaultRedirectChildrenMax);
294 Config.redirectChildren = DefaultRedirectChildrenMax;
295 }
296 }
297 if (Config.Program.authenticate) {
298 if (Config.authenticateChildren < 1) {
299 Config.authenticateChildren = 0;
300 wordlistDestroy(&Config.Program.authenticate);
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 }
308 if (Config.Accel.host) {
309 snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
310 Config2.Accel.prefix = xstrdup(buf);
311 Config2.Accel.on = 1;
312 }
313 if (Config.appendDomain)
314 if (*Config.appendDomain != '.')
315 fatal("append_domain must begin with a '.'");
316 if (Config.errHtmlText == NULL)
317 Config.errHtmlText = xstrdup(null_string);
318 storeConfigure();
319 if (Config2.Accel.on && !strcmp(Config.Accel.host, "virtual"))
320 vhost_mode = 1;
321 if (Config.Sockaddr.http == NULL)
322 fatal("No http_port specified!");
323 snprintf(ThisCache, sizeof(ThisCache), "%s:%d (%s)",
324 uniqueHostname(),
325 (int) ntohs(Config.Sockaddr.http->s.sin_port),
326 full_appname_string);
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(),
333 (int) ntohs(Config.Sockaddr.http->s.sin_port),
334 full_appname_string);
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;
341 safe_free(debug_options)
342 debug_options = xstrdup(Config.debugOptions);
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) {
348 debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
349 Config.retry.maxtries = 1;
350 }
351 #if HEAP_REPLACEMENT
352 /* The non-LRU policies do not use referenceAge */
353 #else
354 if (Config.referenceAge < 300) {
355 debug(3, 0) ("WARNING: resetting 'reference_age' to 1 week\n");
356 Config.referenceAge = 86400 * 7;
357 }
358 #endif
359 requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
360 #if USE_DNSSERVERS
361 requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
362 #endif
363 requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
364 if (Config.Program.redirect)
365 requirePathnameExists("redirect_program", Config.Program.redirect->key);
366 if (Config.Program.authenticate)
367 requirePathnameExists("authenticate_program", Config.Program.authenticate->key);
368 requirePathnameExists("Icon Directory", Config.icons.directory);
369 requirePathnameExists("Error Directory", Config.errorDirectory);
370 #if HTTP_VIOLATIONS
371 {
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 }
385 }
386 #endif
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);
392 Config.Wais.peer->host = xstrdup(Config.Wais.relayHost);
393 Config.Wais.peer->http_port = Config.Wais.relayPort;
394 }
395 if (aclPurgeMethodInUse(Config.accessList.http))
396 Config2.onoff.enable_purge = 1;
397 }
398
399 /* Parse a time specification from the config file. Store the
400 * result in 'tptr', after converting it to 'units' */
401 static void
402 parseTimeLine(time_t * tptr, const char *units)
403 {
404 char *token;
405 double d;
406 time_t m;
407 time_t u;
408 if ((u = parseTimeUnits(units)) == 0)
409 self_destruct();
410 if ((token = strtok(NULL, w_space)) == NULL)
411 self_destruct();
412 d = atof(token);
413 m = u; /* default to 'units' if none specified */
414 if (0 == d)
415 (void) 0;
416 else if ((token = strtok(NULL, w_space)) == NULL)
417 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
418 config_input_line, d, units);
419 else if ((m = parseTimeUnits(token)) == 0)
420 self_destruct();
421 *tptr = m * d / u;
422 }
423
424 static int
425 parseTimeUnits(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
449 static void
450 parseBytesLine(size_t * bptr, const char *units)
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 */
462 if (0.0 == d)
463 (void) 0;
464 else if ((token = strtok(NULL, w_space)) == NULL)
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();
469 *bptr = m * d / u;
470 }
471
472 static size_t
473 parseBytesUnits(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)))
478 return 1 << 10;
479 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
480 return 1 << 20;
481 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
482 return 1 << 30;
483 debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
484 return 0;
485 }
486
487 /*****************************************************************************
488 * Max
489 *****************************************************************************/
490
491 static void
492 dump_acl(StoreEntry * entry, const char *name, acl * ae)
493 {
494 wordlist *w;
495 wordlist *v;
496 while (ae != NULL) {
497 debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
498 v = w = aclDumpGeneric(ae);
499 while (v != NULL) {
500 debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
501 storeAppendPrintf(entry, "%s %s %s %s\n",
502 name,
503 ae->name,
504 aclTypeToStr(ae->type),
505 v->key);
506 v = v->next;
507 }
508 wordlistDestroy(&w);
509 ae = ae->next;
510 }
511 }
512
513 static void
514 parse_acl(acl ** ae)
515 {
516 aclParseAclLine(ae);
517 }
518
519 static void
520 free_acl(acl ** ae)
521 {
522 aclDestroyAcls(ae);
523 }
524
525 static void
526 dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
527 {
528 acl_list *l;
529 while (head != NULL) {
530 storeAppendPrintf(entry, "%s %s",
531 name,
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 : "!",
536 l->acl->name);
537 }
538 storeAppendPrintf(entry, "\n");
539 head = head->next;
540 }
541 }
542
543 static void
544 parse_acl_access(acl_access ** head)
545 {
546 aclParseAccessLine(head);
547 }
548
549 static void
550 free_acl_access(acl_access ** head)
551 {
552 aclDestroyAccessList(head);
553 }
554
555 static void
556 dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
557 {
558 storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
559 }
560
561 static void
562 parse_address(struct in_addr *addr)
563 {
564 const struct hostent *hp;
565 char *token = strtok(NULL, w_space);
566
567 if (token == NULL)
568 self_destruct();
569 if (safe_inet_addr(token, addr) == 1)
570 (void) 0;
571 else if ((hp = gethostbyname(token))) /* dont use ipcache */
572 *addr = inaddrFromHostent(hp);
573 else
574 self_destruct();
575 }
576
577 static void
578 free_address(struct in_addr *addr)
579 {
580 memset(addr, '\0', sizeof(struct in_addr));
581 }
582
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
595 static void
596 free_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
616 static void
617 dump_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
648 static void
649 parse_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
662 static void
663 parse_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
692 static void
693 parse_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;
720 i = GetInteger();
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
737 static void
738 parse_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
751 static void
752 dump_http_header(StoreEntry * entry, const char *name, HttpHeaderMask header)
753 {
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 }
761 }
762
763 static void
764 parse_http_header(HttpHeaderMask * header)
765 {
766 int allowed, id;
767 char *t = NULL;
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 }
784 if (!http_header_first) {
785 http_header_first = 1;
786 if (allowed) {
787 http_header_allowed = 1;
788 httpHeaderMaskInit(header, 0xFF);
789 } else {
790 http_header_allowed = 0;
791 httpHeaderMaskInit(header, 0);
792 }
793 }
794 while ((t = strtok(NULL, w_space))) {
795 if ((id = httpHeaderIdByNameDef(t, strlen(t))) == -1)
796 debug(3, 0) ("parse_http_header: Ignoring unknown header '%s'\n", t);
797 else if (allowed)
798 CBIT_CLR(*header, id);
799 else
800 CBIT_SET(*header, id);
801 }
802 }
803
804 static void
805 free_http_header(HttpHeaderMask * header)
806 {
807 httpHeaderMaskInit(header, 0);
808 }
809
810 static void
811 dump_cachedir(StoreEntry * entry, const char *name, cacheSwap swap)
812 {
813 SwapDir *s;
814 int i;
815 for (i = 0; i < swap.n_configured; i++) {
816 s = swap.swapDirs + i;
817 s->dump(entry, name, s);
818 }
819 }
820
821 static int
822 check_null_cachedir(cacheSwap swap)
823 {
824 return swap.swapDirs == NULL;
825 }
826
827 static int
828 check_null_string(char *s)
829 {
830 return s == NULL;
831 }
832
833 void
834 allocate_new_swapdir(cacheSwap * swap)
835 {
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) {
841 SwapDir *tmp;
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 }
848 }
849
850 static int
851 find_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
862 static void
863 parse_cachedir(cacheSwap * swap)
864 {
865 char *type_str;
866 char *path_str;
867 SwapDir *sd;
868 int i;
869 int fs;
870 size_t maxobjsize;
871
872 if ((type_str = strtok(NULL, w_space)) == NULL)
873 self_destruct();
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);
917 }
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();
928 }
929
930 static void
931 free_cachedir(cacheSwap * swap)
932 {
933 SwapDir *s;
934 int i;
935 /* DON'T FREE THESE FOR RECONFIGURE */
936 if (reconfiguring)
937 return;
938 for (i = 0; i < swap->n_configured; i++) {
939 s = swap->swapDirs + i;
940 s->freefs(s);
941 xfree(s->path);
942 }
943 safe_free(swap->swapDirs);
944 swap->swapDirs = NULL;
945 swap->n_allocated = 0;
946 swap->n_configured = 0;
947 }
948
949 const char *
950 peer_type_str(const peer_t type)
951 {
952 switch (type) {
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
968 static void
969 dump_peer(StoreEntry * entry, const char *name, peer * p)
970 {
971 domain_ping *d;
972 acl_access *a;
973 domain_type *t;
974 LOCAL_ARRAY(char, xname, 128);
975 while (p != NULL) {
976 storeAppendPrintf(entry, "%s %s %s %d %d",
977 name,
978 p->host,
979 neighborTypeStr(p),
980 p->http_port,
981 p->icp.port);
982 dump_peer_options(entry, p);
983 for (d = p->peer_domain; d; d = d->next) {
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 }
999 p = p->next;
1000 }
1001 }
1002
1003 static void
1004 parse_peer(peer ** head)
1005 {
1006 char *token = NULL;
1007 peer *p;
1008 int i;
1009 sockaddr_in_list *s;
1010 const char *me = null_string; /* XXX */
1011 p = memAllocate(MEM_PEER);
1012 p->http_port = CACHE_HTTP_PORT;
1013 p->icp.port = CACHE_ICP_PORT;
1014 p->weight = 1;
1015 p->stats.logged_state = PEER_ALIVE;
1016 if ((token = strtok(NULL, w_space)) == NULL)
1017 self_destruct();
1018 p->host = xstrdup(token);
1019 if ((token = strtok(NULL, w_space)) == NULL)
1020 self_destruct();
1021 p->type = parseNeighborType(token);
1022 i = GetInteger();
1023 p->http_port = (u_short) i;
1024 i = GetInteger();
1025 p->icp.port = (u_short) i;
1026 if (strcmp(p->host, me) == 0) {
1027 for (s = Config.Sockaddr.http; s; s = s->next) {
1028 if (p->http_port != ntohs(s->s.sin_port))
1029 continue;
1030 debug(15, 0) ("parse_peer: Peer looks like myself: %s %s/%d/%d\n",
1031 p->type, p->host, p->http_port, p->icp.port);
1032 self_destruct();
1033 }
1034 }
1035 while ((token = strtok(NULL, w_space))) {
1036 if (!strcasecmp(token, "proxy-only")) {
1037 p->options.proxy_only = 1;
1038 } else if (!strcasecmp(token, "no-query")) {
1039 p->options.no_query = 1;
1040 } else if (!strcasecmp(token, "no-digest")) {
1041 p->options.no_digest = 1;
1042 } else if (!strcasecmp(token, "multicast-responder")) {
1043 p->options.mcast_responder = 1;
1044 } else if (!strncasecmp(token, "weight=", 7)) {
1045 p->weight = atoi(token + 7);
1046 } else if (!strcasecmp(token, "closest-only")) {
1047 p->options.closest_only = 1;
1048 } else if (!strncasecmp(token, "ttl=", 4)) {
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;
1054 } else if (!strcasecmp(token, "default")) {
1055 p->options.default_parent = 1;
1056 } else if (!strcasecmp(token, "round-robin")) {
1057 p->options.roundrobin = 1;
1058 #if USE_HTCP
1059 } else if (!strcasecmp(token, "htcp")) {
1060 p->options.htcp = 1;
1061 #endif
1062 } else if (!strcasecmp(token, "no-netdb-exchange")) {
1063 p->options.no_netdb_exchange = 1;
1064 #if USE_CARP
1065 } else if (!strncasecmp(token, "carp-load-factor=", 17)) {
1066 if (p->type != PEER_PARENT)
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);
1070 #endif
1071 #if DELAY_POOLS
1072 } else if (!strcasecmp(token, "no-delay")) {
1073 p->options.no_delay = 1;
1074 #endif
1075 } else if (!strncasecmp(token, "login=", 6)) {
1076 p->login = xstrdup(token + 6);
1077 } else if (!strncasecmp(token, "connect-timeout=", 16)) {
1078 p->connect_timeout = atoi(token + 16);
1079 #if USE_CACHE_DIGESTS
1080 } else if (!strncasecmp(token, "digest-url=", 11)) {
1081 p->digest_url = xstrdup(token + 11);
1082 #endif
1083 } else if (!strcasecmp(token, "allow-miss")) {
1084 p->options.allow_miss = 1;
1085 } else {
1086 debug(3, 0) ("parse_peer: token='%s'\n", token);
1087 self_destruct();
1088 }
1089 }
1090 if (p->weight < 1)
1091 p->weight = 1;
1092 p->icp.version = ICP_VERSION_CURRENT;
1093 p->tcp_up = PEER_TCP_MAGIC_COUNT;
1094 p->test_fd = -1;
1095 #if USE_CARP
1096 if (p->carp.load_factor) {
1097 /* calculate this peers hash for use in CARP */
1098 p->carp.hash = 0;
1099 for (token = p->host; *token != 0; token++)
1100 p->carp.hash += (p->carp.hash << 19) + *token;
1101 }
1102 #endif
1103 /* This must preceed peerDigestCreate */
1104 cbdataAdd(p, peerDestroy, MEM_PEER);
1105 #if USE_CACHE_DIGESTS
1106 if (!p->options.no_digest) {
1107 p->digest = peerDigestCreate(p);
1108 cbdataLock(p->digest); /* so we know when/if digest disappears */
1109 }
1110 #endif
1111 while (*head != NULL)
1112 head = &(*head)->next;
1113 *head = p;
1114 Config.npeers++;
1115 peerClearRR(p);
1116 }
1117
1118 static void
1119 free_peer(peer ** P)
1120 {
1121 peer *p;
1122 while ((p = *P) != NULL) {
1123 *P = p->next;
1124 #if USE_CACHE_DIGESTS
1125 if (p->digest)
1126 cbdataUnlock(p->digest);
1127 p->digest = NULL;
1128 #endif
1129 cbdataFree(p);
1130 }
1131 Config.npeers = 0;
1132 }
1133
1134 static void
1135 dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
1136 {
1137 wordlist *w;
1138 while (list != NULL) {
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);
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 }
1149 }
1150
1151 static void
1152 parse_cachemgrpasswd(cachemgr_passwd ** head)
1153 {
1154 char *passwd = NULL;
1155 wordlist *actions = NULL;
1156 cachemgr_passwd *p;
1157 cachemgr_passwd **P;
1158 parse_string(&passwd);
1159 parse_wordlist(&actions);
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;
1165 }
1166
1167 static void
1168 free_cachemgrpasswd(cachemgr_passwd ** head)
1169 {
1170 cachemgr_passwd *p;
1171 while ((p = *head) != NULL) {
1172 *head = p->next;
1173 xfree(p->passwd);
1174 wordlistDestroy(&p->actions);
1175 xfree(p);
1176 }
1177 }
1178
1179 static void
1180 dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
1181 {
1182 acl_name_list *a;
1183 while (var != NULL) {
1184 storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
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 }
1190 }
1191
1192 static void
1193 parse_denyinfo(acl_deny_info_list ** var)
1194 {
1195 aclParseDenyInfoLine(var);
1196 }
1197
1198 void
1199 free_denyinfo(acl_deny_info_list ** list)
1200 {
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;
1205 for (a = *list; a; a = a_next) {
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);
1212 }
1213 *list = NULL;
1214 }
1215
1216 static void
1217 parse_peer_access(void)
1218 {
1219 char *host = NULL;
1220 peer *p;
1221 if (!(host = strtok(NULL, w_space)))
1222 self_destruct();
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 }
1228 aclParseAccessLine(&p->access);
1229 }
1230
1231 static void
1232 parse_hostdomain(void)
1233 {
1234 char *host = NULL;
1235 char *domain = NULL;
1236 if (!(host = strtok(NULL, w_space)))
1237 self_destruct();
1238 while ((domain = strtok(NULL, list_sep))) {
1239 domain_ping *l = NULL;
1240 domain_ping **L = NULL;
1241 peer *p;
1242 if ((p = peerFindByName(host)) == NULL) {
1243 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1244 cfg_filename, config_lineno, host);
1245 continue;
1246 }
1247 l = xcalloc(1, sizeof(domain_ping));
1248 l->do_ping = 1;
1249 if (*domain == '!') { /* check for !.edu */
1250 l->do_ping = 0;
1251 domain++;
1252 }
1253 l->domain = xstrdup(domain);
1254 for (L = &(p->peer_domain); *L; L = &((*L)->next));
1255 *L = l;
1256 }
1257 }
1258
1259 static void
1260 parse_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();
1269 while ((domain = strtok(NULL, list_sep))) {
1270 domain_type *l = NULL;
1271 domain_type **L = NULL;
1272 peer *p;
1273 if ((p = peerFindByName(host)) == NULL) {
1274 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1275 cfg_filename, config_lineno, host);
1276 return;
1277 }
1278 l = xcalloc(1, sizeof(domain_type));
1279 l->type = parseNeighborType(type);
1280 l->domain = xstrdup(domain);
1281 for (L = &(p->typelist); *L; L = &((*L)->next));
1282 *L = l;
1283 }
1284 }
1285
1286 #if UNUSED_CODE
1287 static void
1288 dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
1289 {
1290 while (u) {
1291 storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
1292 u = u->next;
1293 }
1294 }
1295
1296 static int
1297 check_null_ushortlist(ushortlist * u)
1298 {
1299 return u == NULL;
1300 }
1301
1302 static void
1303 parse_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;
1318 }
1319 }
1320
1321 static void
1322 free_ushortlist(ushortlist ** P)
1323 {
1324 ushortlist *u;
1325 while ((u = *P) != NULL) {
1326 *P = u->next;
1327 xfree(u);
1328 }
1329 }
1330 #endif
1331
1332 static void
1333 dump_int(StoreEntry * entry, const char *name, int var)
1334 {
1335 storeAppendPrintf(entry, "%s %d\n", name, var);
1336 }
1337
1338 static void
1339 parse_int(int *var)
1340 {
1341 int i;
1342 i = GetInteger();
1343 *var = i;
1344 }
1345
1346 static void
1347 free_int(int *var)
1348 {
1349 *var = 0;
1350 }
1351
1352 static void
1353 dump_onoff(StoreEntry * entry, const char *name, int var)
1354 {
1355 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
1356 }
1357
1358 static void
1359 parse_onoff(int *var)
1360 {
1361 char *token = strtok(NULL, w_space);
1362
1363 if (token == NULL)
1364 self_destruct();
1365 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
1366 *var = 1;
1367 else
1368 *var = 0;
1369 }
1370
1371 #define free_onoff free_int
1372 #define dump_eol dump_string
1373 #define free_eol free_string
1374
1375 static void
1376 dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
1377 {
1378 while (head != NULL) {
1379 storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
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),
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");
1397 head = head->next;
1398 }
1399 }
1400
1401 static void
1402 parse_refreshpattern(refresh_t ** head)
1403 {
1404 char *token;
1405 char *pattern;
1406 time_t min = 0;
1407 double pct = 0.0;
1408 time_t max = 0;
1409 #if HTTP_VIOLATIONS
1410 int override_expire = 0;
1411 int override_lastmod = 0;
1412 int reload_into_ims = 0;
1413 int ignore_reload = 0;
1414 #endif
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);
1432 i = GetInteger(); /* token: min */
1433 min = (time_t) (i * 60); /* convert minutes to seconds */
1434 i = GetInteger(); /* token: pct */
1435 pct = (double) i / 100.0;
1436 i = GetInteger(); /* token: max */
1437 max = (time_t) (i * 60); /* convert minutes to seconds */
1438 /* Options */
1439 while ((token = strtok(NULL, w_space)) != NULL) {
1440 #if HTTP_VIOLATIONS
1441 if (!strcmp(token, "override-expire"))
1442 override_expire = 1;
1443 else if (!strcmp(token, "override-lastmod"))
1444 override_lastmod = 1;
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
1454 #endif
1455 debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
1456 pattern, token);
1457 }
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 }
1467 pct = pct < 0.0 ? 0.0 : pct;
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;
1473 t->pct = pct;
1474 t->max = max;
1475 if (flags & REG_ICASE)
1476 t->flags.icase = 1;
1477 #if HTTP_VIOLATIONS
1478 if (override_expire)
1479 t->flags.override_expire = 1;
1480 if (override_lastmod)
1481 t->flags.override_lastmod = 1;
1482 if (reload_into_ims)
1483 t->flags.reload_into_ims = 1;
1484 if (ignore_reload)
1485 t->flags.ignore_reload = 1;
1486 #endif
1487 t->next = NULL;
1488 while (*head)
1489 head = &(*head)->next;
1490 *head = t;
1491 safe_free(pattern);
1492 }
1493
1494 static int
1495 check_null_refreshpattern(refresh_t *data)
1496 {
1497 return data != NULL;
1498 }
1499
1500 static void
1501 free_refreshpattern(refresh_t ** head)
1502 {
1503 refresh_t *t;
1504 while ((t = *head) != NULL) {
1505 *head = t->next;
1506 safe_free(t->pattern);
1507 regfree(&t->compiled_pattern);
1508 safe_free(t);
1509 }
1510 }
1511
1512 static void
1513 dump_string(StoreEntry * entry, const char *name, char *var)
1514 {
1515 if (var != NULL)
1516 storeAppendPrintf(entry, "%s %s\n", name, var);
1517 }
1518
1519 static void
1520 parse_string(char **var)
1521 {
1522 char *token = strtok(NULL, w_space);
1523 safe_free(*var);
1524 if (token == NULL)
1525 self_destruct();
1526 *var = xstrdup(token);
1527 }
1528
1529 static void
1530 free_string(char **var)
1531 {
1532 safe_free(*var);
1533 }
1534
1535 static void
1536 parse_eol(char *volatile *var)
1537 {
1538 char *token = strtok(NULL, null_string);
1539 safe_free(*var);
1540 if (token == NULL)
1541 self_destruct();
1542 *var = xstrdup(token);
1543 }
1544
1545 static void
1546 dump_time_t(StoreEntry * entry, const char *name, time_t var)
1547 {
1548 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
1549 }
1550
1551 static void
1552 parse_time_t(time_t * var)
1553 {
1554 parseTimeLine(var, T_SECOND_STR);
1555 }
1556
1557 static void
1558 free_time_t(time_t * var)
1559 {
1560 *var = 0;
1561 }
1562
1563 static void
1564 dump_size_t(StoreEntry * entry, const char *name, size_t var)
1565 {
1566 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
1567 }
1568
1569 static void
1570 dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
1571 {
1572 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
1573 }
1574
1575 static void
1576 dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
1577 {
1578 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
1579 }
1580
1581 static void
1582 parse_size_t(size_t * var)
1583 {
1584 int i;
1585 i = GetInteger();
1586 *var = (size_t) i;
1587 }
1588
1589 static void
1590 parse_b_size_t(size_t * var)
1591 {
1592 parseBytesLine(var, B_BYTES_STR);
1593 }
1594
1595 static void
1596 parse_kb_size_t(size_t * var)
1597 {
1598 parseBytesLine(var, B_KBYTES_STR);
1599 }
1600
1601 static void
1602 free_size_t(size_t * var)
1603 {
1604 *var = 0;
1605 }
1606
1607 #define free_b_size_t free_size_t
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
1611
1612 static void
1613 dump_ushort(StoreEntry * entry, const char *name, u_short var)
1614 {
1615 storeAppendPrintf(entry, "%s %d\n", name, var);
1616 }
1617
1618 static void
1619 free_ushort(u_short * u)
1620 {
1621 *u = 0;
1622 }
1623
1624 static void
1625 parse_ushort(u_short * var)
1626 {
1627 int i;
1628
1629 i = GetInteger();
1630 if (i < 0)
1631 i = 0;
1632 *var = (u_short) i;
1633 }
1634
1635 static void
1636 dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
1637 {
1638 while (list != NULL) {
1639 storeAppendPrintf(entry, "%s %s\n", name, list->key);
1640 list = list->next;
1641 }
1642 }
1643
1644 static void
1645 parse_wordlist(wordlist ** list)
1646 {
1647 char *token;
1648 while ((token = strtok(NULL, w_space)))
1649 wordlistAdd(list, token);
1650 }
1651
1652 static int
1653 check_null_wordlist(wordlist * w)
1654 {
1655 return w == NULL;
1656 }
1657
1658 static int
1659 check_null_acl_access(acl_access * a)
1660 {
1661 return a == NULL;
1662 }
1663
1664 #define free_wordlist wordlistDestroy
1665
1666 #define free_uri_whitespace free_int
1667
1668 static void
1669 parse_uri_whitespace(int *var)
1670 {
1671 char *token = strtok(NULL, w_space);
1672 if (token == NULL)
1673 self_destruct();
1674 if (!strcasecmp(token, "strip"))
1675 *var = URI_WHITESPACE_STRIP;
1676 else if (!strcasecmp(token, "deny"))
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
1689 static void
1690 dump_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";
1699 else if (var == URI_WHITESPACE_DENY)
1700 s = "deny";
1701 else
1702 s = "strip";
1703 storeAppendPrintf(entry, "%s %s\n", name, s);
1704 }
1705
1706 #include "cf_parser.c"
1707
1708 peer_t
1709 parseNeighborType(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 }
1724
1725 static void
1726 parse_sockaddr_in_list(sockaddr_in_list ** head)
1727 {
1728 char *token;
1729 char *t;
1730 char *host;
1731 const struct hostent *hp;
1732 unsigned short port;
1733 sockaddr_in_list *s;
1734 while ((token = strtok(NULL, w_space))) {
1735 host = NULL;
1736 port = 0;
1737 if ((t = strchr(token, ':'))) {
1738 /* host:port */
1739 host = token;
1740 *t = '\0';
1741 port = (unsigned short) atoi(t + 1);
1742 if (0 == port)
1743 self_destruct();
1744 } else if ((port = atoi(token)) > 0) {
1745 /* port */
1746 } else {
1747 self_destruct();
1748 }
1749 s = xcalloc(1, sizeof(*s));
1750 s->s.sin_port = htons(port);
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;
1755 else if ((hp = gethostbyname(host))) /* dont use ipcache */
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
1765 static void
1766 dump_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
1777 static void
1778 free_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
1787 static int
1788 check_null_sockaddr_in_list(const sockaddr_in_list * s)
1789 {
1790 return NULL == s;
1791 }
1792
1793 void
1794 configFreeMemory(void)
1795 {
1796 free_all();
1797 }
1798
1799 static void
1800 requirePathnameExists(const char *name, const char *path)
1801 {
1802 struct stat sb;
1803 assert(path != NULL);
1804 if (stat(path, &sb) < 0)
1805 fatalf("%s: %s", path, xstrerror());
1806 }