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