]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cache_cf.cc
Unwrap globals.h
[thirdparty/squid.git] / src / cache_cf.cc
CommitLineData
be335c22 1
30a4f2a8 2/*
1ee67578 3 * $Id: cache_cf.cc,v 1.390 2001/08/23 13:20:46 robertc Exp $
30a4f2a8 4 *
5 * DEBUG: section 3 Configuration File Parsing
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see 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";
b0e7d2d5 58
14f13894 59static void parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring);
60static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd);
61static void parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring);
62static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd);
b0e7d2d5 63static struct cache_dir_option common_cachedir_options[] =
64{
65 {"read-only", parse_cachedir_option_readonly, dump_cachedir_option_readonly},
66 {"max-size", parse_cachedir_option_maxsize, dump_cachedir_option_maxsize},
67 {NULL, NULL}
68};
69
97474590 70
cd748f27 71static void update_maxobjsize(void);
f5b8bbc4 72static void configDoConfigure(void);
73static void parse_refreshpattern(refresh_t **);
74static int parseTimeUnits(const char *unit);
75static void parseTimeLine(time_t * tptr, const char *units);
59715b38 76static void parse_ushort(u_short * var);
f5b8bbc4 77static void parse_string(char **);
94439e4e 78void parse_wordlist(wordlist **);
f5b8bbc4 79static void default_all(void);
80static void defaults_if_none(void);
81static int parse_line(char *);
82static void parseBytesLine(size_t * bptr, const char *units);
83static size_t parseBytesUnits(const char *unit);
f5b8bbc4 84static void free_all(void);
94439e4e 85void requirePathnameExists(const char *name, const char *path);
ed7f5615 86static OBJH dump_config;
6bccf575 87static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
88static void parse_http_header_access(header_mangler header[]);
89static void free_http_header_access(header_mangler header[]);
90static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
91static void parse_http_header_replace(header_mangler * header);
92static void free_http_header_replace(header_mangler * header);
93static void parse_denyinfo(acl_deny_info_list ** var);
94static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
95static void free_denyinfo(acl_deny_info_list ** var);
7e3ce7b9 96static void parse_sockaddr_in_list(sockaddr_in_list **);
97static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
98static void free_sockaddr_in_list(sockaddr_in_list **);
99static int check_null_sockaddr_in_list(const sockaddr_in_list *);
d193a436 100#if USE_SSL
101static void parse_https_port_list(https_port_list **);
102static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
103static void free_https_port_list(https_port_list **);
104#if 0
105static int check_null_https_port_list(const https_port_list *);
106#endif
107#endif /* USE_SSL */
270b86af 108
0e4e0e7d 109void
0673c0ba 110self_destruct(void)
090089c4 111{
137ee196 112 fatalf("Bungled %s line %d: %s",
b8de7ebe 113 cfg_filename, config_lineno, config_input_line);
090089c4 114}
115
8203a132 116void
117wordlistDestroy(wordlist ** list)
0ffd22bc 118{
119 wordlist *w = NULL;
79d39a72 120 while ((w = *list) != NULL) {
b5639035 121 *list = w->next;
0ffd22bc 122 safe_free(w->key);
db1cd23c 123 memFree(w, MEM_WORDLIST);
0ffd22bc 124 }
125 *list = NULL;
126}
127
858783c9 128const char *
fe4e214f 129wordlistAdd(wordlist ** list, const char *key)
090089c4 130{
c68e9c6b 131 while (*list)
132 list = &(*list)->next;
133 *list = memAllocate(MEM_WORDLIST);
134 (*list)->key = xstrdup(key);
135 (*list)->next = NULL;
858783c9 136 return (*list)->key;
137}
138
139void
a4b8110e 140wordlistJoin(wordlist ** list, wordlist ** wl)
858783c9 141{
142 while (*list)
143 list = &(*list)->next;
144 *list = *wl;
145 *wl = NULL;
146}
147
148void
a4b8110e 149wordlistAddWl(wordlist ** list, wordlist * wl)
858783c9 150{
151 while (*list)
152 list = &(*list)->next;
a4b8110e 153 for (; wl; wl = wl->next, list = &(*list)->next) {
858783c9 154 *list = memAllocate(MEM_WORDLIST);
155 (*list)->key = xstrdup(wl->key);
a4b8110e 156 (*list)->next = NULL;
858783c9 157 }
090089c4 158}
159
137ee196 160void
eeb423fb 161wordlistCat(const wordlist * w, MemBuf * mb)
5da06f20 162{
5da06f20 163 while (NULL != w) {
137ee196 164 memBufPrintf(mb, "%s\n", w->key);
5da06f20 165 w = w->next;
166 }
5da06f20 167}
168
6b8e7481 169wordlist *
170wordlistDup(const wordlist * w)
171{
172 wordlist *D = NULL;
173 while (NULL != w) {
174 wordlistAdd(&D, w->key);
175 w = w->next;
176 }
177 return D;
178}
179
8203a132 180void
181intlistDestroy(intlist ** list)
92a6f4b1 182{
183 intlist *w = NULL;
184 intlist *n = NULL;
92a6f4b1 185 for (w = *list; w; w = n) {
186 n = w->next;
db1cd23c 187 memFree(w, MEM_INTLIST);
92a6f4b1 188 }
189 *list = NULL;
190}
191
5db53b8f 192int
193intlistFind(intlist * list, int i)
194{
195 intlist *w = NULL;
196 for (w = list; w; w = w->next)
197 if (w->i == i)
198 return 1;
199 return 0;
200}
201
403279e0 202
3c5557f9 203/*
204 * Use this #define in all the parse*() functions. Assumes char *token is
205 * defined
206 */
090089c4 207
0e4e0e7d 208int
209GetInteger(void)
210{
211 char *token = strtok(NULL, w_space);
212 int i;
213 if (token == NULL)
214 self_destruct();
215 if (sscanf(token, "%d", &i) != 1)
216 self_destruct();
217 return i;
218}
090089c4 219
cd748f27 220static void
221update_maxobjsize(void)
222{
223 int i;
e8dbac8b 224 ssize_t ms = -1;
cd748f27 225
226 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
a4b8110e 227 if (Config.cacheSwap.swapDirs[i].max_objsize > ms)
228 ms = Config.cacheSwap.swapDirs[i].max_objsize;
cd748f27 229 }
230 store_maxobjsize = ms;
231}
232
270b86af 233int
234parseConfigFile(const char *file_name)
2546fcb3 235{
270b86af 236 FILE *fp = NULL;
237 char *token = NULL;
72121e8b 238 char *tmp_line;
e13ee7ad 239 int err_count = 0;
42bf7c64 240 configFreeMemory();
0153d498 241 default_all();
137ee196 242 if ((fp = fopen(file_name, "r")) == NULL)
243 fatalf("Unable to open configuration file: %s: %s",
270b86af 244 file_name, xstrerror());
c4aefe96 245#if defined(_SQUID_CYGWIN_)
246 setmode(fileno(fp), O_TEXT);
247#endif
270b86af 248 cfg_filename = file_name;
249 if ((token = strrchr(cfg_filename, '/')))
250 cfg_filename = token + 1;
251 memset(config_input_line, '\0', BUFSIZ);
252 config_lineno = 0;
253 while (fgets(config_input_line, BUFSIZ, fp)) {
254 config_lineno++;
255 if ((token = strchr(config_input_line, '\n')))
256 *token = '\0';
257 if (config_input_line[0] == '#')
258 continue;
259 if (config_input_line[0] == '\0')
260 continue;
261 debug(3, 5) ("Processing: '%s'\n", config_input_line);
72121e8b 262 tmp_line = xstrdup(config_input_line);
270b86af 263 if (!parse_line(tmp_line)) {
264 debug(3, 0) ("parseConfigFile: line %d unrecognized: '%s'\n",
265 config_lineno,
266 config_input_line);
e13ee7ad 267 err_count++;
270b86af 268 }
72121e8b 269 safe_free(tmp_line);
270b86af 270 }
f0b19334 271 fclose(fp);
272 defaults_if_none();
273 configDoConfigure();
22f3fd98 274 cachemgrRegister("config",
275 "Current Squid Configuration",
276 dump_config,
1da3b90b 277 1, 1);
e13ee7ad 278 return err_count;
f0b19334 279}
270b86af 280
f0b19334 281static void
282configDoConfigure(void)
283{
284 LOCAL_ARRAY(char, buf, BUFSIZ);
285 memset(&Config2, '\0', sizeof(SquidConfig2));
7021844c 286 /* init memory as early as possible */
287 memConfigure();
270b86af 288 /* Sanity checks */
a95856a0 289 if (Config.cacheSwap.swapDirs == NULL)
290 fatal("No cache_dir's specified in config file");
9fa8263f 291 /* calculate Config.Swap.maxSize */
f4e3fa54 292 storeDirConfigure();
82e2afd9 293 if (0 == Config.Swap.maxSize)
294 /* people might want a zero-sized cache on purpose */
295 (void) 0;
296 else if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
92b5d5b7 297 debug(3, 0) ("WARNING cache_mem is larger than total disk cache space!\n");
84f42bac 298 if (Config.Announce.period > 0) {
299 Config.onoff.announce = 1;
300 } else if (Config.Announce.period < 1) {
f1dc9b30 301 Config.Announce.period = 86400 * 365; /* one year */
17a0a4ee 302 Config.onoff.announce = 0;
270b86af 303 }
6b53c392 304#if USE_DNSSERVERS
f0b19334 305 if (Config.dnsChildren < 1)
306 fatal("No dnsservers allocated");
efd900cb 307#endif
270b86af 308 if (Config.Program.redirect) {
309 if (Config.redirectChildren < 1) {
310 Config.redirectChildren = 0;
c6d5b87b 311 wordlistDestroy(&Config.Program.redirect);
270b86af 312 }
fea2e6e0 313 }
f1dc9b30 314 if (Config.Accel.host) {
a47b9029 315 snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
316 Config2.Accel.prefix = xstrdup(buf);
317 Config2.Accel.on = 1;
f1dc9b30 318 }
319 if (Config.appendDomain)
320 if (*Config.appendDomain != '.')
321 fatal("append_domain must begin with a '.'");
270b86af 322 if (Config.errHtmlText == NULL)
323 Config.errHtmlText = xstrdup(null_string);
324 storeConfigure();
42b51993 325 if (Config2.Accel.on && !strcmp(Config.Accel.host, "virtual")) {
270b86af 326 vhost_mode = 1;
42b51993 327 if (Config.Accel.port == 0)
328 vport_mode = 1;
329 }
7e3ce7b9 330 if (Config.Sockaddr.http == NULL)
270b86af 331 fatal("No http_port specified!");
137ee196 332 snprintf(ThisCache, sizeof(ThisCache), "%s:%d (%s)",
98829f69 333 uniqueHostname(),
7e3ce7b9 334 (int) ntohs(Config.Sockaddr.http->s.sin_port),
137ee196 335 full_appname_string);
38a6c74e 336 /*
337 * the extra space is for loop detection in client_side.c -- we search
338 * for substrings in the Via header.
339 */
340 snprintf(ThisCache2, sizeof(ThisCache), " %s:%d (%s)",
341 uniqueHostname(),
7e3ce7b9 342 (int) ntohs(Config.Sockaddr.http->s.sin_port),
38a6c74e 343 full_appname_string);
270b86af 344 if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
345 Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
346 if (Config.appendDomain)
347 Config.appendDomainLen = strlen(Config.appendDomain);
348 else
349 Config.appendDomainLen = 0;
f1dc9b30 350 safe_free(debug_options)
351 debug_options = xstrdup(Config.debugOptions);
22c653cd 352 if (Config.retry.timeout < 5)
353 fatal("minimum_retry_timeout must be at least 5 seconds");
354 if (Config.retry.maxtries > 10)
355 fatal("maximum_single_addr_tries cannot be larger than 10");
356 if (Config.retry.maxtries < 1) {
22c653cd 357 debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
5210854d 358 Config.retry.maxtries = 1;
359 }
f0b19334 360 requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
6b53c392 361#if USE_DNSSERVERS
f0b19334 362 requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
efd900cb 363#endif
a3d0a19d 364#if USE_UNLINKD
f0b19334 365 requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
a3d0a19d 366#endif
f0b19334 367 if (Config.Program.redirect)
c6d5b87b 368 requirePathnameExists("redirect_program", Config.Program.redirect->key);
f0b19334 369 requirePathnameExists("Icon Directory", Config.icons.directory);
370 requirePathnameExists("Error Directory", Config.errorDirectory);
9f60cfdf 371#if HTTP_VIOLATIONS
372 {
49c0f46d 373 const refresh_t *R;
374 for (R = Config.Refresh; R; R = R->next) {
375 if (!R->flags.override_expire)
376 continue;
377 debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
378 break;
379 }
380 for (R = Config.Refresh; R; R = R->next) {
381 if (!R->flags.override_lastmod)
382 continue;
383 debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
384 break;
385 }
9f60cfdf 386 }
387#endif
db1cd23c 388 if (Config.Wais.relayHost) {
389 if (Config.Wais.peer)
390 cbdataFree(Config.Wais.peer);
72711e31 391 Config.Wais.peer = cbdataAlloc(peer);
b6a2f15e 392 Config.Wais.peer->host = xstrdup(Config.Wais.relayHost);
db1cd23c 393 Config.Wais.peer->http_port = Config.Wais.relayPort;
394 }
53cb32a9 395 if (aclPurgeMethodInUse(Config.accessList.http))
396 Config2.onoff.enable_purge = 1;
8749fa47 397 if (geteuid() == 0) {
398 if (NULL != Config.effectiveUser) {
2d72d4fd 399 struct passwd *pwd = getpwnam(Config.effectiveUser);
400 if (NULL == pwd)
401 /*
402 * Andres Kroonmaa <andre@online.ee>:
403 * Some getpwnam() implementations (Solaris?) require
404 * an available FD < 256 for opening a FILE* to the
405 * passwd file.
406 * DW:
407 * This should be safe at startup, but might still fail
408 * during reconfigure.
409 */
410 fatalf("getpwnam failed to find userid for effective user '%s'",
411 Config.effectiveUser,
412 xstrerror());
413 Config2.effectiveUserID = pwd->pw_uid;
963a4014 414 Config2.effectiveGroupID = pwd->pw_gid;
2d72d4fd 415 }
8749fa47 416 } else {
417 Config2.effectiveUserID = geteuid();
418 Config2.effectiveGroupID = getegid();
d20b1cd0 419 }
420 if (NULL != Config.effectiveGroup) {
421 struct group *grp = getgrnam(Config.effectiveGroup);
422 if (NULL == grp)
423 fatalf("getgrnam failed to find groupid for effective group '%s'",
424 Config.effectiveGroup,
425 xstrerror());
426 Config2.effectiveGroupID = grp->gr_gid;
427 }
56fe752e 428 urlExtMethodConfigure();
feb32c6e 429 if (0 == Config.onoff.client_db) {
430 acl *a;
431 for (a = Config.aclList; a; a = a->next) {
432 if (ACL_MAXCONN != a->type)
433 continue;
434 debug(22, 0) ("WARNING: 'maxconn' ACL (%s) won't work with client_db disabled\n", a->name);
435 }
436 }
090089c4 437}
438
270b86af 439/* Parse a time specification from the config file. Store the
f1dc9b30 440 * result in 'tptr', after converting it to 'units' */
8203a132 441static void
a47b9029 442parseTimeLine(time_t * tptr, const char *units)
090089c4 443{
444 char *token;
270b86af 445 double d;
f1dc9b30 446 time_t m;
447 time_t u;
270b86af 448 if ((u = parseTimeUnits(units)) == 0)
3003c0f3 449 self_destruct();
270b86af 450 if ((token = strtok(NULL, w_space)) == NULL)
3003c0f3 451 self_destruct();
270b86af 452 d = atof(token);
453 m = u; /* default to 'units' if none specified */
10738561 454 if (0 == d)
455 (void) 0;
456 else if ((token = strtok(NULL, w_space)) == NULL)
a47b9029 457 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
458 config_input_line, d, units);
9e975e4e 459 else if ((m = parseTimeUnits(token)) == 0)
a47b9029 460 self_destruct();
f1dc9b30 461 *tptr = m * d / u;
090089c4 462}
463
270b86af 464static int
465parseTimeUnits(const char *unit)
466{
467 if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
468 return 1;
469 if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
470 return 60;
471 if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
472 return 3600;
473 if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
474 return 86400;
475 if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
476 return 86400 * 7;
477 if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
478 return 86400 * 14;
479 if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
480 return 86400 * 30;
481 if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
482 return 86400 * 365.2522;
483 if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
484 return 86400 * 365.2522 * 10;
485 debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit);
486 return 0;
487}
488
9906e724 489static void
9e975e4e 490parseBytesLine(size_t * bptr, const char *units)
9906e724 491{
492 char *token;
493 double d;
494 size_t m;
495 size_t u;
496 if ((u = parseBytesUnits(units)) == 0)
497 self_destruct();
498 if ((token = strtok(NULL, w_space)) == NULL)
499 self_destruct();
500 d = atof(token);
501 m = u; /* default to 'units' if none specified */
343f47a3 502 if (0.0 == d)
10738561 503 (void) 0;
4860dc1b 504 else if ((token = strtok(NULL, w_space)) == NULL)
9e975e4e 505 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
506 config_input_line, d, units);
507 else if ((m = parseBytesUnits(token)) == 0)
508 self_destruct();
9906e724 509 *bptr = m * d / u;
510}
511
512static size_t
513parseBytesUnits(const char *unit)
514{
515 if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
516 return 1;
517 if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
a47b9029 518 return 1 << 10;
9906e724 519 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
a47b9029 520 return 1 << 20;
9906e724 521 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
a47b9029 522 return 1 << 30;
9906e724 523 debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
524 return 0;
525}
526
270b86af 527/*****************************************************************************
528 * Max
529 *****************************************************************************/
530
8203a132 531static void
9ef28b60 532dump_acl(StoreEntry * entry, const char *name, acl * ae)
090089c4 533{
56b63fa1 534 wordlist *w;
535 wordlist *v;
9ef28b60 536 while (ae != NULL) {
c68e9c6b 537 debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
9ef28b60 538 v = w = aclDumpGeneric(ae);
56b63fa1 539 while (v != NULL) {
c68e9c6b 540 debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
16300b58 541 storeAppendPrintf(entry, "%s %s %s %s\n",
542 name,
9ef28b60 543 ae->name,
544 aclTypeToStr(ae->type),
16300b58 545 v->key);
56b63fa1 546 v = v->next;
547 }
548 wordlistDestroy(&w);
9ef28b60 549 ae = ae->next;
56b63fa1 550 }
090089c4 551}
552
8203a132 553static void
9ef28b60 554parse_acl(acl ** ae)
090089c4 555{
9ef28b60 556 aclParseAclLine(ae);
f1dc9b30 557}
558
559static void
9ef28b60 560free_acl(acl ** ae)
f1dc9b30 561{
9ef28b60 562 aclDestroyAcls(ae);
090089c4 563}
564
8203a132 565static void
16300b58 566dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
30a4f2a8 567{
56b63fa1 568 acl_list *l;
569 while (head != NULL) {
505e35db 570 storeAppendPrintf(entry, "%s %s",
0cdcddb9 571 name,
505e35db 572 head->allow ? "Allow" : "Deny");
573 for (l = head->acl_list; l != NULL; l = l->next) {
574 storeAppendPrintf(entry, " %s%s",
575 l->op ? null_string : "!",
56b63fa1 576 l->acl->name);
16300b58 577 }
505e35db 578 storeAppendPrintf(entry, "\n");
56b63fa1 579 head = head->next;
580 }
30a4f2a8 581}
090089c4 582
8203a132 583static void
16300b58 584parse_acl_access(acl_access ** head)
090089c4 585{
270b86af 586 aclParseAccessLine(head);
090089c4 587}
588
0153d498 589static void
16300b58 590free_acl_access(acl_access ** head)
0153d498 591{
a47b9029 592 aclDestroyAccessList(head);
0153d498 593}
594
8203a132 595static void
a7d59104 596dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
270b86af 597{
f53b06f9 598 storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
270b86af 599}
600
601static void
602parse_address(struct in_addr *addr)
090089c4 603{
0ee4272b 604 const struct hostent *hp;
270b86af 605 char *token = strtok(NULL, w_space);
606
30a4f2a8 607 if (token == NULL)
608 self_destruct();
429fdbec 609 if (safe_inet_addr(token, addr) == 1)
610 (void) 0;
ceb8994e 611 else if ((hp = gethostbyname(token))) /* dont use ipcache */
1d73e33a 612 *addr = inaddrFromHostent(hp);
30a4f2a8 613 else
3003c0f3 614 self_destruct();
090089c4 615}
616
0153d498 617static void
618free_address(struct in_addr *addr)
619{
a47b9029 620 memset(addr, '\0', sizeof(struct in_addr));
0153d498 621}
622
59715b38 623#if DELAY_POOLS
624
625/* do nothing - free_delay_pool_count is the magic free function.
626 * this is why delay_pool_count isn't just marked TYPE: ushort
627 */
628#define free_delay_pool_class(X)
629#define free_delay_pool_access(X)
630#define free_delay_pool_rates(X)
631#define dump_delay_pool_class(X, Y, Z)
632#define dump_delay_pool_access(X, Y, Z)
633#define dump_delay_pool_rates(X, Y, Z)
634
635static void
636free_delay_pool_count(delayConfig * cfg)
637{
638 int i;
639
640 if (!cfg->pools)
641 return;
642 for (i = 0; i < cfg->pools; i++) {
643 if (cfg->class[i]) {
644 delayFreeDelayPool(i);
645 safe_free(cfg->rates[i]);
646 }
647 aclDestroyAccessList(&cfg->access[i]);
648 }
649 delayFreeDelayData();
650 xfree(cfg->class);
651 xfree(cfg->rates);
652 xfree(cfg->access);
653 memset(cfg, 0, sizeof(*cfg));
654}
655
656static void
657dump_delay_pool_count(StoreEntry * entry, const char *name, delayConfig cfg)
658{
659 int i;
660 LOCAL_ARRAY(char, nom, 32);
661
662 if (!cfg.pools) {
663 storeAppendPrintf(entry, "%s 0\n", name);
664 return;
665 }
666 storeAppendPrintf(entry, "%s %d\n", name, cfg.pools);
667 for (i = 0; i < cfg.pools; i++) {
668 storeAppendPrintf(entry, "delay_class %d %d\n", i + 1, cfg.class[i]);
669 snprintf(nom, 32, "delay_access %d", i + 1);
670 dump_acl_access(entry, nom, cfg.access[i]);
671 if (cfg.class[i] >= 1)
672 storeAppendPrintf(entry, "delay_parameters %d %d/%d", i + 1,
673 cfg.rates[i]->aggregate.restore_bps,
674 cfg.rates[i]->aggregate.max_bytes);
675 if (cfg.class[i] >= 3)
676 storeAppendPrintf(entry, " %d/%d",
677 cfg.rates[i]->network.restore_bps,
678 cfg.rates[i]->network.max_bytes);
679 if (cfg.class[i] >= 2)
680 storeAppendPrintf(entry, " %d/%d",
681 cfg.rates[i]->individual.restore_bps,
682 cfg.rates[i]->individual.max_bytes);
683 if (cfg.class[i] >= 1)
684 storeAppendPrintf(entry, "\n");
685 }
686}
687
688static void
689parse_delay_pool_count(delayConfig * cfg)
690{
691 if (cfg->pools) {
692 debug(3, 0) ("parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config\n");
693 free_delay_pool_count(cfg);
694 }
695 parse_ushort(&cfg->pools);
1781dfc0 696 if (cfg->pools) {
697 delayInitDelayData(cfg->pools);
698 cfg->class = xcalloc(cfg->pools, sizeof(u_char));
699 cfg->rates = xcalloc(cfg->pools, sizeof(delaySpecSet *));
700 cfg->access = xcalloc(cfg->pools, sizeof(acl_access *));
701 }
59715b38 702}
703
704static void
705parse_delay_pool_class(delayConfig * cfg)
706{
707 ushort pool, class;
708
709 parse_ushort(&pool);
710 if (pool < 1 || pool > cfg->pools) {
711 debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
712 return;
713 }
714 parse_ushort(&class);
715 if (class < 1 || class > 3) {
716 debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d class %d not in 1 .. 3\n", pool, class);
717 return;
718 }
719 pool--;
720 if (cfg->class[pool]) {
721 delayFreeDelayPool(pool);
722 safe_free(cfg->rates[pool]);
723 }
724 cfg->rates[pool] = xmalloc(class * sizeof(delaySpec));
725 cfg->class[pool] = class;
726 cfg->rates[pool]->aggregate.restore_bps = cfg->rates[pool]->aggregate.max_bytes = -1;
727 if (cfg->class[pool] >= 3)
728 cfg->rates[pool]->network.restore_bps = cfg->rates[pool]->network.max_bytes = -1;
729 if (cfg->class[pool] >= 2)
730 cfg->rates[pool]->individual.restore_bps = cfg->rates[pool]->individual.max_bytes = -1;
731 delayCreateDelayPool(pool, class);
732}
733
734static void
735parse_delay_pool_rates(delayConfig * cfg)
736{
737 ushort pool, class;
738 int i;
739 delaySpec *ptr;
740 char *token;
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 pool--;
748 class = cfg->class[pool];
749 if (class == 0) {
750 debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d attempt to set rates with class not set\n", pool + 1);
751 return;
752 }
753 ptr = (delaySpec *) cfg->rates[pool];
754 /* read in "class" sets of restore,max pairs */
755 while (class--) {
756 token = strtok(NULL, "/");
757 if (token == NULL)
758 self_destruct();
759 if (sscanf(token, "%d", &i) != 1)
760 self_destruct();
761 ptr->restore_bps = i;
0e4e0e7d 762 i = GetInteger();
59715b38 763 ptr->max_bytes = i;
764 ptr++;
765 }
766 class = cfg->class[pool];
767 /* if class is 3, swap around network and individual */
768 if (class == 3) {
769 delaySpec tmp;
770
771 tmp = cfg->rates[pool]->individual;
772 cfg->rates[pool]->individual = cfg->rates[pool]->network;
773 cfg->rates[pool]->network = tmp;
774 }
775 /* initialize the delay pools */
776 delayInitDelayPool(pool, class, cfg->rates[pool]);
777}
778
779static void
780parse_delay_pool_access(delayConfig * cfg)
781{
782 ushort pool;
783
784 parse_ushort(&pool);
785 if (pool < 1 || pool > cfg->pools) {
786 debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools);
787 return;
788 }
789 aclParseAccessLine(&cfg->access[pool - 1]);
790}
791#endif
792
97474590 793static void
6bccf575 794dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
e3dd531e 795{
efd900cb 796 int i;
6bccf575 797 for (i = 0; i < HDR_ENUM_END; i++) {
798 if (header[i].access_list != NULL) {
72711e31 799 storeAppendPrintf(entry, "%s ", name);
6bccf575 800 dump_acl_access(entry, httpHeaderNameById(i),
801 header[i].access_list);
802 }
efd900cb 803 }
97474590 804}
e3dd531e 805
97474590 806static void
6bccf575 807parse_http_header_access(header_mangler header[])
97474590 808{
6bccf575 809 int id, i;
97474590 810 char *t = NULL;
97474590 811 if ((t = strtok(NULL, w_space)) == NULL) {
812 debug(3, 0) ("%s line %d: %s\n",
813 cfg_filename, config_lineno, config_input_line);
6bccf575 814 debug(3, 0) ("parse_http_header_access: missing header name.\n");
97474590 815 return;
816 }
6bccf575 817 /* Now lookup index of header. */
818 id = httpHeaderIdByNameDef(t, strlen(t));
819 if (strcmp(t, "All") == 0)
820 id = HDR_ENUM_END;
821 else if (strcmp(t, "Other") == 0)
822 id = HDR_OTHER;
823 else if (id == -1) {
97474590 824 debug(3, 0) ("%s line %d: %s\n",
825 cfg_filename, config_lineno, config_input_line);
6bccf575 826 debug(3, 0) ("parse_http_header_access: unknown header name %s.\n", t);
97474590 827 return;
828 }
6bccf575 829 if (id != HDR_ENUM_END) {
830 parse_acl_access(&header[id].access_list);
831 } else {
72711e31 832 char *next_string = t + strlen(t) - 1;
de3ee917 833 *next_string = 'A';
72711e31 834 *(next_string + 1) = ' ';
6bccf575 835 for (i = 0; i < HDR_ENUM_END; i++) {
836 char *new_string = xstrdup(next_string);
de3ee917 837 strtok(new_string, w_space);
6bccf575 838 parse_acl_access(&header[i].access_list);
839 safe_free(new_string);
efd900cb 840 }
97474590 841 }
6bccf575 842}
843
844static void
845free_http_header_access(header_mangler header[])
846{
847 int i;
848 for (i = 0; i < HDR_ENUM_END; i++) {
849 free_acl_access(&header[i].access_list);
850 }
851}
852
853static void
854dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
855 header[])
856{
857 int i;
6bccf575 858 for (i = 0; i < HDR_ENUM_END; i++) {
859 if (NULL == header[i].replacement)
860 continue;
de3ee917 861 storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
6bccf575 862 header[i].replacement);
97474590 863 }
864}
e3dd531e 865
97474590 866static void
6bccf575 867parse_http_header_replace(header_mangler header[])
e3dd531e 868{
6bccf575 869 int id, i;
870 char *t = NULL;
871 if ((t = strtok(NULL, w_space)) == NULL) {
872 debug(3, 0) ("%s line %d: %s\n",
873 cfg_filename, config_lineno, config_input_line);
874 debug(3, 0) ("parse_http_header_replace: missing header name.\n");
875 return;
876 }
877 /* Now lookup index of header. */
878 id = httpHeaderIdByNameDef(t, strlen(t));
879 if (strcmp(t, "All") == 0)
880 id = HDR_ENUM_END;
881 else if (strcmp(t, "Other") == 0)
882 id = HDR_OTHER;
883 else if (id == -1) {
884 debug(3, 0) ("%s line %d: %s\n",
885 cfg_filename, config_lineno, config_input_line);
886 debug(3, 0) ("parse_http_header_replace: unknown header name %s.\n",
887 t);
888 return;
889 }
890 if (id != HDR_ENUM_END) {
891 if (header[id].replacement != NULL)
892 safe_free(header[id].replacement);
893 header[id].replacement = xstrdup(t + strlen(t) + 1);
894 } else {
895 for (i = 0; i < HDR_ENUM_END; i++) {
896 if (header[i].replacement != NULL)
897 safe_free(header[i].replacement);
898 header[i].replacement = xstrdup(t + strlen(t) + 1);
899 }
900 }
901}
902
903static void
904free_http_header_replace(header_mangler header[])
905{
906 int i;
907 for (i = 0; i < HDR_ENUM_END; i++) {
908 if (header[i].replacement != NULL)
909 safe_free(header[i].replacement);
910 }
97474590 911}
912
25a77f03 913void
914dump_cachedir_options(StoreEntry * entry, struct cache_dir_option *options, SwapDir * sd)
915{
916 struct cache_dir_option *option;
917 if (!options)
918 return;
919 for (option = options; option->name; option++)
920 option->dump(entry, option->name, sd);
921}
922
e90100aa 923static void
56b63fa1 924dump_cachedir(StoreEntry * entry, const char *name, cacheSwap swap)
e90100aa 925{
f53b06f9 926 SwapDir *s;
927 int i;
a7d59104 928 for (i = 0; i < swap.n_configured; i++) {
929 s = swap.swapDirs + i;
25a77f03 930 storeAppendPrintf(entry, "%s %s %s", name, s->type, s->path);
931 if (s->dump)
932 s->dump(entry, s);
933 dump_cachedir_options(entry, common_cachedir_options, s);
934 storeAppendPrintf(entry, "\n");
f53b06f9 935 }
936}
937
938static int
56b63fa1 939check_null_cachedir(cacheSwap swap)
f53b06f9 940{
941 return swap.swapDirs == NULL;
e90100aa 942}
943
53ad48e6 944static int
945check_null_string(char *s)
946{
947 return s == NULL;
948}
949
2d72d4fd 950static void
94439e4e 951allocate_new_authScheme(authConfig * cfg)
952{
953 if (cfg->schemes == NULL) {
954 cfg->n_allocated = 4;
955 cfg->schemes = xcalloc(cfg->n_allocated, sizeof(authScheme));
956 }
957 if (cfg->n_allocated == cfg->n_configured) {
958 authScheme *tmp;
959 cfg->n_allocated <<= 1;
960 tmp = xcalloc(cfg->n_allocated, sizeof(authScheme));
961 xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme));
962 xfree(cfg->schemes);
963 cfg->schemes = tmp;
964 }
965}
966
967static void
968parse_authparam(authConfig * config)
969{
970 char *type_str;
971 char *param_str;
972 authScheme *scheme = NULL;
973 int type, i;
974
975 if ((type_str = strtok(NULL, w_space)) == NULL)
976 self_destruct();
977
978 if ((param_str = strtok(NULL, w_space)) == NULL)
979 self_destruct();
980
981 if ((type = authenticateAuthSchemeId(type_str)) == -1) {
982 debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
983 return;
984 }
985 for (i = 0; i < config->n_configured; i++) {
986 if (config->schemes[i].Id == type) {
987 scheme = config->schemes + i;
988 }
989 }
990
991 if (scheme == NULL) {
992 allocate_new_authScheme(config);
993 scheme = config->schemes + config->n_configured;
994 config->n_configured++;
995 scheme->Id = type;
996 scheme->typestr = authscheme_list[type].typestr;
997 }
998 authscheme_list[type].parse(scheme, config->n_configured, param_str);
999}
1000
1001static void
1002free_authparam(authConfig * cfg)
1003{
1004 authScheme *scheme;
1005 int i;
1006 /* DON'T FREE THESE FOR RECONFIGURE */
1007 if (reconfiguring)
1008 return;
1009 for (i = 0; i < cfg->n_configured; i++) {
1010 scheme = cfg->schemes + i;
1011 authscheme_list[scheme->Id].freeconfig(scheme);
1012 }
1013 safe_free(cfg->schemes);
1014 cfg->schemes = NULL;
1015 cfg->n_allocated = 0;
1016 cfg->n_configured = 0;
1017}
1018
1019static void
1020dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
1021{
1022 authScheme *scheme;
1023 int i;
1024 for (i = 0; i < cfg.n_configured; i++) {
1025 scheme = cfg.schemes + i;
1026 authscheme_list[scheme->Id].dump(entry, name, scheme);
1027 }
1028}
1029
0e4e0e7d 1030void
1031allocate_new_swapdir(cacheSwap * swap)
090089c4 1032{
f1dc9b30 1033 if (swap->swapDirs == NULL) {
1034 swap->n_allocated = 4;
1035 swap->swapDirs = xcalloc(swap->n_allocated, sizeof(SwapDir));
1036 }
1037 if (swap->n_allocated == swap->n_configured) {
0e4e0e7d 1038 SwapDir *tmp;
f1dc9b30 1039 swap->n_allocated <<= 1;
1040 tmp = xcalloc(swap->n_allocated, sizeof(SwapDir));
1041 xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir));
1042 xfree(swap->swapDirs);
1043 swap->swapDirs = tmp;
1044 }
0e4e0e7d 1045}
1046
cd748f27 1047static int
1048find_fstype(char *type)
1049{
1050 int i;
1051 for (i = 0; storefs_list[i].typestr != NULL; i++) {
a4b8110e 1052 if (strcasecmp(type, storefs_list[i].typestr) == 0) {
cd748f27 1053 return i;
1054 }
1055 }
1056 return (-1);
1057}
1058
0e4e0e7d 1059static void
1060parse_cachedir(cacheSwap * swap)
1061{
1062 char *type_str;
cd748f27 1063 char *path_str;
1064 SwapDir *sd;
1065 int i;
1066 int fs;
cd748f27 1067
0e4e0e7d 1068 if ((type_str = strtok(NULL, w_space)) == NULL)
1069 self_destruct();
cd748f27 1070
cd748f27 1071 if ((path_str = strtok(NULL, w_space)) == NULL)
1072 self_destruct();
1073
1074 /*
1075 * This bit of code is a little strange.
1076 * See, if we find a path and type match for a given line, then
1077 * as long as we're reconfiguring, we can just call its reconfigure
1078 * function. No harm there.
1079 *
1080 * Trouble is, if we find a path match, but not a type match, we have
1081 * a dilemma - we could gracefully shut down the fs, kill it, and
1082 * create a new one of a new type in its place, BUT at this stage the
1083 * fs is meant to be the *NEW* one, and so things go very strange. :-)
1084 *
1085 * So, we'll assume the person isn't going to change the fs type for now,
1086 * and XXX later on we will make sure that its picked up.
1087 *
1088 * (moving around cache_dir lines will be looked at later in a little
1089 * more sane detail..)
1090 */
1091
1092 for (i = 0; i < swap->n_configured; i++) {
a4b8110e 1093 if (0 == strcasecmp(path_str, swap->swapDirs[i].path)) {
cd748f27 1094 /* This is a little weird, you'll appreciate it later */
1095 fs = find_fstype(type_str);
1096 if (fs < 0) {
a4b8110e 1097 fatalf("Unknown cache_dir type '%s'\n", type_str);
cd748f27 1098 }
1099 sd = swap->swapDirs + i;
1100 storefs_list[fs].reconfigurefunc(sd, i, path_str);
a4b8110e 1101 update_maxobjsize();
1102 return;
cd748f27 1103 }
1104 }
1105
2b6662ba 1106 assert(swap->n_configured < 63); /* 7 bits, signed */
dc986280 1107
cd748f27 1108 fs = find_fstype(type_str);
1109 if (fs < 0) {
a4b8110e 1110 /* If we get here, we didn't find a matching cache_dir type */
1111 fatalf("Unknown cache_dir type '%s'\n", type_str);
0e4e0e7d 1112 }
cd748f27 1113 allocate_new_swapdir(swap);
1114 sd = swap->swapDirs + swap->n_configured;
cd748f27 1115 sd->type = storefs_list[fs].typestr;
90d42c28 1116 /* defaults in case fs implementation fails to set these */
8e8d4f30 1117 sd->max_objsize = -1;
90d42c28 1118 sd->fs.blksize = 1024;
8e8d4f30 1119 /* parse the FS parameters and options */
1120 storefs_list[fs].parsefunc(sd, swap->n_configured, path_str);
cd748f27 1121 swap->n_configured++;
1122 /* Update the max object size */
1123 update_maxobjsize();
752c3b27 1124}
1125
8e8d4f30 1126static void
1127parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring)
1128{
1129 int read_only = 0;
1130 if (value)
1131 read_only = atoi(value);
1132 else
1133 read_only = 1;
1134 sd->flags.read_only = read_only;
1135}
1136
25a77f03 1137static void
1138dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd)
1139{
1140 if (sd->flags.read_only)
1141 storeAppendPrintf(e, " %s", option);
1142}
1143
8e8d4f30 1144static void
1145parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring)
1146{
1147 ssize_t size;
1148
1149 if (!value)
1150 self_destruct();
1151
1152 size = atoi(value);
1153
1154 if (reconfiguring && sd->max_objsize != size)
1155 debug(3, 1) ("Cache dir '%s' max object size now %d\n", size);
1156
1157 sd->max_objsize = size;
1158}
1159
25a77f03 1160static void
1161dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd)
1162{
1163 if (sd->max_objsize != -1)
1164 storeAppendPrintf(e, " %s=%d", option, sd->max_objsize);
1165}
1166
8e8d4f30 1167void
1168parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring)
1169{
1170 int old_read_only = sd->flags.read_only;
1171 char *name, *value;
1172 struct cache_dir_option *option, *op;
1173
1174 while ((name = strtok(NULL, w_space)) != NULL) {
1175 value = strchr(name, '=');
1176 if (value)
1177 *value++ = '\0'; /* cut on = */
1178 option = NULL;
1179 if (options) {
1180 for (op = options; !option && op->name; op++) {
1181 if (strcmp(op->name, name) == 0) {
1182 option = op;
1183 break;
1184 }
1185 }
1186 }
1187 for (op = common_cachedir_options; !option && op->name; op++) {
1188 if (strcmp(op->name, name) == 0) {
1189 option = op;
1190 break;
1191 }
1192 }
1193 if (!option || !option->parse)
1194 self_destruct();
1195 option->parse(sd, name, value, reconfiguring);
1196 }
1197 /*
1198 * Handle notifications about reconfigured single-options with no value
1199 * where the removal of the option cannot be easily detected in the
1200 * parsing...
1201 */
1202 if (reconfiguring) {
1203 if (old_read_only != sd->flags.read_only) {
1204 debug(3, 1) ("Cache dir '%s' now %s\n",
1205 sd->path, sd->flags.read_only ? "Read-Only" : "Read-Write");
1206 }
1207 }
1208}
1209
8203a132 1210static void
16300b58 1211free_cachedir(cacheSwap * swap)
f1dc9b30 1212{
a47b9029 1213 SwapDir *s;
1214 int i;
860ee7e3 1215 /* DON'T FREE THESE FOR RECONFIGURE */
5cd39a10 1216 if (reconfiguring)
860ee7e3 1217 return;
a47b9029 1218 for (i = 0; i < swap->n_configured; i++) {
1219 s = swap->swapDirs + i;
cd748f27 1220 s->freefs(s);
a47b9029 1221 xfree(s->path);
a47b9029 1222 }
1223 safe_free(swap->swapDirs);
1224 swap->swapDirs = NULL;
1225 swap->n_allocated = 0;
1226 swap->n_configured = 0;
f1dc9b30 1227}
1228
2d72d4fd 1229static const char *
505e35db 1230peer_type_str(const peer_t type)
1231{
0cdcddb9 1232 switch (type) {
505e35db 1233 case PEER_PARENT:
1234 return "parent";
1235 break;
1236 case PEER_SIBLING:
1237 return "sibling";
1238 break;
1239 case PEER_MULTICAST:
1240 return "multicast";
1241 break;
1242 default:
1243 return "unknown";
1244 break;
1245 }
1246}
1247
f1dc9b30 1248static void
a7d59104 1249dump_peer(StoreEntry * entry, const char *name, peer * p)
98ffb7e4 1250{
505e35db 1251 domain_ping *d;
505e35db 1252 domain_type *t;
1253 LOCAL_ARRAY(char, xname, 128);
d41de3c1 1254 while (p != NULL) {
1255 storeAppendPrintf(entry, "%s %s %s %d %d",
1256 name,
1257 p->host,
1258 neighborTypeStr(p),
1259 p->http_port,
399cabec 1260 p->icp.port);
a369131d 1261 dump_peer_options(entry, p);
b6a2f15e 1262 for (d = p->peer_domain; d; d = d->next) {
505e35db 1263 storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
1264 p->host,
1265 d->do_ping ? null_string : "!",
1266 d->domain);
1267 }
1810dde6 1268 if (p->access) {
505e35db 1269 snprintf(xname, 128, "cache_peer_access %s", p->host);
1270 dump_acl_access(entry, xname, p->access);
1271 }
1272 for (t = p->typelist; t; t = t->next) {
1273 storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
1274 p->host,
1275 peer_type_str(t->type),
1276 t->domain);
1277 }
d41de3c1 1278 p = p->next;
1279 }
98ffb7e4 1280}
1281
8203a132 1282static void
40a1495e 1283parse_peer(peer ** head)
7813c6d5 1284{
270b86af 1285 char *token = NULL;
40a1495e 1286 peer *p;
7813c6d5 1287 int i;
72711e31 1288 p = cbdataAlloc(peer);
40a1495e 1289 p->http_port = CACHE_HTTP_PORT;
399cabec 1290 p->icp.port = CACHE_ICP_PORT;
40a1495e 1291 p->weight = 1;
dc835977 1292 p->stats.logged_state = PEER_ALIVE;
e481c2dc 1293 if ((token = strtok(NULL, w_space)) == NULL)
270b86af 1294 self_destruct();
40a1495e 1295 p->host = xstrdup(token);
e481c2dc 1296 if ((token = strtok(NULL, w_space)) == NULL)
270b86af 1297 self_destruct();
40a1495e 1298 p->type = parseNeighborType(token);
0e4e0e7d 1299 i = GetInteger();
40a1495e 1300 p->http_port = (u_short) i;
0e4e0e7d 1301 i = GetInteger();
399cabec 1302 p->icp.port = (u_short) i;
270b86af 1303 while ((token = strtok(NULL, w_space))) {
1304 if (!strcasecmp(token, "proxy-only")) {
cd196bc8 1305 p->options.proxy_only = 1;
270b86af 1306 } else if (!strcasecmp(token, "no-query")) {
cd196bc8 1307 p->options.no_query = 1;
8638fc66 1308 } else if (!strcasecmp(token, "no-digest")) {
cd196bc8 1309 p->options.no_digest = 1;
270b86af 1310 } else if (!strcasecmp(token, "multicast-responder")) {
cd196bc8 1311 p->options.mcast_responder = 1;
270b86af 1312 } else if (!strncasecmp(token, "weight=", 7)) {
40a1495e 1313 p->weight = atoi(token + 7);
0103c4c1 1314 } else if (!strcasecmp(token, "closest-only")) {
cd196bc8 1315 p->options.closest_only = 1;
270b86af 1316 } else if (!strncasecmp(token, "ttl=", 4)) {
40a1495e 1317 p->mcast.ttl = atoi(token + 4);
1318 if (p->mcast.ttl < 0)
1319 p->mcast.ttl = 0;
1320 if (p->mcast.ttl > 128)
1321 p->mcast.ttl = 128;
0103c4c1 1322 } else if (!strcasecmp(token, "default")) {
cd196bc8 1323 p->options.default_parent = 1;
0103c4c1 1324 } else if (!strcasecmp(token, "round-robin")) {
cd196bc8 1325 p->options.roundrobin = 1;
dc9d133b 1326#if USE_HTCP
0103c4c1 1327 } else if (!strcasecmp(token, "htcp")) {
cd196bc8 1328 p->options.htcp = 1;
dc9d133b 1329#endif
0103c4c1 1330 } else if (!strcasecmp(token, "no-netdb-exchange")) {
cd196bc8 1331 p->options.no_netdb_exchange = 1;
afd88fbe 1332#if USE_CARP
1333 } else if (!strncasecmp(token, "carp-load-factor=", 17)) {
1334 if (p->type != PEER_PARENT)
0cdcddb9 1335 debug(3, 0) ("parse_peer: Ignoring carp-load-factor for non-parent %s/%d\n", p->host, p->http_port);
1336 else
1337 p->carp.load_factor = atof(token + 17);
95e36d02 1338#endif
1339#if DELAY_POOLS
1340 } else if (!strcasecmp(token, "no-delay")) {
cd196bc8 1341 p->options.no_delay = 1;
afd88fbe 1342#endif
c68e9c6b 1343 } else if (!strncasecmp(token, "login=", 6)) {
1344 p->login = xstrdup(token + 6);
4472c779 1345 rfc1738_unescape(p->login);
3f62decd 1346 } else if (!strncasecmp(token, "connect-timeout=", 16)) {
1347 p->connect_timeout = atoi(token + 16);
7e3ce7b9 1348#if USE_CACHE_DIGESTS
1349 } else if (!strncasecmp(token, "digest-url=", 11)) {
1350 p->digest_url = xstrdup(token + 11);
1351#endif
987de783 1352 } else if (!strcasecmp(token, "allow-miss")) {
1353 p->options.allow_miss = 1;
c7f9eb6d 1354 } else if (!strcasecmp(token, "max-conn=")) {
1355 p->max_conn = atoi(token + 9);
270b86af 1356 } else {
40a1495e 1357 debug(3, 0) ("parse_peer: token='%s'\n", token);
270b86af 1358 self_destruct();
1359 }
1360 }
40a1495e 1361 if (p->weight < 1)
1362 p->weight = 1;
399cabec 1363 p->icp.version = ICP_VERSION_CURRENT;
98829f69 1364 p->tcp_up = PEER_TCP_MAGIC_COUNT;
eb406bb7 1365 p->test_fd = -1;
afd88fbe 1366#if USE_CARP
8ee9b49f 1367#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
afd88fbe 1368 if (p->carp.load_factor) {
e13ee7ad 1369 /* calculate this peers hash for use in CARP */
0cdcddb9 1370 p->carp.hash = 0;
1371 for (token = p->host; *token != 0; token++)
8ee9b49f 1372 p->carp.hash += ROTATE_LEFT(p->carp.hash, 19) + (unsigned int) *token;
d20b1cd0 1373 p->carp.hash += p->carp.hash * 0x62531965;
8ee9b49f 1374 p->carp.hash = ROTATE_LEFT(p->carp.hash, 21);
afd88fbe 1375 }
1376#endif
e13ee7ad 1377#if USE_CACHE_DIGESTS
1378 if (!p->options.no_digest) {
1379 p->digest = peerDigestCreate(p);
8a6218c6 1380 cbdataLock(p->digest); /* so we know when/if digest disappears */
1381 }
e13ee7ad 1382#endif
0153d498 1383 while (*head != NULL)
1384 head = &(*head)->next;
1385 *head = p;
40a1495e 1386 Config.npeers++;
82056f1e 1387 peerClearRR(p);
0153d498 1388}
1389
1390static void
40a1495e 1391free_peer(peer ** P)
0153d498 1392{
40a1495e 1393 peer *p;
79d39a72 1394 while ((p = *P) != NULL) {
a47b9029 1395 *P = p->next;
3855c318 1396#if USE_CACHE_DIGESTS
1397 if (p->digest)
1398 cbdataUnlock(p->digest);
1399 p->digest = NULL;
1400#endif
41042c81 1401 cbdataFree(p);
a47b9029 1402 }
987c67d1 1403 Config.npeers = 0;
270b86af 1404}
1405
1406static void
a7d59104 1407dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
270b86af 1408{
d41de3c1 1409 wordlist *w;
1410 while (list != NULL) {
74aa8456 1411 if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
1412 storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
1413 else
1414 storeAppendPrintf(entry, "%s %s", name, list->passwd);
d41de3c1 1415 for (w = list->actions; w != NULL; w = w->next) {
1416 storeAppendPrintf(entry, " %s", w->key);
1417 }
1418 storeAppendPrintf(entry, "\n");
1419 list = list->next;
1420 }
270b86af 1421}
1422
1423static void
a47b9029 1424parse_cachemgrpasswd(cachemgr_passwd ** head)
270b86af 1425{
1426 char *passwd = NULL;
1427 wordlist *actions = NULL;
22f3fd98 1428 cachemgr_passwd *p;
1429 cachemgr_passwd **P;
270b86af 1430 parse_string(&passwd);
1431 parse_wordlist(&actions);
22f3fd98 1432 p = xcalloc(1, sizeof(cachemgr_passwd));
1433 p->passwd = passwd;
1434 p->actions = actions;
1435 for (P = head; *P; P = &(*P)->next);
1436 *P = p;
270b86af 1437}
1438
1439static void
a47b9029 1440free_cachemgrpasswd(cachemgr_passwd ** head)
270b86af 1441{
a47b9029 1442 cachemgr_passwd *p;
79d39a72 1443 while ((p = *head) != NULL) {
a47b9029 1444 *head = p->next;
1445 xfree(p->passwd);
22f3fd98 1446 wordlistDestroy(&p->actions);
a47b9029 1447 xfree(p);
1448 }
270b86af 1449}
1450
8203a132 1451static void
16300b58 1452dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
270b86af 1453{
d41de3c1 1454 acl_name_list *a;
1455 while (var != NULL) {
02922e76 1456 storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
d41de3c1 1457 for (a = var->acl_list; a != NULL; a = a->next)
1458 storeAppendPrintf(entry, " %s", a->name);
1459 storeAppendPrintf(entry, "\n");
1460 var = var->next;
1461 }
270b86af 1462}
1463
1464static void
16300b58 1465parse_denyinfo(acl_deny_info_list ** var)
6e40f263 1466{
f1dc9b30 1467 aclParseDenyInfoLine(var);
6e40f263 1468}
403279e0 1469
1273d501 1470void
a47b9029 1471free_denyinfo(acl_deny_info_list ** list)
3c5557f9 1472{
56b63fa1 1473 acl_deny_info_list *a = NULL;
1474 acl_deny_info_list *a_next = NULL;
1475 acl_name_list *l = NULL;
1476 acl_name_list *l_next = NULL;
1273d501 1477 for (a = *list; a; a = a_next) {
a47b9029 1478 for (l = a->acl_list; l; l = l_next) {
1479 l_next = l->next;
3314e65b 1480 memFree(l, MEM_ACL_NAME_LIST);
eeda4c4d 1481 l = NULL;
a47b9029 1482 }
1483 a_next = a->next;
eeda4c4d 1484 memFree(a, MEM_ACL_DENY_INFO_LIST);
1485 a = NULL;
1273d501 1486 }
1487 *list = NULL;
270b86af 1488}
1489
1490static void
505e35db 1491parse_peer_access(void)
270b86af 1492{
1493 char *host = NULL;
505e35db 1494 peer *p;
270b86af 1495 if (!(host = strtok(NULL, w_space)))
1496 self_destruct();
0cdcddb9 1497 if ((p = peerFindByName(host)) == NULL) {
1498 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1499 cfg_filename, config_lineno, host);
1500 return;
1501 }
505e35db 1502 aclParseAccessLine(&p->access);
270b86af 1503}
1504
270b86af 1505static void
1506parse_hostdomain(void)
1507{
1508 char *host = NULL;
1509 char *domain = NULL;
1510 if (!(host = strtok(NULL, w_space)))
1511 self_destruct();
f1dc9b30 1512 while ((domain = strtok(NULL, list_sep))) {
1513 domain_ping *l = NULL;
1514 domain_ping **L = NULL;
40a1495e 1515 peer *p;
1516 if ((p = peerFindByName(host)) == NULL) {
43c3424b 1517 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
f1dc9b30 1518 cfg_filename, config_lineno, host);
1519 continue;
1520 }
56b63fa1 1521 l = xcalloc(1, sizeof(domain_ping));
f1dc9b30 1522 l->do_ping = 1;
1523 if (*domain == '!') { /* check for !.edu */
1524 l->do_ping = 0;
1525 domain++;
1526 }
1527 l->domain = xstrdup(domain);
b6a2f15e 1528 for (L = &(p->peer_domain); *L; L = &((*L)->next));
f1dc9b30 1529 *L = l;
1530 }
270b86af 1531}
1532
1533static void
1534parse_hostdomaintype(void)
1535{
1536 char *host = NULL;
1537 char *type = NULL;
1538 char *domain = NULL;
1539 if (!(host = strtok(NULL, w_space)))
1540 self_destruct();
1541 if (!(type = strtok(NULL, w_space)))
1542 self_destruct();
f1dc9b30 1543 while ((domain = strtok(NULL, list_sep))) {
1544 domain_type *l = NULL;
1545 domain_type **L = NULL;
40a1495e 1546 peer *p;
1547 if ((p = peerFindByName(host)) == NULL) {
43c3424b 1548 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
f1dc9b30 1549 cfg_filename, config_lineno, host);
1550 return;
1551 }
56b63fa1 1552 l = xcalloc(1, sizeof(domain_type));
f1dc9b30 1553 l->type = parseNeighborType(type);
1554 l->domain = xstrdup(domain);
1555 for (L = &(p->typelist); *L; L = &((*L)->next));
1556 *L = l;
1557 }
270b86af 1558}
1559
7e3ce7b9 1560#if UNUSED_CODE
270b86af 1561static void
a7d59104 1562dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
090089c4 1563{
270b86af 1564 while (u) {
f53b06f9 1565 storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
270b86af 1566 u = u->next;
1567 }
1568}
090089c4 1569
f53b06f9 1570static int
1571check_null_ushortlist(ushortlist * u)
1572{
1573 return u == NULL;
1574}
1575
270b86af 1576static void
1577parse_ushortlist(ushortlist ** P)
1578{
1579 char *token;
1580 int i;
1581 ushortlist *u;
1582 ushortlist **U;
1583 while ((token = strtok(NULL, w_space))) {
1584 if (sscanf(token, "%d", &i) != 1)
1585 self_destruct();
1586 if (i < 0)
1587 i = 0;
1588 u = xcalloc(1, sizeof(ushortlist));
1589 u->i = (u_short) i;
1590 for (U = P; *U; U = &(*U)->next);
1591 *U = u;
090089c4 1592 }
270b86af 1593}
090089c4 1594
0153d498 1595static void
a47b9029 1596free_ushortlist(ushortlist ** P)
0153d498 1597{
a47b9029 1598 ushortlist *u;
79d39a72 1599 while ((u = *P) != NULL) {
a47b9029 1600 *P = u->next;
1601 xfree(u);
1602 }
0153d498 1603}
7e3ce7b9 1604#endif
0153d498 1605
270b86af 1606static void
a7d59104 1607dump_int(StoreEntry * entry, const char *name, int var)
270b86af 1608{
f53b06f9 1609 storeAppendPrintf(entry, "%s %d\n", name, var);
270b86af 1610}
c1c29eb6 1611
94439e4e 1612void
270b86af 1613parse_int(int *var)
1614{
270b86af 1615 int i;
0e4e0e7d 1616 i = GetInteger();
270b86af 1617 *var = i;
1618}
090089c4 1619
0153d498 1620static void
1621free_int(int *var)
1622{
a47b9029 1623 *var = 0;
0153d498 1624}
1625
270b86af 1626static void
a7d59104 1627dump_onoff(StoreEntry * entry, const char *name, int var)
270b86af 1628{
f53b06f9 1629 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
270b86af 1630}
090089c4 1631
270b86af 1632static void
1633parse_onoff(int *var)
1634{
1635 char *token = strtok(NULL, w_space);
090089c4 1636
270b86af 1637 if (token == NULL)
1638 self_destruct();
1639 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
1640 *var = 1;
1641 else
1642 *var = 0;
1643}
e90100aa 1644
0153d498 1645#define free_onoff free_int
f1dc9b30 1646#define dump_eol dump_string
1647#define free_eol free_string
30a4f2a8 1648
270b86af 1649static void
a7d59104 1650dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
270b86af 1651{
d41de3c1 1652 while (head != NULL) {
9f60cfdf 1653 storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
c3f6d204 1654 name,
1655 head->flags.icase ? " -i" : null_string,
1656 head->pattern,
1657 (int) head->min / 60,
1658 (int) (100.0 * head->pct + 0.5),
9f60cfdf 1659 (int) head->max / 60);
1660#if HTTP_VIOLATIONS
1661 if (head->flags.override_expire)
1662 storeAppendPrintf(entry, " override-expire");
1663 if (head->flags.override_lastmod)
1664 storeAppendPrintf(entry, " override-lastmod");
1665 if (head->flags.reload_into_ims)
1666 storeAppendPrintf(entry, " reload-into-ims");
1667 if (head->flags.ignore_reload)
1668 storeAppendPrintf(entry, " ignore-reload");
1669#endif
1670 storeAppendPrintf(entry, "\n");
d41de3c1 1671 head = head->next;
1672 }
270b86af 1673}
090089c4 1674
270b86af 1675static void
f1dc9b30 1676parse_refreshpattern(refresh_t ** head)
270b86af 1677{
f1dc9b30 1678 char *token;
1679 char *pattern;
1680 time_t min = 0;
c3f6d204 1681 double pct = 0.0;
f1dc9b30 1682 time_t max = 0;
9f60cfdf 1683#if HTTP_VIOLATIONS
1dfa1d81 1684 int override_expire = 0;
1685 int override_lastmod = 0;
cbe3a719 1686 int reload_into_ims = 0;
1687 int ignore_reload = 0;
9f60cfdf 1688#endif
f1dc9b30 1689 int i;
1690 refresh_t *t;
1691 regex_t comp;
1692 int errcode;
1693 int flags = REG_EXTENDED | REG_NOSUB;
1694 if ((token = strtok(NULL, w_space)) == NULL)
1695 self_destruct();
1696 if (strcmp(token, "-i") == 0) {
1697 flags |= REG_ICASE;
1698 token = strtok(NULL, w_space);
1699 } else if (strcmp(token, "+i") == 0) {
1700 flags &= ~REG_ICASE;
1701 token = strtok(NULL, w_space);
1702 }
1703 if (token == NULL)
1704 self_destruct();
1705 pattern = xstrdup(token);
0e4e0e7d 1706 i = GetInteger(); /* token: min */
f1dc9b30 1707 min = (time_t) (i * 60); /* convert minutes to seconds */
0e4e0e7d 1708 i = GetInteger(); /* token: pct */
c3f6d204 1709 pct = (double) i / 100.0;
0e4e0e7d 1710 i = GetInteger(); /* token: max */
f1dc9b30 1711 max = (time_t) (i * 60); /* convert minutes to seconds */
1dfa1d81 1712 /* Options */
1713 while ((token = strtok(NULL, w_space)) != NULL) {
9f60cfdf 1714#if HTTP_VIOLATIONS
1dfa1d81 1715 if (!strcmp(token, "override-expire"))
1716 override_expire = 1;
255d6021 1717 else if (!strcmp(token, "override-lastmod"))
1dfa1d81 1718 override_lastmod = 1;
cbe3a719 1719 else if (!strcmp(token, "reload-into-ims")) {
1720 reload_into_ims = 1;
1721 refresh_nocache_hack = 1;
1722 /* tell client_side.c that this is used */
1723 } else if (!strcmp(token, "ignore-reload")) {
1724 ignore_reload = 1;
1725 refresh_nocache_hack = 1;
1726 /* tell client_side.c that this is used */
1727 } else
9f60cfdf 1728#endif
cbe3a719 1729 debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
1dfa1d81 1730 pattern, token);
1731 }
f1dc9b30 1732 if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
1733 char errbuf[256];
1734 regerror(errcode, &comp, errbuf, sizeof errbuf);
1735 debug(22, 0) ("%s line %d: %s\n",
1736 cfg_filename, config_lineno, config_input_line);
1737 debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %s\n",
1738 pattern, errbuf);
1739 return;
1740 }
c3f6d204 1741 pct = pct < 0.0 ? 0.0 : pct;
f1dc9b30 1742 max = max < 0 ? 0 : max;
1743 t = xcalloc(1, sizeof(refresh_t));
1744 t->pattern = (char *) xstrdup(pattern);
1745 t->compiled_pattern = comp;
1746 t->min = min;
c3f6d204 1747 t->pct = pct;
f1dc9b30 1748 t->max = max;
c3f6d204 1749 if (flags & REG_ICASE)
1750 t->flags.icase = 1;
9f60cfdf 1751#if HTTP_VIOLATIONS
1dfa1d81 1752 if (override_expire)
1753 t->flags.override_expire = 1;
1754 if (override_lastmod)
1755 t->flags.override_lastmod = 1;
cbe3a719 1756 if (reload_into_ims)
1757 t->flags.reload_into_ims = 1;
1758 if (ignore_reload)
1759 t->flags.ignore_reload = 1;
9f60cfdf 1760#endif
f1dc9b30 1761 t->next = NULL;
1762 while (*head)
1763 head = &(*head)->next;
1764 *head = t;
1765 safe_free(pattern);
270b86af 1766}
090089c4 1767
6b53c392 1768static int
a4b8110e 1769check_null_refreshpattern(refresh_t * data)
6b53c392 1770{
1771 return data != NULL;
1772}
1773
270b86af 1774static void
a47b9029 1775free_refreshpattern(refresh_t ** head)
270b86af 1776{
f1dc9b30 1777 refresh_t *t;
79d39a72 1778 while ((t = *head) != NULL) {
f1dc9b30 1779 *head = t->next;
1780 safe_free(t->pattern);
1781 regfree(&t->compiled_pattern);
1782 safe_free(t);
1783 }
270b86af 1784}
12b9e9b1 1785
270b86af 1786static void
a7d59104 1787dump_string(StoreEntry * entry, const char *name, char *var)
270b86af 1788{
f53b06f9 1789 if (var != NULL)
a7d59104 1790 storeAppendPrintf(entry, "%s %s\n", name, var);
270b86af 1791}
98ffb7e4 1792
270b86af 1793static void
0153d498 1794parse_string(char **var)
270b86af 1795{
1796 char *token = strtok(NULL, w_space);
270b86af 1797 safe_free(*var);
1798 if (token == NULL)
1799 self_destruct();
1800 *var = xstrdup(token);
1801}
b15e6857 1802
0153d498 1803static void
1804free_string(char **var)
1805{
027acbaf 1806 safe_free(*var);
0153d498 1807}
caebbe00 1808
94439e4e 1809void
f1dc9b30 1810parse_eol(char *volatile *var)
270b86af 1811{
20cb98c9 1812 unsigned char *token = strtok(NULL, null_string);
270b86af 1813 safe_free(*var);
f1dc9b30 1814 if (token == NULL)
2d72d4fd 1815 self_destruct();
1816 while (*token && isspace(*token))
1817 token++;
20cb98c9 1818 if (!*token)
f1dc9b30 1819 self_destruct();
270b86af 1820 *var = xstrdup(token);
1821}
090089c4 1822
270b86af 1823static void
a7d59104 1824dump_time_t(StoreEntry * entry, const char *name, time_t var)
090089c4 1825{
f53b06f9 1826 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
090089c4 1827}
1828
94439e4e 1829void
a47b9029 1830parse_time_t(time_t * var)
0ffd22bc 1831{
f1dc9b30 1832 parseTimeLine(var, T_SECOND_STR);
0ffd22bc 1833}
1834
270b86af 1835static void
a47b9029 1836free_time_t(time_t * var)
270b86af 1837{
a47b9029 1838 *var = 0;
270b86af 1839}
9906e724 1840
1841static void
a7d59104 1842dump_size_t(StoreEntry * entry, const char *name, size_t var)
1b635117 1843{
f53b06f9 1844 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
1b635117 1845}
1846
1847static void
a7d59104 1848dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
9906e724 1849{
f53b06f9 1850 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
9906e724 1851}
1852
1853static void
a7d59104 1854dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
9906e724 1855{
f53b06f9 1856 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
9906e724 1857}
1858
1859static void
a47b9029 1860parse_size_t(size_t * var)
1b635117 1861{
1b635117 1862 int i;
0e4e0e7d 1863 i = GetInteger();
1b635117 1864 *var = (size_t) i;
1865}
1866
1867static void
1868parse_b_size_t(size_t * var)
9906e724 1869{
1870 parseBytesLine(var, B_BYTES_STR);
1871}
1872
b671cc68 1873CBDATA_TYPE(body_size);
a560ee93 1874
1875static void
b671cc68 1876parse_body_size_t(dlink_list * bodylist)
a560ee93 1877{
1878 body_size *bs;
b671cc68 1879 CBDATA_INIT_TYPE(body_size);
a560ee93 1880 bs = cbdataAlloc(body_size);
b671cc68 1881 parse_size_t(&bs->maxsize);
a560ee93 1882 aclParseAccessLine(&bs->access_list);
1883
1884 dlinkAddTail(bs, &bs->node, bodylist);
1885}
1886
1887static void
1888dump_body_size_t(StoreEntry * entry, const char *name, dlink_list bodylist)
1889{
1890 body_size *bs;
1891 bs = (body_size *) bodylist.head;
1892 while (bs) {
b671cc68 1893 acl_list *l;
a560ee93 1894 acl_access *head = bs->access_list;
1895 while (head != NULL) {
b671cc68 1896 storeAppendPrintf(entry, "%s %d %s", name, bs->maxsize,
a560ee93 1897 head->allow ? "Allow" : "Deny");
1898 for (l = head->acl_list; l != NULL; l = l->next) {
b671cc68 1899 storeAppendPrintf(entry, " %s%s",
a560ee93 1900 l->op ? null_string : "!",
1901 l->acl->name);
1902 }
1903 storeAppendPrintf(entry, "\n");
1904 head = head->next;
b671cc68 1905 }
a560ee93 1906 bs = (body_size *) bs->node.next;
1907 }
1908}
1909
1910static void
b671cc68 1911free_body_size_t(dlink_list * bodylist) //acl_access ** head)
1912 {
a560ee93 1913 body_size *bs, *tempnode;
1914 bs = (body_size *) bodylist->head;
1915 while (bs) {
b671cc68 1916 bs->maxsize = 0;
a560ee93 1917 aclDestroyAccessList(&bs->access_list);
1918 tempnode = (body_size *) bs->node.next;
b671cc68 1919 dlinkDelete(&bs->node, bodylist);
1920 cbdataFree(bs);
a560ee93 1921 bs = tempnode;
1922 }
1923}
1924
1925static int
1926check_null_body_size_t(dlink_list bodylist)
1927{
1928 return bodylist.head == NULL;
1929}
1930
1931
9906e724 1932static void
a47b9029 1933parse_kb_size_t(size_t * var)
9906e724 1934{
1935 parseBytesLine(var, B_KBYTES_STR);
1936}
1937
1938static void
a47b9029 1939free_size_t(size_t * var)
9906e724 1940{
a47b9029 1941 *var = 0;
9906e724 1942}
1943
1b635117 1944#define free_b_size_t free_size_t
9906e724 1945#define free_kb_size_t free_size_t
1946#define free_mb_size_t free_size_t
1947#define free_gb_size_t free_size_t
090089c4 1948
8203a132 1949static void
a7d59104 1950dump_ushort(StoreEntry * entry, const char *name, u_short var)
090089c4 1951{
f53b06f9 1952 storeAppendPrintf(entry, "%s %d\n", name, var);
270b86af 1953}
090089c4 1954
0153d498 1955static void
a47b9029 1956free_ushort(u_short * u)
0153d498 1957{
1958 *u = 0;
1959}
1960
270b86af 1961static void
1962parse_ushort(u_short * var)
1963{
270b86af 1964 int i;
090089c4 1965
0e4e0e7d 1966 i = GetInteger();
270b86af 1967 if (i < 0)
1968 i = 0;
1969 *var = (u_short) i;
090089c4 1970}
1971
270b86af 1972static void
a7d59104 1973dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
270b86af 1974{
270b86af 1975 while (list != NULL) {
f53b06f9 1976 storeAppendPrintf(entry, "%s %s\n", name, list->key);
270b86af 1977 list = list->next;
429fdbec 1978 }
429fdbec 1979}
1980
94439e4e 1981void
270b86af 1982parse_wordlist(wordlist ** list)
429fdbec 1983{
270b86af 1984 char *token;
270b86af 1985 while ((token = strtok(NULL, w_space)))
1986 wordlistAdd(list, token);
429fdbec 1987}
270b86af 1988
f8d9f54a 1989static int
5da06f20 1990check_null_wordlist(wordlist * w)
f8d9f54a 1991{
1992 return w == NULL;
1993}
1994
63e9d884 1995static int
c6d5b87b 1996check_null_acl_access(acl_access * a)
63e9d884 1997{
1998 return a == NULL;
1999}
2000
0153d498 2001#define free_wordlist wordlistDestroy
270b86af 2002
d548ee64 2003#define free_uri_whitespace free_int
2004
2005static void
2006parse_uri_whitespace(int *var)
2007{
2008 char *token = strtok(NULL, w_space);
2009 if (token == NULL)
2010 self_destruct();
7e3ce7b9 2011 if (!strcasecmp(token, "strip"))
2012 *var = URI_WHITESPACE_STRIP;
2013 else if (!strcasecmp(token, "deny"))
d548ee64 2014 *var = URI_WHITESPACE_DENY;
2015 else if (!strcasecmp(token, "allow"))
2016 *var = URI_WHITESPACE_ALLOW;
2017 else if (!strcasecmp(token, "encode"))
2018 *var = URI_WHITESPACE_ENCODE;
2019 else if (!strcasecmp(token, "chop"))
2020 *var = URI_WHITESPACE_CHOP;
2021 else
2022 self_destruct();
2023}
2024
2025
2026static void
2027dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
2028{
2029 char *s;
2030 if (var == URI_WHITESPACE_ALLOW)
2031 s = "allow";
2032 else if (var == URI_WHITESPACE_ENCODE)
2033 s = "encode";
2034 else if (var == URI_WHITESPACE_CHOP)
2035 s = "chop";
7e3ce7b9 2036 else if (var == URI_WHITESPACE_DENY)
d548ee64 2037 s = "deny";
7e3ce7b9 2038 else
2039 s = "strip";
d548ee64 2040 storeAppendPrintf(entry, "%s %s\n", name, s);
2041}
2042
6a566b9c 2043static void
c1dd71ae 2044free_removalpolicy(RemovalPolicySettings ** settings)
6a566b9c 2045{
2046 if (!*settings)
2047 return;
2048 free_string(&(*settings)->type);
2049 free_wordlist(&(*settings)->args);
2050 xfree(*settings);
2051 *settings = NULL;
2052}
2053
2054static void
c1dd71ae 2055parse_removalpolicy(RemovalPolicySettings ** settings)
6a566b9c 2056{
2057 if (*settings)
2058 free_removalpolicy(settings);
2059 *settings = xcalloc(1, sizeof(**settings));
2060 parse_string(&(*settings)->type);
2061 parse_wordlist(&(*settings)->args);
2062}
2063
2064static void
c1dd71ae 2065dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
6a566b9c 2066{
2067 wordlist *args;
2068 storeAppendPrintf(entry, "%s %s", name, settings->type);
2069 args = settings->args;
2070 while (args) {
2071 storeAppendPrintf(entry, " %s", args->key);
2072 args = args->next;
2073 }
be58afb5 2074 storeAppendPrintf(entry, "\n");
6a566b9c 2075}
c1dd71ae 2076
6a566b9c 2077
1ee67578 2078#include "cf_parser.h"
f1dc9b30 2079
2080peer_t
2081parseNeighborType(const char *s)
2082{
2083 if (!strcasecmp(s, "parent"))
2084 return PEER_PARENT;
2085 if (!strcasecmp(s, "neighbor"))
2086 return PEER_SIBLING;
2087 if (!strcasecmp(s, "neighbour"))
2088 return PEER_SIBLING;
2089 if (!strcasecmp(s, "sibling"))
2090 return PEER_SIBLING;
2091 if (!strcasecmp(s, "multicast"))
2092 return PEER_MULTICAST;
2093 debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s);
2094 return PEER_SIBLING;
2095}
f150dd4b 2096
7e3ce7b9 2097static void
2098parse_sockaddr_in_list(sockaddr_in_list ** head)
2099{
2100 char *token;
2101 char *t;
efd900cb 2102 char *host;
7e3ce7b9 2103 const struct hostent *hp;
efd900cb 2104 unsigned short port;
7e3ce7b9 2105 sockaddr_in_list *s;
2106 while ((token = strtok(NULL, w_space))) {
efd900cb 2107 host = NULL;
2108 port = 0;
7e3ce7b9 2109 if ((t = strchr(token, ':'))) {
2110 /* host:port */
2111 host = token;
2112 *t = '\0';
efd900cb 2113 port = (unsigned short) atoi(t + 1);
2114 if (0 == port)
7e3ce7b9 2115 self_destruct();
efd900cb 2116 } else if ((port = atoi(token)) > 0) {
7e3ce7b9 2117 /* port */
2118 } else {
2119 self_destruct();
2120 }
2121 s = xcalloc(1, sizeof(*s));
efd900cb 2122 s->s.sin_port = htons(port);
7e3ce7b9 2123 if (NULL == host)
2124 s->s.sin_addr = any_addr;
2125 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
2126 (void) 0;
efd900cb 2127 else if ((hp = gethostbyname(host))) /* dont use ipcache */
7e3ce7b9 2128 s->s.sin_addr = inaddrFromHostent(hp);
2129 else
2130 self_destruct();
2131 while (*head)
2132 head = &(*head)->next;
2133 *head = s;
2134 }
2135}
2136
2137static void
2138dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
2139{
2140 while (s) {
2141 storeAppendPrintf(e, "%s %s:%d\n",
2142 n,
2143 inet_ntoa(s->s.sin_addr),
2144 ntohs(s->s.sin_port));
2145 s = s->next;
2146 }
2147}
2148
2149static void
2150free_sockaddr_in_list(sockaddr_in_list ** head)
2151{
2152 sockaddr_in_list *s;
2153 while ((s = *head) != NULL) {
2154 *head = s->next;
2155 xfree(s);
2156 }
2157}
2158
2159static int
2160check_null_sockaddr_in_list(const sockaddr_in_list * s)
2161{
2162 return NULL == s;
2163}
2164
d193a436 2165#if USE_SSL
2166static void
2167parse_https_port_list(https_port_list ** head)
2168{
2169 char *token;
2170 char *t;
2171 char *host;
2172 const struct hostent *hp;
2173 unsigned short port;
2174 https_port_list *s;
2175 token = strtok(NULL, w_space);
2176 if (!token)
2177 self_destruct();
2178 host = NULL;
2179 port = 0;
2180 if ((t = strchr(token, ':'))) {
2181 /* host:port */
2182 host = token;
2183 *t = '\0';
2184 port = (unsigned short) atoi(t + 1);
2185 if (0 == port)
2186 self_destruct();
2187 } else if ((port = atoi(token)) > 0) {
2188 /* port */
2189 } else {
2190 self_destruct();
2191 }
2192 s = xcalloc(1, sizeof(*s));
2193 s->s.sin_port = htons(port);
2194 if (NULL == host)
2195 s->s.sin_addr = any_addr;
2196 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
2197 (void) 0;
2198 else if ((hp = gethostbyname(host))) /* dont use ipcache */
2199 s->s.sin_addr = inaddrFromHostent(hp);
2200 else
2201 self_destruct();
2202 /* parse options ... */
2203 while ((token = strtok(NULL, w_space))) {
2204 if (strncmp(token, "cert=", 5) == 0) {
2205 safe_free(s->cert);
2206 s->cert = xstrdup(token + 5);
2207 } else if (strncmp(token, "key=", 4) == 0) {
2208 safe_free(s->key);
2209 s->key = xstrdup(token + 4);
2210 } else {
2211 self_destruct();
2212 }
2213 }
2214 while (*head)
2215 head = &(*head)->next;
2216 *head = s;
2217}
2218
2219static void
2220dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
2221{
2222 while (s) {
2223 storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"\n",
2224 n,
2225 inet_ntoa(s->s.sin_addr),
2226 ntohs(s->s.sin_port),
2227 s->cert,
2228 s->key);
2229 s = s->next;
2230 }
2231}
2232
2233static void
2234free_https_port_list(https_port_list ** head)
2235{
2236 https_port_list *s;
2237 while ((s = *head) != NULL) {
2238 *head = s->next;
2239 safe_free(s->cert);
2240 safe_free(s->key);
2241 safe_free(s);
2242 }
2243}
2244
2245#if 0
2246static int
2247check_null_https_port_list(const https_port_list * s)
2248{
2249 return NULL == s;
2250}
2251#endif
2252
2253#endif /* USE_SSL */
2254
f150dd4b 2255void
2256configFreeMemory(void)
2257{
42bf7c64 2258 safe_free(Config2.Accel.prefix);
23ff6968 2259 free_all();
f150dd4b 2260}
f0b19334 2261
94439e4e 2262void
f0b19334 2263requirePathnameExists(const char *name, const char *path)
2264{
2265 struct stat sb;
f0b19334 2266 assert(path != NULL);
137ee196 2267 if (stat(path, &sb) < 0)
2268 fatalf("%s: %s", path, xstrerror());
f0b19334 2269}