3 * $Id: cache_cf.cc,v 1.343 2000/05/03 17:15:41 adrian Exp $
5 * DEBUG: section 3 Configuration File Parsing
6 * AUTHOR: Harvest Derived
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * CREDITS file for full details.
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.
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.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
42 static const char *const T_SECOND_STR
= "second";
43 static const char *const T_MINUTE_STR
= "minute";
44 static const char *const T_HOUR_STR
= "hour";
45 static const char *const T_DAY_STR
= "day";
46 static const char *const T_WEEK_STR
= "week";
47 static const char *const T_FORTNIGHT_STR
= "fortnight";
48 static const char *const T_MONTH_STR
= "month";
49 static const char *const T_YEAR_STR
= "year";
50 static const char *const T_DECADE_STR
= "decade";
52 static const char *const B_BYTES_STR
= "bytes";
53 static const char *const B_KBYTES_STR
= "KB";
54 static const char *const B_MBYTES_STR
= "MB";
55 static const char *const B_GBYTES_STR
= "GB";
57 static const char *const list_sep
= ", \t\n\r";
58 static int http_header_first
;
59 static int http_header_allowed
= 0;
61 static void update_maxobjsize(void);
62 static void configDoConfigure(void);
63 static void parse_refreshpattern(refresh_t
**);
64 static int parseTimeUnits(const char *unit
);
65 static void parseTimeLine(time_t * tptr
, const char *units
);
66 static void parse_ushort(u_short
* var
);
67 static void parse_string(char **);
68 static void parse_wordlist(wordlist
**);
69 static void default_all(void);
70 static void defaults_if_none(void);
71 static int parse_line(char *);
72 static void parseBytesLine(size_t * bptr
, const char *units
);
73 static size_t parseBytesUnits(const char *unit
);
74 static void free_all(void);
75 static void requirePathnameExists(const char *name
, const char *path
);
76 static OBJH dump_config
;
77 static void dump_http_header(StoreEntry
* entry
, const char *name
, HttpHeaderMask header
);
78 static void parse_http_header(HttpHeaderMask
* header
);
79 static void free_http_header(HttpHeaderMask
* header
);
80 static void parse_sockaddr_in_list(sockaddr_in_list
**);
81 static void dump_sockaddr_in_list(StoreEntry
*, const char *, const sockaddr_in_list
*);
82 static void free_sockaddr_in_list(sockaddr_in_list
**);
83 static int check_null_sockaddr_in_list(const sockaddr_in_list
*);
88 fatalf("Bungled %s line %d: %s",
89 cfg_filename
, config_lineno
, config_input_line
);
93 wordlistDestroy(wordlist
** list
)
96 while ((w
= *list
) != NULL
) {
99 memFree(w
, MEM_WORDLIST
);
105 wordlistAdd(wordlist
** list
, const char *key
)
108 list
= &(*list
)->next
;
109 *list
= memAllocate(MEM_WORDLIST
);
110 (*list
)->key
= xstrdup(key
);
111 (*list
)->next
= NULL
;
116 wordlistJoin(wordlist
** list
, wordlist
**wl
)
119 list
= &(*list
)->next
;
125 wordlistAddWl(wordlist
** list
, wordlist
*wl
)
128 list
= &(*list
)->next
;
129 for(;wl
;wl
=wl
->next
, list
= &(*list
)->next
) {
130 *list
= memAllocate(MEM_WORDLIST
);
131 (*list
)->key
= xstrdup(wl
->key
);
132 (*list
)->next
= NULL
;
137 wordlistCat(const wordlist
* w
, MemBuf
* mb
)
140 memBufPrintf(mb
, "%s\n", w
->key
);
146 wordlistDup(const wordlist
* w
)
150 wordlistAdd(&D
, w
->key
);
157 intlistDestroy(intlist
** list
)
161 for (w
= *list
; w
; w
= n
) {
163 memFree(w
, MEM_INTLIST
);
169 intlistFind(intlist
* list
, int i
)
172 for (w
= list
; w
; w
= w
->next
)
180 * Use this #define in all the parse*() functions. Assumes char *token is
187 char *token
= strtok(NULL
, w_space
);
191 if (sscanf(token
, "%d", &i
) != 1)
197 update_maxobjsize(void)
202 for (i
= 0; i
< Config
.cacheSwap
.n_configured
; i
++) {
203 if (Config
.cacheSwap
.swapDirs
[i
].max_objsize
> ms
)
204 ms
= Config
.cacheSwap
.swapDirs
[i
].max_objsize
;
206 store_maxobjsize
= ms
;
210 parseConfigFile(const char *file_name
)
218 if ((fp
= fopen(file_name
, "r")) == NULL
)
219 fatalf("Unable to open configuration file: %s: %s",
220 file_name
, xstrerror());
221 cfg_filename
= file_name
;
222 if ((token
= strrchr(cfg_filename
, '/')))
223 cfg_filename
= token
+ 1;
224 memset(config_input_line
, '\0', BUFSIZ
);
226 http_header_first
= 0;
227 while (fgets(config_input_line
, BUFSIZ
, fp
)) {
229 if ((token
= strchr(config_input_line
, '\n')))
231 if (config_input_line
[0] == '#')
233 if (config_input_line
[0] == '\0')
235 debug(3, 5) ("Processing: '%s'\n", config_input_line
);
236 tmp_line
= xstrdup(config_input_line
);
237 if (!parse_line(tmp_line
)) {
238 debug(3, 0) ("parseConfigFile: line %d unrecognized: '%s'\n",
248 cachemgrRegister("config",
249 "Current Squid Configuration",
256 configDoConfigure(void)
258 LOCAL_ARRAY(char, buf
, BUFSIZ
);
259 memset(&Config2
, '\0', sizeof(SquidConfig2
));
260 /* init memory as early as possible */
263 if (Config
.cacheSwap
.swapDirs
== NULL
)
264 fatal("No cache_dir's specified in config file");
265 /* calculate Config.Swap.maxSize */
267 if (Config
.Swap
.maxSize
< (Config
.memMaxSize
>> 10))
268 fatal("cache_swap is lower than cache_mem");
269 if (Config
.Announce
.period
> 0) {
270 Config
.onoff
.announce
= 1;
271 } else if (Config
.Announce
.period
< 1) {
272 Config
.Announce
.period
= 86400 * 365; /* one year */
273 Config
.onoff
.announce
= 0;
276 if (Config
.dnsChildren
< 1)
277 fatal("No dnsservers allocated");
278 if (Config
.dnsChildren
> DefaultDnsChildrenMax
) {
279 debug(3, 0) ("WARNING: dns_children was set to a bad value: %d\n",
281 debug(3, 0) ("Setting it to the maximum (%d).\n",
282 DefaultDnsChildrenMax
);
283 Config
.dnsChildren
= DefaultDnsChildrenMax
;
286 if (Config
.Program
.redirect
) {
287 if (Config
.redirectChildren
< 1) {
288 Config
.redirectChildren
= 0;
289 wordlistDestroy(&Config
.Program
.redirect
);
290 } else if (Config
.redirectChildren
> DefaultRedirectChildrenMax
) {
291 debug(3, 0) ("WARNING: redirect_children was set to a bad value: %d\n",
292 Config
.redirectChildren
);
293 debug(3, 0) ("Setting it to the maximum (%d).\n", DefaultRedirectChildrenMax
);
294 Config
.redirectChildren
= DefaultRedirectChildrenMax
;
297 if (Config
.Program
.authenticate
) {
298 if (Config
.authenticateChildren
< 1) {
299 Config
.authenticateChildren
= 0;
300 wordlistDestroy(&Config
.Program
.authenticate
);
301 } else if (Config
.authenticateChildren
> DefaultAuthenticateChildrenMax
) {
302 debug(3, 0) ("WARNING: authenticate_children was set to a bad value: %d\n",
303 Config
.authenticateChildren
);
304 debug(3, 0) ("Setting it to the maximum (%d).\n", DefaultAuthenticateChildrenMax
);
305 Config
.authenticateChildren
= DefaultAuthenticateChildrenMax
;
308 if (Config
.Accel
.host
) {
309 snprintf(buf
, BUFSIZ
, "http://%s:%d", Config
.Accel
.host
, Config
.Accel
.port
);
310 Config2
.Accel
.prefix
= xstrdup(buf
);
311 Config2
.Accel
.on
= 1;
313 if (Config
.appendDomain
)
314 if (*Config
.appendDomain
!= '.')
315 fatal("append_domain must begin with a '.'");
316 if (Config
.errHtmlText
== NULL
)
317 Config
.errHtmlText
= xstrdup(null_string
);
319 if (Config2
.Accel
.on
&& !strcmp(Config
.Accel
.host
, "virtual"))
321 if (Config
.Sockaddr
.http
== NULL
)
322 fatal("No http_port specified!");
323 snprintf(ThisCache
, sizeof(ThisCache
), "%s:%d (%s)",
325 (int) ntohs(Config
.Sockaddr
.http
->s
.sin_port
),
326 full_appname_string
);
328 * the extra space is for loop detection in client_side.c -- we search
329 * for substrings in the Via header.
331 snprintf(ThisCache2
, sizeof(ThisCache
), " %s:%d (%s)",
333 (int) ntohs(Config
.Sockaddr
.http
->s
.sin_port
),
334 full_appname_string
);
335 if (!Config
.udpMaxHitObjsz
|| Config
.udpMaxHitObjsz
> SQUID_UDP_SO_SNDBUF
)
336 Config
.udpMaxHitObjsz
= SQUID_UDP_SO_SNDBUF
;
337 if (Config
.appendDomain
)
338 Config
.appendDomainLen
= strlen(Config
.appendDomain
);
340 Config
.appendDomainLen
= 0;
341 safe_free(debug_options
)
342 debug_options
= xstrdup(Config
.debugOptions
);
343 if (Config
.retry
.timeout
< 5)
344 fatal("minimum_retry_timeout must be at least 5 seconds");
345 if (Config
.retry
.maxtries
> 10)
346 fatal("maximum_single_addr_tries cannot be larger than 10");
347 if (Config
.retry
.maxtries
< 1) {
348 debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
349 Config
.retry
.maxtries
= 1;
352 /* The non-LRU policies do not use referenceAge */
354 if (Config
.referenceAge
< 300) {
355 debug(3, 0) ("WARNING: resetting 'reference_age' to 1 week\n");
356 Config
.referenceAge
= 86400 * 7;
359 requirePathnameExists("MIME Config Table", Config
.mimeTablePathname
);
361 requirePathnameExists("cache_dns_program", Config
.Program
.dnsserver
);
363 requirePathnameExists("unlinkd_program", Config
.Program
.unlinkd
);
364 if (Config
.Program
.redirect
)
365 requirePathnameExists("redirect_program", Config
.Program
.redirect
->key
);
366 if (Config
.Program
.authenticate
)
367 requirePathnameExists("authenticate_program", Config
.Program
.authenticate
->key
);
368 requirePathnameExists("Icon Directory", Config
.icons
.directory
);
369 requirePathnameExists("Error Directory", Config
.errorDirectory
);
373 for (R
= Config
.Refresh
; R
; R
= R
->next
) {
374 if (!R
->flags
.override_expire
)
376 debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
379 for (R
= Config
.Refresh
; R
; R
= R
->next
) {
380 if (!R
->flags
.override_lastmod
)
382 debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
387 if (Config
.Wais
.relayHost
) {
388 if (Config
.Wais
.peer
)
389 cbdataFree(Config
.Wais
.peer
);
390 Config
.Wais
.peer
= memAllocate(MEM_PEER
);
391 cbdataAdd(Config
.Wais
.peer
, peerDestroy
, MEM_PEER
);
392 Config
.Wais
.peer
->host
= xstrdup(Config
.Wais
.relayHost
);
393 Config
.Wais
.peer
->http_port
= Config
.Wais
.relayPort
;
395 if (aclPurgeMethodInUse(Config
.accessList
.http
))
396 Config2
.onoff
.enable_purge
= 1;
399 /* Parse a time specification from the config file. Store the
400 * result in 'tptr', after converting it to 'units' */
402 parseTimeLine(time_t * tptr
, const char *units
)
408 if ((u
= parseTimeUnits(units
)) == 0)
410 if ((token
= strtok(NULL
, w_space
)) == NULL
)
413 m
= u
; /* default to 'units' if none specified */
416 else if ((token
= strtok(NULL
, w_space
)) == NULL
)
417 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
418 config_input_line
, d
, units
);
419 else if ((m
= parseTimeUnits(token
)) == 0)
425 parseTimeUnits(const char *unit
)
427 if (!strncasecmp(unit
, T_SECOND_STR
, strlen(T_SECOND_STR
)))
429 if (!strncasecmp(unit
, T_MINUTE_STR
, strlen(T_MINUTE_STR
)))
431 if (!strncasecmp(unit
, T_HOUR_STR
, strlen(T_HOUR_STR
)))
433 if (!strncasecmp(unit
, T_DAY_STR
, strlen(T_DAY_STR
)))
435 if (!strncasecmp(unit
, T_WEEK_STR
, strlen(T_WEEK_STR
)))
437 if (!strncasecmp(unit
, T_FORTNIGHT_STR
, strlen(T_FORTNIGHT_STR
)))
439 if (!strncasecmp(unit
, T_MONTH_STR
, strlen(T_MONTH_STR
)))
441 if (!strncasecmp(unit
, T_YEAR_STR
, strlen(T_YEAR_STR
)))
442 return 86400 * 365.2522;
443 if (!strncasecmp(unit
, T_DECADE_STR
, strlen(T_DECADE_STR
)))
444 return 86400 * 365.2522 * 10;
445 debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit
);
450 parseBytesLine(size_t * bptr
, const char *units
)
456 if ((u
= parseBytesUnits(units
)) == 0)
458 if ((token
= strtok(NULL
, w_space
)) == NULL
)
461 m
= u
; /* default to 'units' if none specified */
464 else if ((token
= strtok(NULL
, w_space
)) == NULL
)
465 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
466 config_input_line
, d
, units
);
467 else if ((m
= parseBytesUnits(token
)) == 0)
473 parseBytesUnits(const char *unit
)
475 if (!strncasecmp(unit
, B_BYTES_STR
, strlen(B_BYTES_STR
)))
477 if (!strncasecmp(unit
, B_KBYTES_STR
, strlen(B_KBYTES_STR
)))
479 if (!strncasecmp(unit
, B_MBYTES_STR
, strlen(B_MBYTES_STR
)))
481 if (!strncasecmp(unit
, B_GBYTES_STR
, strlen(B_GBYTES_STR
)))
483 debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit
);
487 /*****************************************************************************
489 *****************************************************************************/
492 dump_acl(StoreEntry
* entry
, const char *name
, acl
* ae
)
497 debug(3, 3) ("dump_acl: %s %s\n", name
, ae
->name
);
498 v
= w
= aclDumpGeneric(ae
);
500 debug(3, 3) ("dump_acl: %s %s %s\n", name
, ae
->name
, v
->key
);
501 storeAppendPrintf(entry
, "%s %s %s %s\n",
504 aclTypeToStr(ae
->type
),
526 dump_acl_access(StoreEntry
* entry
, const char *name
, acl_access
* head
)
529 while (head
!= NULL
) {
530 storeAppendPrintf(entry
, "%s %s",
532 head
->allow
? "Allow" : "Deny");
533 for (l
= head
->acl_list
; l
!= NULL
; l
= l
->next
) {
534 storeAppendPrintf(entry
, " %s%s",
535 l
->op
? null_string
: "!",
538 storeAppendPrintf(entry
, "\n");
544 parse_acl_access(acl_access
** head
)
546 aclParseAccessLine(head
);
550 free_acl_access(acl_access
** head
)
552 aclDestroyAccessList(head
);
556 dump_address(StoreEntry
* entry
, const char *name
, struct in_addr addr
)
558 storeAppendPrintf(entry
, "%s %s\n", name
, inet_ntoa(addr
));
562 parse_address(struct in_addr
*addr
)
564 const struct hostent
*hp
;
565 char *token
= strtok(NULL
, w_space
);
569 if (safe_inet_addr(token
, addr
) == 1)
571 else if ((hp
= gethostbyname(token
))) /* dont use ipcache */
572 *addr
= inaddrFromHostent(hp
);
578 free_address(struct in_addr
*addr
)
580 memset(addr
, '\0', sizeof(struct in_addr
));
585 /* do nothing - free_delay_pool_count is the magic free function.
586 * this is why delay_pool_count isn't just marked TYPE: ushort
588 #define free_delay_pool_class(X)
589 #define free_delay_pool_access(X)
590 #define free_delay_pool_rates(X)
591 #define dump_delay_pool_class(X, Y, Z)
592 #define dump_delay_pool_access(X, Y, Z)
593 #define dump_delay_pool_rates(X, Y, Z)
596 free_delay_pool_count(delayConfig
* cfg
)
602 for (i
= 0; i
< cfg
->pools
; i
++) {
604 delayFreeDelayPool(i
);
605 safe_free(cfg
->rates
[i
]);
607 aclDestroyAccessList(&cfg
->access
[i
]);
609 delayFreeDelayData();
613 memset(cfg
, 0, sizeof(*cfg
));
617 dump_delay_pool_count(StoreEntry
* entry
, const char *name
, delayConfig cfg
)
620 LOCAL_ARRAY(char, nom
, 32);
623 storeAppendPrintf(entry
, "%s 0\n", name
);
626 storeAppendPrintf(entry
, "%s %d\n", name
, cfg
.pools
);
627 for (i
= 0; i
< cfg
.pools
; i
++) {
628 storeAppendPrintf(entry
, "delay_class %d %d\n", i
+ 1, cfg
.class[i
]);
629 snprintf(nom
, 32, "delay_access %d", i
+ 1);
630 dump_acl_access(entry
, nom
, cfg
.access
[i
]);
631 if (cfg
.class[i
] >= 1)
632 storeAppendPrintf(entry
, "delay_parameters %d %d/%d", i
+ 1,
633 cfg
.rates
[i
]->aggregate
.restore_bps
,
634 cfg
.rates
[i
]->aggregate
.max_bytes
);
635 if (cfg
.class[i
] >= 3)
636 storeAppendPrintf(entry
, " %d/%d",
637 cfg
.rates
[i
]->network
.restore_bps
,
638 cfg
.rates
[i
]->network
.max_bytes
);
639 if (cfg
.class[i
] >= 2)
640 storeAppendPrintf(entry
, " %d/%d",
641 cfg
.rates
[i
]->individual
.restore_bps
,
642 cfg
.rates
[i
]->individual
.max_bytes
);
643 if (cfg
.class[i
] >= 1)
644 storeAppendPrintf(entry
, "\n");
649 parse_delay_pool_count(delayConfig
* cfg
)
652 debug(3, 0) ("parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config\n");
653 free_delay_pool_count(cfg
);
655 parse_ushort(&cfg
->pools
);
656 delayInitDelayData(cfg
->pools
);
657 cfg
->class = xcalloc(cfg
->pools
, sizeof(u_char
));
658 cfg
->rates
= xcalloc(cfg
->pools
, sizeof(delaySpecSet
*));
659 cfg
->access
= xcalloc(cfg
->pools
, sizeof(acl_access
*));
663 parse_delay_pool_class(delayConfig
* cfg
)
668 if (pool
< 1 || pool
> cfg
->pools
) {
669 debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d not in 1 .. %d\n", pool
, cfg
->pools
);
672 parse_ushort(&class);
673 if (class < 1 || class > 3) {
674 debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d class %d not in 1 .. 3\n", pool
, class);
678 if (cfg
->class[pool
]) {
679 delayFreeDelayPool(pool
);
680 safe_free(cfg
->rates
[pool
]);
682 cfg
->rates
[pool
] = xmalloc(class * sizeof(delaySpec
));
683 cfg
->class[pool
] = class;
684 cfg
->rates
[pool
]->aggregate
.restore_bps
= cfg
->rates
[pool
]->aggregate
.max_bytes
= -1;
685 if (cfg
->class[pool
] >= 3)
686 cfg
->rates
[pool
]->network
.restore_bps
= cfg
->rates
[pool
]->network
.max_bytes
= -1;
687 if (cfg
->class[pool
] >= 2)
688 cfg
->rates
[pool
]->individual
.restore_bps
= cfg
->rates
[pool
]->individual
.max_bytes
= -1;
689 delayCreateDelayPool(pool
, class);
693 parse_delay_pool_rates(delayConfig
* cfg
)
701 if (pool
< 1 || pool
> cfg
->pools
) {
702 debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool
, cfg
->pools
);
706 class = cfg
->class[pool
];
708 debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d attempt to set rates with class not set\n", pool
+ 1);
711 ptr
= (delaySpec
*) cfg
->rates
[pool
];
712 /* read in "class" sets of restore,max pairs */
714 token
= strtok(NULL
, "/");
717 if (sscanf(token
, "%d", &i
) != 1)
719 ptr
->restore_bps
= i
;
724 class = cfg
->class[pool
];
725 /* if class is 3, swap around network and individual */
729 tmp
= cfg
->rates
[pool
]->individual
;
730 cfg
->rates
[pool
]->individual
= cfg
->rates
[pool
]->network
;
731 cfg
->rates
[pool
]->network
= tmp
;
733 /* initialize the delay pools */
734 delayInitDelayPool(pool
, class, cfg
->rates
[pool
]);
738 parse_delay_pool_access(delayConfig
* cfg
)
743 if (pool
< 1 || pool
> cfg
->pools
) {
744 debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool
, cfg
->pools
);
747 aclParseAccessLine(&cfg
->access
[pool
- 1]);
752 dump_http_header(StoreEntry
* entry
, const char *name
, HttpHeaderMask header
)
755 for (i
= 0; i
< HDR_OTHER
; i
++) {
756 if (http_header_allowed
&& !CBIT_TEST(header
, i
))
757 storeAppendPrintf(entry
, "%s allow %s\n", name
, httpHeaderNameById(i
));
758 else if (!http_header_allowed
&& CBIT_TEST(header
, i
))
759 storeAppendPrintf(entry
, "%s deny %s\n", name
, httpHeaderNameById(i
));
764 parse_http_header(HttpHeaderMask
* header
)
768 if ((t
= strtok(NULL
, w_space
)) == NULL
) {
769 debug(3, 0) ("%s line %d: %s\n",
770 cfg_filename
, config_lineno
, config_input_line
);
771 debug(3, 0) ("parse_http_header: missing 'allow' or 'deny'.\n");
774 if (!strcmp(t
, "allow"))
776 else if (!strcmp(t
, "deny"))
779 debug(3, 0) ("%s line %d: %s\n",
780 cfg_filename
, config_lineno
, config_input_line
);
781 debug(3, 0) ("parse_http_header: expecting 'allow' or 'deny', got '%s'.\n", t
);
784 if (!http_header_first
) {
785 http_header_first
= 1;
787 http_header_allowed
= 1;
788 httpHeaderMaskInit(header
, 0xFF);
790 http_header_allowed
= 0;
791 httpHeaderMaskInit(header
, 0);
794 while ((t
= strtok(NULL
, w_space
))) {
795 if ((id
= httpHeaderIdByNameDef(t
, strlen(t
))) == -1)
796 debug(3, 0) ("parse_http_header: Ignoring unknown header '%s'\n", t
);
798 CBIT_CLR(*header
, id
);
800 CBIT_SET(*header
, id
);
805 free_http_header(HttpHeaderMask
* header
)
807 httpHeaderMaskInit(header
, 0);
811 dump_cachedir(StoreEntry
* entry
, const char *name
, cacheSwap swap
)
815 for (i
= 0; i
< swap
.n_configured
; i
++) {
816 s
= swap
.swapDirs
+ i
;
817 s
->dump(entry
, name
, s
);
822 check_null_cachedir(cacheSwap swap
)
824 return swap
.swapDirs
== NULL
;
828 check_null_string(char *s
)
834 allocate_new_swapdir(cacheSwap
* swap
)
836 if (swap
->swapDirs
== NULL
) {
837 swap
->n_allocated
= 4;
838 swap
->swapDirs
= xcalloc(swap
->n_allocated
, sizeof(SwapDir
));
840 if (swap
->n_allocated
== swap
->n_configured
) {
842 swap
->n_allocated
<<= 1;
843 tmp
= xcalloc(swap
->n_allocated
, sizeof(SwapDir
));
844 xmemcpy(tmp
, swap
->swapDirs
, swap
->n_configured
* sizeof(SwapDir
));
845 xfree(swap
->swapDirs
);
846 swap
->swapDirs
= tmp
;
851 find_fstype(char *type
)
854 for (i
= 0; storefs_list
[i
].typestr
!= NULL
; i
++) {
855 if (strcasecmp(type
, storefs_list
[i
].typestr
) == 0) {
863 parse_cachedir(cacheSwap
* swap
)
872 if ((type_str
= strtok(NULL
, w_space
)) == NULL
)
875 maxobjsize
= (size_t)GetInteger();
877 if ((path_str
= strtok(NULL
, w_space
)) == NULL
)
881 * This bit of code is a little strange.
882 * See, if we find a path and type match for a given line, then
883 * as long as we're reconfiguring, we can just call its reconfigure
884 * function. No harm there.
886 * Trouble is, if we find a path match, but not a type match, we have
887 * a dilemma - we could gracefully shut down the fs, kill it, and
888 * create a new one of a new type in its place, BUT at this stage the
889 * fs is meant to be the *NEW* one, and so things go very strange. :-)
891 * So, we'll assume the person isn't going to change the fs type for now,
892 * and XXX later on we will make sure that its picked up.
894 * (moving around cache_dir lines will be looked at later in a little
895 * more sane detail..)
898 for (i
= 0; i
< swap
->n_configured
; i
++) {
899 if (0 == strcasecmp(path_str
, swap
->swapDirs
[i
].path
)) {
900 /* This is a little weird, you'll appreciate it later */
901 fs
= find_fstype(type_str
);
903 fatalf("Unknown cache_dir type '%s'\n", type_str
);
905 sd
= swap
->swapDirs
+ i
;
906 storefs_list
[fs
].reconfigurefunc(sd
, i
, path_str
);
907 sd
->max_objsize
= maxobjsize
;
913 fs
= find_fstype(type_str
);
915 /* If we get here, we didn't find a matching cache_dir type */
916 fatalf("Unknown cache_dir type '%s'\n", type_str
);
919 allocate_new_swapdir(swap
);
920 sd
= swap
->swapDirs
+ swap
->n_configured
;
921 storefs_list
[fs
].parsefunc(sd
, swap
->n_configured
, path_str
);
922 /* XXX should we dupe the string here, in case it gets trodden on? */
923 sd
->type
= storefs_list
[fs
].typestr
;
924 sd
->max_objsize
= maxobjsize
;
925 swap
->n_configured
++;
926 /* Update the max object size */
931 free_cachedir(cacheSwap
* swap
)
935 /* DON'T FREE THESE FOR RECONFIGURE */
938 for (i
= 0; i
< swap
->n_configured
; i
++) {
939 s
= swap
->swapDirs
+ i
;
943 safe_free(swap
->swapDirs
);
944 swap
->swapDirs
= NULL
;
945 swap
->n_allocated
= 0;
946 swap
->n_configured
= 0;
950 peer_type_str(const peer_t type
)
969 dump_peer(StoreEntry
* entry
, const char *name
, peer
* p
)
974 LOCAL_ARRAY(char, xname
, 128);
976 storeAppendPrintf(entry
, "%s %s %s %d %d",
982 dump_peer_options(entry
, p
);
983 for (d
= p
->peer_domain
; d
; d
= d
->next
) {
984 storeAppendPrintf(entry
, "cache_peer_domain %s %s%s\n",
986 d
->do_ping
? null_string
: "!",
989 if ((a
= p
->access
)) {
990 snprintf(xname
, 128, "cache_peer_access %s", p
->host
);
991 dump_acl_access(entry
, xname
, p
->access
);
993 for (t
= p
->typelist
; t
; t
= t
->next
) {
994 storeAppendPrintf(entry
, "neighbor_type_domain %s %s %s\n",
996 peer_type_str(t
->type
),
1004 parse_peer(peer
** head
)
1009 sockaddr_in_list
*s
;
1010 const char *me
= null_string
; /* XXX */
1011 p
= memAllocate(MEM_PEER
);
1012 p
->http_port
= CACHE_HTTP_PORT
;
1013 p
->icp
.port
= CACHE_ICP_PORT
;
1015 p
->stats
.logged_state
= PEER_ALIVE
;
1016 if ((token
= strtok(NULL
, w_space
)) == NULL
)
1018 p
->host
= xstrdup(token
);
1019 if ((token
= strtok(NULL
, w_space
)) == NULL
)
1021 p
->type
= parseNeighborType(token
);
1023 p
->http_port
= (u_short
) i
;
1025 p
->icp
.port
= (u_short
) i
;
1026 if (strcmp(p
->host
, me
) == 0) {
1027 for (s
= Config
.Sockaddr
.http
; s
; s
= s
->next
) {
1028 if (p
->http_port
!= ntohs(s
->s
.sin_port
))
1030 debug(15, 0) ("parse_peer: Peer looks like myself: %s %s/%d/%d\n",
1031 p
->type
, p
->host
, p
->http_port
, p
->icp
.port
);
1035 while ((token
= strtok(NULL
, w_space
))) {
1036 if (!strcasecmp(token
, "proxy-only")) {
1037 p
->options
.proxy_only
= 1;
1038 } else if (!strcasecmp(token
, "no-query")) {
1039 p
->options
.no_query
= 1;
1040 } else if (!strcasecmp(token
, "no-digest")) {
1041 p
->options
.no_digest
= 1;
1042 } else if (!strcasecmp(token
, "multicast-responder")) {
1043 p
->options
.mcast_responder
= 1;
1044 } else if (!strncasecmp(token
, "weight=", 7)) {
1045 p
->weight
= atoi(token
+ 7);
1046 } else if (!strcasecmp(token
, "closest-only")) {
1047 p
->options
.closest_only
= 1;
1048 } else if (!strncasecmp(token
, "ttl=", 4)) {
1049 p
->mcast
.ttl
= atoi(token
+ 4);
1050 if (p
->mcast
.ttl
< 0)
1052 if (p
->mcast
.ttl
> 128)
1054 } else if (!strcasecmp(token
, "default")) {
1055 p
->options
.default_parent
= 1;
1056 } else if (!strcasecmp(token
, "round-robin")) {
1057 p
->options
.roundrobin
= 1;
1059 } else if (!strcasecmp(token
, "htcp")) {
1060 p
->options
.htcp
= 1;
1062 } else if (!strcasecmp(token
, "no-netdb-exchange")) {
1063 p
->options
.no_netdb_exchange
= 1;
1065 } else if (!strncasecmp(token
, "carp-load-factor=", 17)) {
1066 if (p
->type
!= PEER_PARENT
)
1067 debug(3, 0) ("parse_peer: Ignoring carp-load-factor for non-parent %s/%d\n", p
->host
, p
->http_port
);
1069 p
->carp
.load_factor
= atof(token
+ 17);
1072 } else if (!strcasecmp(token
, "no-delay")) {
1073 p
->options
.no_delay
= 1;
1075 } else if (!strncasecmp(token
, "login=", 6)) {
1076 p
->login
= xstrdup(token
+ 6);
1077 } else if (!strncasecmp(token
, "connect-timeout=", 16)) {
1078 p
->connect_timeout
= atoi(token
+ 16);
1079 #if USE_CACHE_DIGESTS
1080 } else if (!strncasecmp(token
, "digest-url=", 11)) {
1081 p
->digest_url
= xstrdup(token
+ 11);
1083 } else if (!strcasecmp(token
, "allow-miss")) {
1084 p
->options
.allow_miss
= 1;
1086 debug(3, 0) ("parse_peer: token='%s'\n", token
);
1092 p
->icp
.version
= ICP_VERSION_CURRENT
;
1093 p
->tcp_up
= PEER_TCP_MAGIC_COUNT
;
1096 if (p
->carp
.load_factor
) {
1097 /* calculate this peers hash for use in CARP */
1099 for (token
= p
->host
; *token
!= 0; token
++)
1100 p
->carp
.hash
+= (p
->carp
.hash
<< 19) + *token
;
1103 /* This must preceed peerDigestCreate */
1104 cbdataAdd(p
, peerDestroy
, MEM_PEER
);
1105 #if USE_CACHE_DIGESTS
1106 if (!p
->options
.no_digest
) {
1107 p
->digest
= peerDigestCreate(p
);
1108 cbdataLock(p
->digest
); /* so we know when/if digest disappears */
1111 while (*head
!= NULL
)
1112 head
= &(*head
)->next
;
1119 free_peer(peer
** P
)
1122 while ((p
= *P
) != NULL
) {
1124 #if USE_CACHE_DIGESTS
1126 cbdataUnlock(p
->digest
);
1135 dump_cachemgrpasswd(StoreEntry
* entry
, const char *name
, cachemgr_passwd
* list
)
1138 while (list
!= NULL
) {
1139 if (strcmp(list
->passwd
, "none") && strcmp(list
->passwd
, "disable"))
1140 storeAppendPrintf(entry
, "%s XXXXXXXXXX", name
);
1142 storeAppendPrintf(entry
, "%s %s", name
, list
->passwd
);
1143 for (w
= list
->actions
; w
!= NULL
; w
= w
->next
) {
1144 storeAppendPrintf(entry
, " %s", w
->key
);
1146 storeAppendPrintf(entry
, "\n");
1152 parse_cachemgrpasswd(cachemgr_passwd
** head
)
1154 char *passwd
= NULL
;
1155 wordlist
*actions
= NULL
;
1157 cachemgr_passwd
**P
;
1158 parse_string(&passwd
);
1159 parse_wordlist(&actions
);
1160 p
= xcalloc(1, sizeof(cachemgr_passwd
));
1162 p
->actions
= actions
;
1163 for (P
= head
; *P
; P
= &(*P
)->next
);
1168 free_cachemgrpasswd(cachemgr_passwd
** head
)
1171 while ((p
= *head
) != NULL
) {
1174 wordlistDestroy(&p
->actions
);
1180 dump_denyinfo(StoreEntry
* entry
, const char *name
, acl_deny_info_list
* var
)
1183 while (var
!= NULL
) {
1184 storeAppendPrintf(entry
, "%s %s", name
, var
->err_page_name
);
1185 for (a
= var
->acl_list
; a
!= NULL
; a
= a
->next
)
1186 storeAppendPrintf(entry
, " %s", a
->name
);
1187 storeAppendPrintf(entry
, "\n");
1193 parse_denyinfo(acl_deny_info_list
** var
)
1195 aclParseDenyInfoLine(var
);
1199 free_denyinfo(acl_deny_info_list
** list
)
1201 acl_deny_info_list
*a
= NULL
;
1202 acl_deny_info_list
*a_next
= NULL
;
1203 acl_name_list
*l
= NULL
;
1204 acl_name_list
*l_next
= NULL
;
1205 for (a
= *list
; a
; a
= a_next
) {
1206 for (l
= a
->acl_list
; l
; l
= l_next
) {
1217 parse_peer_access(void)
1221 if (!(host
= strtok(NULL
, w_space
)))
1223 if ((p
= peerFindByName(host
)) == NULL
) {
1224 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1225 cfg_filename
, config_lineno
, host
);
1228 aclParseAccessLine(&p
->access
);
1232 parse_hostdomain(void)
1235 char *domain
= NULL
;
1236 if (!(host
= strtok(NULL
, w_space
)))
1238 while ((domain
= strtok(NULL
, list_sep
))) {
1239 domain_ping
*l
= NULL
;
1240 domain_ping
**L
= NULL
;
1242 if ((p
= peerFindByName(host
)) == NULL
) {
1243 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1244 cfg_filename
, config_lineno
, host
);
1247 l
= xcalloc(1, sizeof(domain_ping
));
1249 if (*domain
== '!') { /* check for !.edu */
1253 l
->domain
= xstrdup(domain
);
1254 for (L
= &(p
->peer_domain
); *L
; L
= &((*L
)->next
));
1260 parse_hostdomaintype(void)
1264 char *domain
= NULL
;
1265 if (!(host
= strtok(NULL
, w_space
)))
1267 if (!(type
= strtok(NULL
, w_space
)))
1269 while ((domain
= strtok(NULL
, list_sep
))) {
1270 domain_type
*l
= NULL
;
1271 domain_type
**L
= NULL
;
1273 if ((p
= peerFindByName(host
)) == NULL
) {
1274 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1275 cfg_filename
, config_lineno
, host
);
1278 l
= xcalloc(1, sizeof(domain_type
));
1279 l
->type
= parseNeighborType(type
);
1280 l
->domain
= xstrdup(domain
);
1281 for (L
= &(p
->typelist
); *L
; L
= &((*L
)->next
));
1288 dump_ushortlist(StoreEntry
* entry
, const char *name
, ushortlist
* u
)
1291 storeAppendPrintf(entry
, "%s %d\n", name
, (int) u
->i
);
1297 check_null_ushortlist(ushortlist
* u
)
1303 parse_ushortlist(ushortlist
** P
)
1309 while ((token
= strtok(NULL
, w_space
))) {
1310 if (sscanf(token
, "%d", &i
) != 1)
1314 u
= xcalloc(1, sizeof(ushortlist
));
1316 for (U
= P
; *U
; U
= &(*U
)->next
);
1322 free_ushortlist(ushortlist
** P
)
1325 while ((u
= *P
) != NULL
) {
1333 dump_int(StoreEntry
* entry
, const char *name
, int var
)
1335 storeAppendPrintf(entry
, "%s %d\n", name
, var
);
1353 dump_onoff(StoreEntry
* entry
, const char *name
, int var
)
1355 storeAppendPrintf(entry
, "%s %s\n", name
, var
? "on" : "off");
1359 parse_onoff(int *var
)
1361 char *token
= strtok(NULL
, w_space
);
1365 if (!strcasecmp(token
, "on") || !strcasecmp(token
, "enable"))
1371 #define free_onoff free_int
1372 #define dump_eol dump_string
1373 #define free_eol free_string
1376 dump_refreshpattern(StoreEntry
* entry
, const char *name
, refresh_t
* head
)
1378 while (head
!= NULL
) {
1379 storeAppendPrintf(entry
, "%s%s %s %d %d%% %d\n",
1381 head
->flags
.icase
? " -i" : null_string
,
1383 (int) head
->min
/ 60,
1384 (int) (100.0 * head
->pct
+ 0.5),
1385 (int) head
->max
/ 60);
1387 if (head
->flags
.override_expire
)
1388 storeAppendPrintf(entry
, " override-expire");
1389 if (head
->flags
.override_lastmod
)
1390 storeAppendPrintf(entry
, " override-lastmod");
1391 if (head
->flags
.reload_into_ims
)
1392 storeAppendPrintf(entry
, " reload-into-ims");
1393 if (head
->flags
.ignore_reload
)
1394 storeAppendPrintf(entry
, " ignore-reload");
1396 storeAppendPrintf(entry
, "\n");
1402 parse_refreshpattern(refresh_t
** head
)
1410 int override_expire
= 0;
1411 int override_lastmod
= 0;
1412 int reload_into_ims
= 0;
1413 int ignore_reload
= 0;
1419 int flags
= REG_EXTENDED
| REG_NOSUB
;
1420 if ((token
= strtok(NULL
, w_space
)) == NULL
)
1422 if (strcmp(token
, "-i") == 0) {
1424 token
= strtok(NULL
, w_space
);
1425 } else if (strcmp(token
, "+i") == 0) {
1426 flags
&= ~REG_ICASE
;
1427 token
= strtok(NULL
, w_space
);
1431 pattern
= xstrdup(token
);
1432 i
= GetInteger(); /* token: min */
1433 min
= (time_t) (i
* 60); /* convert minutes to seconds */
1434 i
= GetInteger(); /* token: pct */
1435 pct
= (double) i
/ 100.0;
1436 i
= GetInteger(); /* token: max */
1437 max
= (time_t) (i
* 60); /* convert minutes to seconds */
1439 while ((token
= strtok(NULL
, w_space
)) != NULL
) {
1441 if (!strcmp(token
, "override-expire"))
1442 override_expire
= 1;
1443 else if (!strcmp(token
, "override-lastmod"))
1444 override_lastmod
= 1;
1445 else if (!strcmp(token
, "reload-into-ims")) {
1446 reload_into_ims
= 1;
1447 refresh_nocache_hack
= 1;
1448 /* tell client_side.c that this is used */
1449 } else if (!strcmp(token
, "ignore-reload")) {
1451 refresh_nocache_hack
= 1;
1452 /* tell client_side.c that this is used */
1455 debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
1458 if ((errcode
= regcomp(&comp
, pattern
, flags
)) != 0) {
1460 regerror(errcode
, &comp
, errbuf
, sizeof errbuf
);
1461 debug(22, 0) ("%s line %d: %s\n",
1462 cfg_filename
, config_lineno
, config_input_line
);
1463 debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %s\n",
1467 pct
= pct
< 0.0 ? 0.0 : pct
;
1468 max
= max
< 0 ? 0 : max
;
1469 t
= xcalloc(1, sizeof(refresh_t
));
1470 t
->pattern
= (char *) xstrdup(pattern
);
1471 t
->compiled_pattern
= comp
;
1475 if (flags
& REG_ICASE
)
1478 if (override_expire
)
1479 t
->flags
.override_expire
= 1;
1480 if (override_lastmod
)
1481 t
->flags
.override_lastmod
= 1;
1482 if (reload_into_ims
)
1483 t
->flags
.reload_into_ims
= 1;
1485 t
->flags
.ignore_reload
= 1;
1489 head
= &(*head
)->next
;
1495 check_null_refreshpattern(refresh_t
*data
)
1497 return data
!= NULL
;
1501 free_refreshpattern(refresh_t
** head
)
1504 while ((t
= *head
) != NULL
) {
1506 safe_free(t
->pattern
);
1507 regfree(&t
->compiled_pattern
);
1513 dump_string(StoreEntry
* entry
, const char *name
, char *var
)
1516 storeAppendPrintf(entry
, "%s %s\n", name
, var
);
1520 parse_string(char **var
)
1522 char *token
= strtok(NULL
, w_space
);
1526 *var
= xstrdup(token
);
1530 free_string(char **var
)
1536 parse_eol(char *volatile *var
)
1538 char *token
= strtok(NULL
, null_string
);
1542 *var
= xstrdup(token
);
1546 dump_time_t(StoreEntry
* entry
, const char *name
, time_t var
)
1548 storeAppendPrintf(entry
, "%s %d seconds\n", name
, (int) var
);
1552 parse_time_t(time_t * var
)
1554 parseTimeLine(var
, T_SECOND_STR
);
1558 free_time_t(time_t * var
)
1564 dump_size_t(StoreEntry
* entry
, const char *name
, size_t var
)
1566 storeAppendPrintf(entry
, "%s %d\n", name
, (int) var
);
1570 dump_b_size_t(StoreEntry
* entry
, const char *name
, size_t var
)
1572 storeAppendPrintf(entry
, "%s %d %s\n", name
, (int) var
, B_BYTES_STR
);
1576 dump_kb_size_t(StoreEntry
* entry
, const char *name
, size_t var
)
1578 storeAppendPrintf(entry
, "%s %d %s\n", name
, (int) var
, B_KBYTES_STR
);
1582 parse_size_t(size_t * var
)
1590 parse_b_size_t(size_t * var
)
1592 parseBytesLine(var
, B_BYTES_STR
);
1596 parse_kb_size_t(size_t * var
)
1598 parseBytesLine(var
, B_KBYTES_STR
);
1602 free_size_t(size_t * var
)
1607 #define free_b_size_t free_size_t
1608 #define free_kb_size_t free_size_t
1609 #define free_mb_size_t free_size_t
1610 #define free_gb_size_t free_size_t
1613 dump_ushort(StoreEntry
* entry
, const char *name
, u_short var
)
1615 storeAppendPrintf(entry
, "%s %d\n", name
, var
);
1619 free_ushort(u_short
* u
)
1625 parse_ushort(u_short
* var
)
1636 dump_wordlist(StoreEntry
* entry
, const char *name
, wordlist
* list
)
1638 while (list
!= NULL
) {
1639 storeAppendPrintf(entry
, "%s %s\n", name
, list
->key
);
1645 parse_wordlist(wordlist
** list
)
1648 while ((token
= strtok(NULL
, w_space
)))
1649 wordlistAdd(list
, token
);
1653 check_null_wordlist(wordlist
* w
)
1659 check_null_acl_access(acl_access
* a
)
1664 #define free_wordlist wordlistDestroy
1666 #define free_uri_whitespace free_int
1669 parse_uri_whitespace(int *var
)
1671 char *token
= strtok(NULL
, w_space
);
1674 if (!strcasecmp(token
, "strip"))
1675 *var
= URI_WHITESPACE_STRIP
;
1676 else if (!strcasecmp(token
, "deny"))
1677 *var
= URI_WHITESPACE_DENY
;
1678 else if (!strcasecmp(token
, "allow"))
1679 *var
= URI_WHITESPACE_ALLOW
;
1680 else if (!strcasecmp(token
, "encode"))
1681 *var
= URI_WHITESPACE_ENCODE
;
1682 else if (!strcasecmp(token
, "chop"))
1683 *var
= URI_WHITESPACE_CHOP
;
1690 dump_uri_whitespace(StoreEntry
* entry
, const char *name
, int var
)
1693 if (var
== URI_WHITESPACE_ALLOW
)
1695 else if (var
== URI_WHITESPACE_ENCODE
)
1697 else if (var
== URI_WHITESPACE_CHOP
)
1699 else if (var
== URI_WHITESPACE_DENY
)
1703 storeAppendPrintf(entry
, "%s %s\n", name
, s
);
1706 #include "cf_parser.c"
1709 parseNeighborType(const char *s
)
1711 if (!strcasecmp(s
, "parent"))
1713 if (!strcasecmp(s
, "neighbor"))
1714 return PEER_SIBLING
;
1715 if (!strcasecmp(s
, "neighbour"))
1716 return PEER_SIBLING
;
1717 if (!strcasecmp(s
, "sibling"))
1718 return PEER_SIBLING
;
1719 if (!strcasecmp(s
, "multicast"))
1720 return PEER_MULTICAST
;
1721 debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s
);
1722 return PEER_SIBLING
;
1726 parse_sockaddr_in_list(sockaddr_in_list
** head
)
1731 const struct hostent
*hp
;
1732 unsigned short port
;
1733 sockaddr_in_list
*s
;
1734 while ((token
= strtok(NULL
, w_space
))) {
1737 if ((t
= strchr(token
, ':'))) {
1741 port
= (unsigned short) atoi(t
+ 1);
1744 } else if ((port
= atoi(token
)) > 0) {
1749 s
= xcalloc(1, sizeof(*s
));
1750 s
->s
.sin_port
= htons(port
);
1752 s
->s
.sin_addr
= any_addr
;
1753 else if (1 == safe_inet_addr(host
, &s
->s
.sin_addr
))
1755 else if ((hp
= gethostbyname(host
))) /* dont use ipcache */
1756 s
->s
.sin_addr
= inaddrFromHostent(hp
);
1760 head
= &(*head
)->next
;
1766 dump_sockaddr_in_list(StoreEntry
* e
, const char *n
, const sockaddr_in_list
* s
)
1769 storeAppendPrintf(e
, "%s %s:%d\n",
1771 inet_ntoa(s
->s
.sin_addr
),
1772 ntohs(s
->s
.sin_port
));
1778 free_sockaddr_in_list(sockaddr_in_list
** head
)
1780 sockaddr_in_list
*s
;
1781 while ((s
= *head
) != NULL
) {
1788 check_null_sockaddr_in_list(const sockaddr_in_list
* s
)
1794 configFreeMemory(void)
1800 requirePathnameExists(const char *name
, const char *path
)
1803 assert(path
!= NULL
);
1804 if (stat(path
, &sb
) < 0)
1805 fatalf("%s: %s", path
, xstrerror());