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