cache_cf.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:40k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: cache_cf.c,v 1.324.2.2 1999/02/14 00:23:09 wessels Exp $
  3.  *
  4.  * DEBUG: section 3     Configuration File Parsing
  5.  * AUTHOR: Harvest Derived
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. #if SQUID_SNMP
  36. #include "snmp.h"
  37. #endif
  38. static const char *const T_SECOND_STR = "second";
  39. static const char *const T_MINUTE_STR = "minute";
  40. static const char *const T_HOUR_STR = "hour";
  41. static const char *const T_DAY_STR = "day";
  42. static const char *const T_WEEK_STR = "week";
  43. static const char *const T_FORTNIGHT_STR = "fortnight";
  44. static const char *const T_MONTH_STR = "month";
  45. static const char *const T_YEAR_STR = "year";
  46. static const char *const T_DECADE_STR = "decade";
  47. static const char *const B_BYTES_STR = "bytes";
  48. static const char *const B_KBYTES_STR = "KB";
  49. static const char *const B_MBYTES_STR = "MB";
  50. static const char *const B_GBYTES_STR = "GB";
  51. static const char *const list_sep = ", tnr";
  52. static int http_header_first = 0;
  53. static void self_destruct(void);
  54. static void configDoConfigure(void);
  55. static void parse_refreshpattern(refresh_t **);
  56. static int parseTimeUnits(const char *unit);
  57. static void parseTimeLine(time_t * tptr, const char *units);
  58. static void parse_ushort(u_short * var);
  59. static void parse_string(char **);
  60. static void parse_wordlist(wordlist **);
  61. static void default_all(void);
  62. static void defaults_if_none(void);
  63. static int parse_line(char *);
  64. static void parseBytesLine(size_t * bptr, const char *units);
  65. static size_t parseBytesUnits(const char *unit);
  66. static void free_all(void);
  67. static void requirePathnameExists(const char *name, const char *path);
  68. static OBJH dump_config;
  69. static void dump_http_header(StoreEntry * entry, const char *name, HttpHeaderMask header);
  70. static void parse_http_header(HttpHeaderMask * header);
  71. static void free_http_header(HttpHeaderMask * header);
  72. static void
  73. self_destruct(void)
  74. {
  75.     fatalf("Bungled %s line %d: %s",
  76. cfg_filename, config_lineno, config_input_line);
  77. }
  78. void
  79. wordlistDestroy(wordlist ** list)
  80. {
  81.     wordlist *w = NULL;
  82.     while ((w = *list) != NULL) {
  83. *list = w->next;
  84. safe_free(w->key);
  85. memFree(w, MEM_WORDLIST);
  86.     }
  87.     *list = NULL;
  88. }
  89. wordlist *
  90. wordlistAdd(wordlist ** list, const char *key)
  91. {
  92.     while (*list)
  93. list = &(*list)->next;
  94.     *list = memAllocate(MEM_WORDLIST);
  95.     (*list)->key = xstrdup(key);
  96.     (*list)->next = NULL;
  97.     return *list;
  98. }
  99. void
  100. wordlistCat(const wordlist * w, MemBuf * mb)
  101. {
  102.     while (NULL != w) {
  103. memBufPrintf(mb, "%sn", w->key);
  104. w = w->next;
  105.     }
  106. }
  107. void
  108. intlistDestroy(intlist ** list)
  109. {
  110.     intlist *w = NULL;
  111.     intlist *n = NULL;
  112.     for (w = *list; w; w = n) {
  113. n = w->next;
  114. memFree(w, MEM_INTLIST);
  115.     }
  116.     *list = NULL;
  117. }
  118. int
  119. intlistFind(intlist * list, int i)
  120. {
  121.     intlist *w = NULL;
  122.     for (w = list; w; w = w->next)
  123. if (w->i == i)
  124.     return 1;
  125.     return 0;
  126. }
  127. /*
  128.  * Use this #define in all the parse*() functions.  Assumes char *token is
  129.  * defined
  130.  */
  131. #define GetInteger(var) 
  132. token = strtok(NULL, w_space); 
  133. if( token == NULL) 
  134. self_destruct(); 
  135. if (sscanf(token, "%d", &var) != 1) 
  136. self_destruct();
  137. int
  138. parseConfigFile(const char *file_name)
  139. {
  140.     FILE *fp = NULL;
  141.     char *token = NULL;
  142.     char *tmp_line;
  143.     int err_count = 0;
  144.     free_all();
  145.     default_all();
  146.     if ((fp = fopen(file_name, "r")) == NULL)
  147. fatalf("Unable to open configuration file: %s: %s",
  148.     file_name, xstrerror());
  149.     cfg_filename = file_name;
  150.     if ((token = strrchr(cfg_filename, '/')))
  151. cfg_filename = token + 1;
  152.     memset(config_input_line, '', BUFSIZ);
  153.     config_lineno = 0;
  154.     while (fgets(config_input_line, BUFSIZ, fp)) {
  155. config_lineno++;
  156. if ((token = strchr(config_input_line, 'n')))
  157.     *token = '';
  158. if (config_input_line[0] == '#')
  159.     continue;
  160. if (config_input_line[0] == '')
  161.     continue;
  162. debug(3, 5) ("Processing: '%s'n", config_input_line);
  163. tmp_line = xstrdup(config_input_line);
  164. if (!parse_line(tmp_line)) {
  165.     debug(3, 0) ("parseConfigFile: line %d unrecognized: '%s'n",
  166. config_lineno,
  167. config_input_line);
  168.     err_count++;
  169. }
  170. safe_free(tmp_line);
  171.     }
  172.     fclose(fp);
  173.     defaults_if_none();
  174.     configDoConfigure();
  175.     cachemgrRegister("config",
  176. "Current Squid Configuration",
  177. dump_config,
  178. 1, 1);
  179.     return err_count;
  180. }
  181. static void
  182. configDoConfigure(void)
  183. {
  184.     LOCAL_ARRAY(char, buf, BUFSIZ);
  185.     memset(&Config2, '', sizeof(SquidConfig2));
  186.     /* init memory as early as possible */
  187.     memConfigure();
  188.     /* Sanity checks */
  189.     if (Config.cacheSwap.swapDirs == NULL)
  190. fatal("No cache_dir's specified in config file");
  191.     /* calculate Config.Swap.maxSize */
  192.     storeDirConfigure();
  193.     if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
  194. fatal("cache_swap is lower than cache_mem");
  195.     if (Config.Announce.period > 0) {
  196. Config.onoff.announce = 1;
  197.     } else if (Config.Announce.period < 1) {
  198. Config.Announce.period = 86400 * 365; /* one year */
  199. Config.onoff.announce = 0;
  200.     }
  201.     if (Config.dnsChildren < 1)
  202. fatal("No dnsservers allocated");
  203.     if (Config.dnsChildren > DefaultDnsChildrenMax) {
  204. debug(3, 0) ("WARNING: dns_children was set to a bad value: %dn",
  205.     Config.dnsChildren);
  206. debug(3, 0) ("Setting it to the maximum (%d).n",
  207.     DefaultDnsChildrenMax);
  208. Config.dnsChildren = DefaultDnsChildrenMax;
  209.     }
  210.     if (Config.Program.redirect) {
  211. if (Config.redirectChildren < 1) {
  212.     Config.redirectChildren = 0;
  213.     safe_free(Config.Program.redirect);
  214. } else if (Config.redirectChildren > DefaultRedirectChildrenMax) {
  215.     debug(3, 0) ("WARNING: redirect_children was set to a bad value: %dn",
  216. Config.redirectChildren);
  217.     debug(3, 0) ("Setting it to the maximum (%d).n", DefaultRedirectChildrenMax);
  218.     Config.redirectChildren = DefaultRedirectChildrenMax;
  219. }
  220.     }
  221.     if (Config.Program.authenticate) {
  222. if (Config.authenticateChildren < 1) {
  223.     Config.authenticateChildren = 0;
  224.     wordlistDestroy(&Config.Program.authenticate);
  225. } else if (Config.authenticateChildren > DefaultAuthenticateChildrenMax) {
  226.     debug(3, 0) ("WARNING: authenticate_children was set to a bad value: %dn",
  227. Config.authenticateChildren);
  228.     debug(3, 0) ("Setting it to the maximum (%d).n", DefaultAuthenticateChildrenMax);
  229.     Config.authenticateChildren = DefaultAuthenticateChildrenMax;
  230. }
  231.     }
  232.     if (Config.Accel.host) {
  233. snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
  234. Config2.Accel.prefix = xstrdup(buf);
  235. Config2.Accel.on = 1;
  236.     }
  237.     if (Config.appendDomain)
  238. if (*Config.appendDomain != '.')
  239.     fatal("append_domain must begin with a '.'");
  240.     if (Config.errHtmlText == NULL)
  241. Config.errHtmlText = xstrdup(null_string);
  242.     storeConfigure();
  243.     if (Config2.Accel.on && !strcmp(Config.Accel.host, "virtual"))
  244. vhost_mode = 1;
  245.     if (Config.Port.http == NULL)
  246. fatal("No http_port specified!");
  247.     snprintf(ThisCache, sizeof(ThisCache), "%s:%d (%s)",
  248. uniqueHostname(),
  249. (int) Config.Port.http->i,
  250. full_appname_string);
  251.     /*
  252.      * the extra space is for loop detection in client_side.c -- we search
  253.      * for substrings in the Via header.
  254.      */
  255.     snprintf(ThisCache2, sizeof(ThisCache), " %s:%d (%s)",
  256. uniqueHostname(),
  257. (int) Config.Port.http->i,
  258. full_appname_string);
  259.     if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
  260. Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
  261.     if (Config.appendDomain)
  262. Config.appendDomainLen = strlen(Config.appendDomain);
  263.     else
  264. Config.appendDomainLen = 0;
  265.     safe_free(debug_options)
  266. debug_options = xstrdup(Config.debugOptions);
  267.     if (Config.retry.timeout < 5)
  268. fatal("minimum_retry_timeout must be at least 5 seconds");
  269.     if (Config.retry.maxtries > 10)
  270. fatal("maximum_single_addr_tries cannot be larger than 10");
  271.     if (Config.retry.maxtries < 1) {
  272. debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1n");
  273. Config.retry.maxtries = 1;
  274.     }
  275.     if (Config.referenceAge < 300) {
  276. debug(3, 0) ("WARNING: resetting 'reference_age' to 1 weekn");
  277. Config.referenceAge = 86400 * 7;
  278.     }
  279.     requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
  280.     requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
  281.     requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
  282.     if (Config.Program.redirect)
  283. requirePathnameExists("redirect_program", Config.Program.redirect);
  284.     if (Config.Program.authenticate)
  285. requirePathnameExists("authenticate_program", Config.Program.authenticate->key);
  286.     requirePathnameExists("Icon Directory", Config.icons.directory);
  287.     requirePathnameExists("Error Directory", Config.errorDirectory);
  288. #if HTTP_VIOLATIONS
  289.     {
  290. const refresh_t *R;
  291. for (R = Config.Refresh; R; R = R->next) {
  292.     if (!R->flags.override_expire)
  293. continue;
  294.     debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTPn");
  295.     break;
  296. }
  297. for (R = Config.Refresh; R; R = R->next) {
  298.     if (!R->flags.override_lastmod)
  299. continue;
  300.     debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTPn");
  301.     break;
  302. }
  303.     }
  304. #endif
  305.     if (Config.Wais.relayHost) {
  306. if (Config.Wais.peer)
  307.     cbdataFree(Config.Wais.peer);
  308. Config.Wais.peer = memAllocate(MEM_PEER);
  309. cbdataAdd(Config.Wais.peer, peerDestroy, MEM_PEER);
  310. Config.Wais.peer->host = Config.Wais.relayHost;
  311. Config.Wais.peer->http_port = Config.Wais.relayPort;
  312.     }
  313. }
  314. /* Parse a time specification from the config file.  Store the
  315.  * result in 'tptr', after converting it to 'units' */
  316. static void
  317. parseTimeLine(time_t * tptr, const char *units)
  318. {
  319.     char *token;
  320.     double d;
  321.     time_t m;
  322.     time_t u;
  323.     if ((u = parseTimeUnits(units)) == 0)
  324. self_destruct();
  325.     if ((token = strtok(NULL, w_space)) == NULL)
  326. self_destruct();
  327.     d = atof(token);
  328.     m = u; /* default to 'units' if none specified */
  329.     if (0 == d)
  330. (void) 0;
  331.     else if ((token = strtok(NULL, w_space)) == NULL)
  332. debug(3, 0) ("WARNING: No units on '%s', assuming %f %sn",
  333.     config_input_line, d, units);
  334.     else if ((m = parseTimeUnits(token)) == 0)
  335. self_destruct();
  336.     *tptr = m * d / u;
  337. }
  338. static int
  339. parseTimeUnits(const char *unit)
  340. {
  341.     if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
  342. return 1;
  343.     if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
  344. return 60;
  345.     if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
  346. return 3600;
  347.     if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
  348. return 86400;
  349.     if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
  350. return 86400 * 7;
  351.     if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
  352. return 86400 * 14;
  353.     if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
  354. return 86400 * 30;
  355.     if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
  356. return 86400 * 365.2522;
  357.     if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
  358. return 86400 * 365.2522 * 10;
  359.     debug(3, 1) ("parseTimeUnits: unknown time unit '%s'n", unit);
  360.     return 0;
  361. }
  362. static void
  363. parseBytesLine(size_t * bptr, const char *units)
  364. {
  365.     char *token;
  366.     double d;
  367.     size_t m;
  368.     size_t u;
  369.     if ((u = parseBytesUnits(units)) == 0)
  370. self_destruct();
  371.     if ((token = strtok(NULL, w_space)) == NULL)
  372. self_destruct();
  373.     d = atof(token);
  374.     m = u; /* default to 'units' if none specified */
  375.     if (0 == d)
  376. (void) 0;
  377.     else if ((token = strtok(NULL, w_space)) == NULL)
  378. debug(3, 0) ("WARNING: No units on '%s', assuming %f %sn",
  379.     config_input_line, d, units);
  380.     else if ((m = parseBytesUnits(token)) == 0)
  381. self_destruct();
  382.     *bptr = m * d / u;
  383. }
  384. static size_t
  385. parseBytesUnits(const char *unit)
  386. {
  387.     if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
  388. return 1;
  389.     if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
  390. return 1 << 10;
  391.     if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
  392. return 1 << 20;
  393.     if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
  394. return 1 << 30;
  395.     debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'n", unit);
  396.     return 0;
  397. }
  398. /*****************************************************************************
  399.  * Max
  400.  *****************************************************************************/
  401. static void
  402. dump_acl(StoreEntry * entry, const char *name, acl * ae)
  403. {
  404.     wordlist *w;
  405.     wordlist *v;
  406.     while (ae != NULL) {
  407. debug(3, 3) ("dump_acl: %s %sn", name, ae->name);
  408. v = w = aclDumpGeneric(ae);
  409. while (v != NULL) {
  410.     debug(3, 3) ("dump_acl: %s %s %sn", name, ae->name, v->key);
  411.     storeAppendPrintf(entry, "%s %s %s %sn",
  412. name,
  413. ae->name,
  414. aclTypeToStr(ae->type),
  415. v->key);
  416.     v = v->next;
  417. }
  418. wordlistDestroy(&w);
  419. ae = ae->next;
  420.     }
  421. }
  422. static void
  423. parse_acl(acl ** ae)
  424. {
  425.     aclParseAclLine(ae);
  426. }
  427. static void
  428. free_acl(acl ** ae)
  429. {
  430.     aclDestroyAcls(ae);
  431. }
  432. static void
  433. dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
  434. {
  435.     acl_list *l;
  436.     while (head != NULL) {
  437. storeAppendPrintf(entry, "%s %s",
  438.     name,
  439.     head->allow ? "Allow" : "Deny");
  440. for (l = head->acl_list; l != NULL; l = l->next) {
  441.     storeAppendPrintf(entry, " %s%s",
  442. l->op ? null_string : "!",
  443. l->acl->name);
  444. }
  445. storeAppendPrintf(entry, "n");
  446. head = head->next;
  447.     }
  448. }
  449. static void
  450. parse_acl_access(acl_access ** head)
  451. {
  452.     aclParseAccessLine(head);
  453. }
  454. static void
  455. free_acl_access(acl_access ** head)
  456. {
  457.     aclDestroyAccessList(head);
  458. }
  459. static void
  460. dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
  461. {
  462.     storeAppendPrintf(entry, "%s %sn", name, inet_ntoa(addr));
  463. }
  464. static void
  465. parse_address(struct in_addr *addr)
  466. {
  467.     const struct hostent *hp;
  468.     char *token = strtok(NULL, w_space);
  469.     if (token == NULL)
  470. self_destruct();
  471.     if (safe_inet_addr(token, addr) == 1)
  472. (void) 0;
  473.     else if ((hp = gethostbyname(token))) /* dont use ipcache */
  474. *addr = inaddrFromHostent(hp);
  475.     else
  476. self_destruct();
  477. }
  478. static void
  479. free_address(struct in_addr *addr)
  480. {
  481.     memset(addr, '', sizeof(struct in_addr));
  482. }
  483. #if DELAY_POOLS
  484. /* do nothing - free_delay_pool_count is the magic free function.
  485.  * this is why delay_pool_count isn't just marked TYPE: ushort
  486.  */
  487. #define free_delay_pool_class(X)
  488. #define free_delay_pool_access(X)
  489. #define free_delay_pool_rates(X)
  490. #define dump_delay_pool_class(X, Y, Z)
  491. #define dump_delay_pool_access(X, Y, Z)
  492. #define dump_delay_pool_rates(X, Y, Z)
  493. static void
  494. free_delay_pool_count(delayConfig * cfg)
  495. {
  496.     int i;
  497.     if (!cfg->pools)
  498. return;
  499.     for (i = 0; i < cfg->pools; i++) {
  500. if (cfg->class[i]) {
  501.     delayFreeDelayPool(i);
  502.     safe_free(cfg->rates[i]);
  503. }
  504. aclDestroyAccessList(&cfg->access[i]);
  505.     }
  506.     delayFreeDelayData();
  507.     xfree(cfg->class);
  508.     xfree(cfg->rates);
  509.     xfree(cfg->access);
  510.     memset(cfg, 0, sizeof(*cfg));
  511. }
  512. static void
  513. dump_delay_pool_count(StoreEntry * entry, const char *name, delayConfig cfg)
  514. {
  515.     int i;
  516.     LOCAL_ARRAY(char, nom, 32);
  517.     if (!cfg.pools) {
  518. storeAppendPrintf(entry, "%s 0n", name);
  519. return;
  520.     }
  521.     storeAppendPrintf(entry, "%s %dn", name, cfg.pools);
  522.     for (i = 0; i < cfg.pools; i++) {
  523. storeAppendPrintf(entry, "delay_class %d %dn", i + 1, cfg.class[i]);
  524. snprintf(nom, 32, "delay_access %d", i + 1);
  525. dump_acl_access(entry, nom, cfg.access[i]);
  526. if (cfg.class[i] >= 1)
  527.     storeAppendPrintf(entry, "delay_parameters %d %d/%d", i + 1,
  528. cfg.rates[i]->aggregate.restore_bps,
  529. cfg.rates[i]->aggregate.max_bytes);
  530. if (cfg.class[i] >= 3)
  531.     storeAppendPrintf(entry, " %d/%d",
  532. cfg.rates[i]->network.restore_bps,
  533. cfg.rates[i]->network.max_bytes);
  534. if (cfg.class[i] >= 2)
  535.     storeAppendPrintf(entry, " %d/%d",
  536. cfg.rates[i]->individual.restore_bps,
  537. cfg.rates[i]->individual.max_bytes);
  538. if (cfg.class[i] >= 1)
  539.     storeAppendPrintf(entry, "n");
  540.     }
  541. }
  542. static void
  543. parse_delay_pool_count(delayConfig * cfg)
  544. {
  545.     if (cfg->pools) {
  546. debug(3, 0) ("parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools confign");
  547. free_delay_pool_count(cfg);
  548.     }
  549.     parse_ushort(&cfg->pools);
  550.     delayInitDelayData(cfg->pools);
  551.     cfg->class = xcalloc(cfg->pools, sizeof(u_char));
  552.     cfg->rates = xcalloc(cfg->pools, sizeof(delaySpecSet *));
  553.     cfg->access = xcalloc(cfg->pools, sizeof(acl_access *));
  554. }
  555. static void
  556. parse_delay_pool_class(delayConfig * cfg)
  557. {
  558.     ushort pool, class;
  559.     parse_ushort(&pool);
  560.     if (pool < 1 || pool > cfg->pools) {
  561. debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d not in 1 .. %dn", pool, cfg->pools);
  562. return;
  563.     }
  564.     parse_ushort(&class);
  565.     if (class < 1 || class > 3) {
  566. debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d class %d not in 1 .. 3n", pool, class);
  567. return;
  568.     }
  569.     pool--;
  570.     if (cfg->class[pool]) {
  571. delayFreeDelayPool(pool);
  572. safe_free(cfg->rates[pool]);
  573.     }
  574.     cfg->rates[pool] = xmalloc(class * sizeof(delaySpec));
  575.     cfg->class[pool] = class;
  576.     cfg->rates[pool]->aggregate.restore_bps = cfg->rates[pool]->aggregate.max_bytes = -1;
  577.     if (cfg->class[pool] >= 3)
  578. cfg->rates[pool]->network.restore_bps = cfg->rates[pool]->network.max_bytes = -1;
  579.     if (cfg->class[pool] >= 2)
  580. cfg->rates[pool]->individual.restore_bps = cfg->rates[pool]->individual.max_bytes = -1;
  581.     delayCreateDelayPool(pool, class);
  582. }
  583. static void
  584. parse_delay_pool_rates(delayConfig * cfg)
  585. {
  586.     ushort pool, class;
  587.     int i;
  588.     delaySpec *ptr;
  589.     char *token;
  590.     parse_ushort(&pool);
  591.     if (pool < 1 || pool > cfg->pools) {
  592. debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %dn", pool, cfg->pools);
  593. return;
  594.     }
  595.     pool--;
  596.     class = cfg->class[pool];
  597.     if (class == 0) {
  598. debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d attempt to set rates with class not setn", pool + 1);
  599. return;
  600.     }
  601.     ptr = (delaySpec *) cfg->rates[pool];
  602.     /* read in "class" sets of restore,max pairs */
  603.     while (class--) {
  604. token = strtok(NULL, "/");
  605. if (token == NULL)
  606.     self_destruct();
  607. if (sscanf(token, "%d", &i) != 1)
  608.     self_destruct();
  609. ptr->restore_bps = i;
  610. GetInteger(i);
  611. ptr->max_bytes = i;
  612. ptr++;
  613.     }
  614.     class = cfg->class[pool];
  615.     /* if class is 3, swap around network and individual */
  616.     if (class == 3) {
  617. delaySpec tmp;
  618. tmp = cfg->rates[pool]->individual;
  619. cfg->rates[pool]->individual = cfg->rates[pool]->network;
  620. cfg->rates[pool]->network = tmp;
  621.     }
  622.     /* initialize the delay pools */
  623.     delayInitDelayPool(pool, class, cfg->rates[pool]);
  624. }
  625. static void
  626. parse_delay_pool_access(delayConfig * cfg)
  627. {
  628.     ushort pool;
  629.     parse_ushort(&pool);
  630.     if (pool < 1 || pool > cfg->pools) {
  631. debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %dn", pool, cfg->pools);
  632. return;
  633.     }
  634.     aclParseAccessLine(&cfg->access[pool - 1]);
  635. }
  636. #endif
  637. static void
  638. dump_http_header(StoreEntry * entry, const char *name, HttpHeaderMask header)
  639. {
  640.     storeAppendPrintf(entry, "%sn", name);
  641. }
  642. static void
  643. parse_http_header(HttpHeaderMask * header)
  644. {
  645.     int allowed, id;
  646.     char *t = NULL;
  647.     if ((t = strtok(NULL, w_space)) == NULL) {
  648. debug(3, 0) ("%s line %d: %sn",
  649.     cfg_filename, config_lineno, config_input_line);
  650. debug(3, 0) ("parse_http_header: missing 'allow' or 'deny'.n");
  651. return;
  652.     }
  653.     if (!strcmp(t, "allow"))
  654. allowed = 1;
  655.     else if (!strcmp(t, "deny"))
  656. allowed = 0;
  657.     else {
  658. debug(3, 0) ("%s line %d: %sn",
  659.     cfg_filename, config_lineno, config_input_line);
  660. debug(3, 0) ("parse_http_header: expecting 'allow' or 'deny', got '%s'.n", t);
  661. return;
  662.     }
  663.     if (!http_header_first) {
  664. http_header_first = 1;
  665. if (allowed)
  666.     httpHeaderMaskInit(header, 0xFF);
  667.     }
  668.     while ((t = strtok(NULL, w_space))) {
  669. if ((id = httpHeaderIdByNameDef(t, strlen(t))) == -1)
  670.     id = HDR_OTHER;
  671. if (allowed)
  672.     CBIT_CLR(*header, id);
  673. else
  674.     CBIT_SET(*header, id);
  675.     }
  676. }
  677. static void
  678. free_http_header(HttpHeaderMask * header)
  679. {
  680.     httpHeaderMaskInit(header, 0);
  681. }
  682. static void
  683. dump_cachedir(StoreEntry * entry, const char *name, cacheSwap swap)
  684. {
  685.     SwapDir *s;
  686.     int i;
  687.     for (i = 0; i < swap.n_configured; i++) {
  688. s = swap.swapDirs + i;
  689. storeAppendPrintf(entry, "%s %s %d %d %dn",
  690.     name,
  691.     s->path,
  692.     s->max_size >> 10,
  693.     s->l1,
  694.     s->l2);
  695.     }
  696. }
  697. static int
  698. check_null_cachedir(cacheSwap swap)
  699. {
  700.     return swap.swapDirs == NULL;
  701. }
  702. static int
  703. check_null_string(char *s)
  704. {
  705.     return s == NULL;
  706. }
  707. static void
  708. parse_cachedir(cacheSwap * swap)
  709. {
  710.     char *token;
  711.     char *path;
  712.     int i;
  713.     int size;
  714.     int l1;
  715.     int l2;
  716.     unsigned int read_only = 0;
  717.     SwapDir *tmp = NULL;
  718.     if ((path = strtok(NULL, w_space)) == NULL)
  719. self_destruct();
  720.     GetInteger(i);
  721.     size = i << 10; /* Mbytes to kbytes */
  722.     if (size <= 0)
  723. fatal("parse_cachedir: invalid size value");
  724.     GetInteger(i);
  725.     l1 = i;
  726.     if (l1 <= 0)
  727. fatal("parse_cachedir: invalid level 1 directories value");
  728.     GetInteger(i);
  729.     l2 = i;
  730.     if (l2 <= 0)
  731. fatal("parse_cachedir: invalid level 2 directories value");
  732.     if ((token = strtok(NULL, w_space)))
  733. if (!strcasecmp(token, "read-only"))
  734.     read_only = 1;
  735.     for (i = 0; i < swap->n_configured; i++) {
  736. tmp = swap->swapDirs + i;
  737. if (!strcmp(path, tmp->path)) {
  738.     /* just reconfigure it */
  739.     if (size == tmp->max_size)
  740. debug(3, 1) ("Cache dir '%s' size remains unchanged at %d KBn",
  741.     path, size);
  742.     else
  743. debug(3, 1) ("Cache dir '%s' size changed to %d KBn",
  744.     path, size);
  745.     tmp->max_size = size;
  746.     if (tmp->flags.read_only != read_only)
  747. debug(3, 1) ("Cache dir '%s' now %sn",
  748.     path, read_only ? "Read-Only" : "Read-Write");
  749.     tmp->flags.read_only = read_only;
  750.     return;
  751. }
  752.     }
  753.     if (swap->swapDirs == NULL) {
  754. swap->n_allocated = 4;
  755. swap->swapDirs = xcalloc(swap->n_allocated, sizeof(SwapDir));
  756.     }
  757.     if (swap->n_allocated == swap->n_configured) {
  758. swap->n_allocated <<= 1;
  759. tmp = xcalloc(swap->n_allocated, sizeof(SwapDir));
  760. xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir));
  761. xfree(swap->swapDirs);
  762. swap->swapDirs = tmp;
  763.     }
  764.     tmp = swap->swapDirs + swap->n_configured;
  765.     tmp->path = xstrdup(path);
  766.     tmp->max_size = size;
  767.     tmp->l1 = l1;
  768.     tmp->l2 = l2;
  769.     tmp->flags.read_only = read_only;
  770.     tmp->swaplog_fd = -1;
  771.     swap->n_configured++;
  772. }
  773. static void
  774. free_cachedir(cacheSwap * swap)
  775. {
  776.     SwapDir *s;
  777.     int i;
  778.     /* DON'T FREE THESE FOR RECONFIGURE */
  779.     if (reconfiguring)
  780. return;
  781.     for (i = 0; i < swap->n_configured; i++) {
  782. s = swap->swapDirs + i;
  783. if (s->swaplog_fd > -1) {
  784.     file_close(s->swaplog_fd);
  785.     s->swaplog_fd = -1;
  786. }
  787. xfree(s->path);
  788. filemapFreeMemory(s->map);
  789.     }
  790.     safe_free(swap->swapDirs);
  791.     swap->swapDirs = NULL;
  792.     swap->n_allocated = 0;
  793.     swap->n_configured = 0;
  794. }
  795. const char *
  796. peer_type_str(const peer_t type)
  797. {
  798.     switch (type) {
  799.     case PEER_PARENT:
  800. return "parent";
  801. break;
  802.     case PEER_SIBLING:
  803. return "sibling";
  804. break;
  805.     case PEER_MULTICAST:
  806. return "multicast";
  807. break;
  808.     default:
  809. return "unknown";
  810. break;
  811.     }
  812. }
  813. static void
  814. dump_peer(StoreEntry * entry, const char *name, peer * p)
  815. {
  816.     domain_ping *d;
  817.     acl_access *a;
  818.     domain_type *t;
  819.     LOCAL_ARRAY(char, xname, 128);
  820.     while (p != NULL) {
  821. storeAppendPrintf(entry, "%s %s %s %d %d",
  822.     name,
  823.     p->host,
  824.     neighborTypeStr(p),
  825.     p->http_port,
  826.     p->icp.port);
  827. dump_peer_options(entry, p);
  828. for (d = p->peer_domain; d; d = d->next) {
  829.     storeAppendPrintf(entry, "cache_peer_domain %s %s%sn",
  830. p->host,
  831. d->do_ping ? null_string : "!",
  832. d->domain);
  833. }
  834. if ((a = p->access)) {
  835.     snprintf(xname, 128, "cache_peer_access %s", p->host);
  836.     dump_acl_access(entry, xname, p->access);
  837. }
  838. for (t = p->typelist; t; t = t->next) {
  839.     storeAppendPrintf(entry, "neighbor_type_domain %s %s %sn",
  840. p->host,
  841. peer_type_str(t->type),
  842. t->domain);
  843. }
  844. p = p->next;
  845.     }
  846. }
  847. static void
  848. parse_peer(peer ** head)
  849. {
  850.     char *token = NULL;
  851.     peer *p;
  852.     int i;
  853.     ushortlist *u;
  854.     const char *me = null_string; /* XXX */
  855.     p = memAllocate(MEM_PEER);
  856.     p->http_port = CACHE_HTTP_PORT;
  857.     p->icp.port = CACHE_ICP_PORT;
  858.     p->weight = 1;
  859.     p->stats.logged_state = PEER_ALIVE;
  860.     if ((token = strtok(NULL, w_space)) == NULL)
  861. self_destruct();
  862.     p->host = xstrdup(token);
  863.     if ((token = strtok(NULL, w_space)) == NULL)
  864. self_destruct();
  865.     p->type = parseNeighborType(token);
  866.     GetInteger(i);
  867.     p->http_port = (u_short) i;
  868.     GetInteger(i);
  869.     p->icp.port = (u_short) i;
  870.     if (strcmp(p->host, me) == 0) {
  871. for (u = Config.Port.http; u; u = u->next) {
  872.     if (p->http_port != u->i)
  873. continue;
  874.     debug(15, 0) ("parse_peer: Peer looks like myself: %s %s/%d/%dn",
  875. p->type, p->host, p->http_port, p->icp.port);
  876.     self_destruct();
  877. }
  878.     }
  879.     while ((token = strtok(NULL, w_space))) {
  880. if (!strcasecmp(token, "proxy-only")) {
  881.     p->options.proxy_only = 1;
  882. } else if (!strcasecmp(token, "no-query")) {
  883.     p->options.no_query = 1;
  884. } else if (!strcasecmp(token, "no-digest")) {
  885.     p->options.no_digest = 1;
  886. } else if (!strcasecmp(token, "multicast-responder")) {
  887.     p->options.mcast_responder = 1;
  888. } else if (!strncasecmp(token, "weight=", 7)) {
  889.     p->weight = atoi(token + 7);
  890. } else if (!strcasecmp(token, "closest-only")) {
  891.     p->options.closest_only = 1;
  892. } else if (!strncasecmp(token, "ttl=", 4)) {
  893.     p->mcast.ttl = atoi(token + 4);
  894.     if (p->mcast.ttl < 0)
  895. p->mcast.ttl = 0;
  896.     if (p->mcast.ttl > 128)
  897. p->mcast.ttl = 128;
  898. } else if (!strcasecmp(token, "default")) {
  899.     p->options.default_parent = 1;
  900. } else if (!strcasecmp(token, "round-robin")) {
  901.     p->options.roundrobin = 1;
  902. #if USE_HTCP
  903. } else if (!strcasecmp(token, "htcp")) {
  904.     p->options.htcp = 1;
  905. #endif
  906. } else if (!strcasecmp(token, "no-netdb-exchange")) {
  907.     p->options.no_netdb_exchange = 1;
  908. #if USE_CARP
  909. } else if (!strncasecmp(token, "carp-load-factor=", 17)) {
  910.     if (p->type != PEER_PARENT)
  911. debug(3, 0) ("parse_peer: Ignoring carp-load-factor for non-parent %s/%dn", p->host, p->http_port);
  912.     else
  913. p->carp.load_factor = atof(token + 17);
  914. #endif
  915. #if DELAY_POOLS
  916. } else if (!strcasecmp(token, "no-delay")) {
  917.     p->options.no_delay = 1;
  918. #endif
  919. } else if (!strncasecmp(token, "login=", 6)) {
  920.     p->login = xstrdup(token + 6);
  921. } else {
  922.     debug(3, 0) ("parse_peer: token='%s'n", token);
  923.     self_destruct();
  924. }
  925.     }
  926.     if (p->weight < 1)
  927. p->weight = 1;
  928.     p->icp.version = ICP_VERSION_CURRENT;
  929.     p->tcp_up = PEER_TCP_MAGIC_COUNT;
  930. #if USE_CARP
  931.     if (p->carp.load_factor) {
  932. /* calculate this peers hash for use in CARP */
  933. p->carp.hash = 0;
  934. for (token = p->host; *token != 0; token++)
  935.     p->carp.hash += (p->carp.hash << 19) + *token;
  936.     }
  937. #endif
  938.     cbdataAdd(p, peerDestroy, MEM_PEER); /* must preceed peerDigestCreate */
  939. #if USE_CACHE_DIGESTS
  940.     if (!p->options.no_digest) {
  941. p->digest = peerDigestCreate(p);
  942. cbdataLock(p->digest); /* so we know when/if digest disappears */
  943.     }
  944. #endif
  945.     while (*head != NULL)
  946. head = &(*head)->next;
  947.     *head = p;
  948.     Config.npeers++;
  949. }
  950. static void
  951. free_peer(peer ** P)
  952. {
  953.     peer *p;
  954.     while ((p = *P) != NULL) {
  955. *P = p->next;
  956. #if USE_CACHE_DIGESTS
  957. if (p->digest)
  958.     cbdataUnlock(p->digest);
  959. p->digest = NULL;
  960. #endif
  961. cbdataFree(p);
  962.     }
  963.     Config.npeers = 0;
  964. }
  965. static void
  966. dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
  967. {
  968.     wordlist *w;
  969.     while (list != NULL) {
  970. if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
  971.     storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
  972. else
  973.     storeAppendPrintf(entry, "%s %s", name, list->passwd);
  974. for (w = list->actions; w != NULL; w = w->next) {
  975.     storeAppendPrintf(entry, " %s", w->key);
  976. }
  977. storeAppendPrintf(entry, "n");
  978. list = list->next;
  979.     }
  980. }
  981. static void
  982. parse_cachemgrpasswd(cachemgr_passwd ** head)
  983. {
  984.     char *passwd = NULL;
  985.     wordlist *actions = NULL;
  986.     cachemgr_passwd *p;
  987.     cachemgr_passwd **P;
  988.     parse_string(&passwd);
  989.     parse_wordlist(&actions);
  990.     p = xcalloc(1, sizeof(cachemgr_passwd));
  991.     p->passwd = passwd;
  992.     p->actions = actions;
  993.     for (P = head; *P; P = &(*P)->next);
  994.     *P = p;
  995. }
  996. static void
  997. free_cachemgrpasswd(cachemgr_passwd ** head)
  998. {
  999.     cachemgr_passwd *p;
  1000.     while ((p = *head) != NULL) {
  1001. *head = p->next;
  1002. xfree(p->passwd);
  1003. wordlistDestroy(&p->actions);
  1004. xfree(p);
  1005.     }
  1006. }
  1007. static void
  1008. dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
  1009. {
  1010.     acl_name_list *a;
  1011.     while (var != NULL) {
  1012. storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
  1013. for (a = var->acl_list; a != NULL; a = a->next)
  1014.     storeAppendPrintf(entry, " %s", a->name);
  1015. storeAppendPrintf(entry, "n");
  1016. var = var->next;
  1017.     }
  1018. }
  1019. static void
  1020. parse_denyinfo(acl_deny_info_list ** var)
  1021. {
  1022.     aclParseDenyInfoLine(var);
  1023. }
  1024. void
  1025. free_denyinfo(acl_deny_info_list ** list)
  1026. {
  1027.     acl_deny_info_list *a = NULL;
  1028.     acl_deny_info_list *a_next = NULL;
  1029.     acl_name_list *l = NULL;
  1030.     acl_name_list *l_next = NULL;
  1031.     for (a = *list; a; a = a_next) {
  1032. for (l = a->acl_list; l; l = l_next) {
  1033.     l_next = l->next;
  1034.     safe_free(l);
  1035. }
  1036. a_next = a->next;
  1037. safe_free(a);
  1038.     }
  1039.     *list = NULL;
  1040. }
  1041. static void
  1042. parse_peer_access(void)
  1043. {
  1044.     char *host = NULL;
  1045.     peer *p;
  1046.     if (!(host = strtok(NULL, w_space)))
  1047. self_destruct();
  1048.     if ((p = peerFindByName(host)) == NULL) {
  1049. debug(15, 0) ("%s, line %d: No cache_peer '%s'n",
  1050.     cfg_filename, config_lineno, host);
  1051. return;
  1052.     }
  1053.     aclParseAccessLine(&p->access);
  1054. }
  1055. static void
  1056. parse_hostdomain(void)
  1057. {
  1058.     char *host = NULL;
  1059.     char *domain = NULL;
  1060.     if (!(host = strtok(NULL, w_space)))
  1061. self_destruct();
  1062.     while ((domain = strtok(NULL, list_sep))) {
  1063. domain_ping *l = NULL;
  1064. domain_ping **L = NULL;
  1065. peer *p;
  1066. if ((p = peerFindByName(host)) == NULL) {
  1067.     debug(15, 0) ("%s, line %d: No cache_peer '%s'n",
  1068. cfg_filename, config_lineno, host);
  1069.     continue;
  1070. }
  1071. l = xcalloc(1, sizeof(domain_ping));
  1072. l->do_ping = 1;
  1073. if (*domain == '!') { /* check for !.edu */
  1074.     l->do_ping = 0;
  1075.     domain++;
  1076. }
  1077. l->domain = xstrdup(domain);
  1078. for (L = &(p->peer_domain); *L; L = &((*L)->next));
  1079. *L = l;
  1080.     }
  1081. }
  1082. static void
  1083. parse_hostdomaintype(void)
  1084. {
  1085.     char *host = NULL;
  1086.     char *type = NULL;
  1087.     char *domain = NULL;
  1088.     if (!(host = strtok(NULL, w_space)))
  1089. self_destruct();
  1090.     if (!(type = strtok(NULL, w_space)))
  1091. self_destruct();
  1092.     while ((domain = strtok(NULL, list_sep))) {
  1093. domain_type *l = NULL;
  1094. domain_type **L = NULL;
  1095. peer *p;
  1096. if ((p = peerFindByName(host)) == NULL) {
  1097.     debug(15, 0) ("%s, line %d: No cache_peer '%s'n",
  1098. cfg_filename, config_lineno, host);
  1099.     return;
  1100. }
  1101. l = xcalloc(1, sizeof(domain_type));
  1102. l->type = parseNeighborType(type);
  1103. l->domain = xstrdup(domain);
  1104. for (L = &(p->typelist); *L; L = &((*L)->next));
  1105. *L = l;
  1106.     }
  1107. }
  1108. static void
  1109. dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
  1110. {
  1111.     while (u) {
  1112. storeAppendPrintf(entry, "%s %dn", name, (int) u->i);
  1113. u = u->next;
  1114.     }
  1115. }
  1116. static int
  1117. check_null_ushortlist(ushortlist * u)
  1118. {
  1119.     return u == NULL;
  1120. }
  1121. static void
  1122. parse_ushortlist(ushortlist ** P)
  1123. {
  1124.     char *token;
  1125.     int i;
  1126.     ushortlist *u;
  1127.     ushortlist **U;
  1128.     while ((token = strtok(NULL, w_space))) {
  1129. if (sscanf(token, "%d", &i) != 1)
  1130.     self_destruct();
  1131. if (i < 0)
  1132.     i = 0;
  1133. u = xcalloc(1, sizeof(ushortlist));
  1134. u->i = (u_short) i;
  1135. for (U = P; *U; U = &(*U)->next);
  1136. *U = u;
  1137.     }
  1138. }
  1139. static void
  1140. free_ushortlist(ushortlist ** P)
  1141. {
  1142.     ushortlist *u;
  1143.     while ((u = *P) != NULL) {
  1144. *P = u->next;
  1145. xfree(u);
  1146.     }
  1147. }
  1148. static void
  1149. dump_int(StoreEntry * entry, const char *name, int var)
  1150. {
  1151.     storeAppendPrintf(entry, "%s %dn", name, var);
  1152. }
  1153. static void
  1154. parse_int(int *var)
  1155. {
  1156.     char *token;
  1157.     int i;
  1158.     GetInteger(i);
  1159.     *var = i;
  1160. }
  1161. static void
  1162. free_int(int *var)
  1163. {
  1164.     *var = 0;
  1165. }
  1166. static void
  1167. dump_onoff(StoreEntry * entry, const char *name, int var)
  1168. {
  1169.     storeAppendPrintf(entry, "%s %sn", name, var ? "on" : "off");
  1170. }
  1171. static void
  1172. parse_onoff(int *var)
  1173. {
  1174.     char *token = strtok(NULL, w_space);
  1175.     if (token == NULL)
  1176. self_destruct();
  1177.     if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
  1178. *var = 1;
  1179.     else
  1180. *var = 0;
  1181. }
  1182. #define free_onoff free_int
  1183. #define free_httpanonymizer free_int
  1184. #define dump_eol dump_string
  1185. #define free_eol free_string
  1186. static void
  1187. dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
  1188. {
  1189.     while (head != NULL) {
  1190. storeAppendPrintf(entry, "%s%s %s %d %d%% %dn",
  1191.     name,
  1192.     head->flags.icase ? " -i" : null_string,
  1193.     head->pattern,
  1194.     (int) head->min / 60,
  1195.     (int) (100.0 * head->pct + 0.5),
  1196.     (int) head->max / 60);
  1197. #if HTTP_VIOLATIONS
  1198. if (head->flags.override_expire)
  1199.     storeAppendPrintf(entry, " override-expire");
  1200. if (head->flags.override_lastmod)
  1201.     storeAppendPrintf(entry, " override-lastmod");
  1202. if (head->flags.reload_into_ims)
  1203.     storeAppendPrintf(entry, " reload-into-ims");
  1204. if (head->flags.ignore_reload)
  1205.     storeAppendPrintf(entry, " ignore-reload");
  1206. #endif
  1207. storeAppendPrintf(entry, "n");
  1208. head = head->next;
  1209.     }
  1210. }
  1211. static void
  1212. parse_refreshpattern(refresh_t ** head)
  1213. {
  1214.     char *token;
  1215.     char *pattern;
  1216.     time_t min = 0;
  1217.     double pct = 0.0;
  1218.     time_t max = 0;
  1219. #if HTTP_VIOLATIONS
  1220.     int override_expire = 0;
  1221.     int override_lastmod = 0;
  1222.     int reload_into_ims = 0;
  1223.     int ignore_reload = 0;
  1224. #endif
  1225.     int i;
  1226.     refresh_t *t;
  1227.     regex_t comp;
  1228.     int errcode;
  1229.     int flags = REG_EXTENDED | REG_NOSUB;
  1230.     if ((token = strtok(NULL, w_space)) == NULL)
  1231. self_destruct();
  1232.     if (strcmp(token, "-i") == 0) {
  1233. flags |= REG_ICASE;
  1234. token = strtok(NULL, w_space);
  1235.     } else if (strcmp(token, "+i") == 0) {
  1236. flags &= ~REG_ICASE;
  1237. token = strtok(NULL, w_space);
  1238.     }
  1239.     if (token == NULL)
  1240. self_destruct();
  1241.     pattern = xstrdup(token);
  1242.     GetInteger(i); /* token: min */
  1243.     min = (time_t) (i * 60); /* convert minutes to seconds */
  1244.     GetInteger(i); /* token: pct */
  1245.     pct = (double) i / 100.0;
  1246.     GetInteger(i); /* token: max */
  1247.     max = (time_t) (i * 60); /* convert minutes to seconds */
  1248.     /* Options */
  1249.     while ((token = strtok(NULL, w_space)) != NULL) {
  1250. #if HTTP_VIOLATIONS
  1251. if (!strcmp(token, "override-expire"))
  1252.     override_expire = 1;
  1253. else if (!strcmp(token, "override-lastmod"))
  1254.     override_lastmod = 1;
  1255. else if (!strcmp(token, "reload-into-ims")) {
  1256.     reload_into_ims = 1;
  1257.     refresh_nocache_hack = 1;
  1258.     /* tell client_side.c that this is used */
  1259. } else if (!strcmp(token, "ignore-reload")) {
  1260.     ignore_reload = 1;
  1261.     refresh_nocache_hack = 1;
  1262.     /* tell client_side.c that this is used */
  1263. } else
  1264. #endif
  1265.     debug(22, 0) ("redreshAddToList: Unknown option '%s': %sn",
  1266. pattern, token);
  1267.     }
  1268.     if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
  1269. char errbuf[256];
  1270. regerror(errcode, &comp, errbuf, sizeof errbuf);
  1271. debug(22, 0) ("%s line %d: %sn",
  1272.     cfg_filename, config_lineno, config_input_line);
  1273. debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %sn",
  1274.     pattern, errbuf);
  1275. return;
  1276.     }
  1277.     pct = pct < 0.0 ? 0.0 : pct;
  1278.     max = max < 0 ? 0 : max;
  1279.     t = xcalloc(1, sizeof(refresh_t));
  1280.     t->pattern = (char *) xstrdup(pattern);
  1281.     t->compiled_pattern = comp;
  1282.     t->min = min;
  1283.     t->pct = pct;
  1284.     t->max = max;
  1285.     if (flags & REG_ICASE)
  1286. t->flags.icase = 1;
  1287. #if HTTP_VIOLATIONS
  1288.     if (override_expire)
  1289. t->flags.override_expire = 1;
  1290.     if (override_lastmod)
  1291. t->flags.override_lastmod = 1;
  1292.     if (reload_into_ims)
  1293. t->flags.reload_into_ims = 1;
  1294.     if (ignore_reload)
  1295. t->flags.ignore_reload = 1;
  1296. #endif
  1297.     t->next = NULL;
  1298.     while (*head)
  1299. head = &(*head)->next;
  1300.     *head = t;
  1301.     safe_free(pattern);
  1302. }
  1303. static void
  1304. free_refreshpattern(refresh_t ** head)
  1305. {
  1306.     refresh_t *t;
  1307.     while ((t = *head) != NULL) {
  1308. *head = t->next;
  1309. safe_free(t->pattern);
  1310. regfree(&t->compiled_pattern);
  1311. safe_free(t);
  1312.     }
  1313. }
  1314. static void
  1315. dump_string(StoreEntry * entry, const char *name, char *var)
  1316. {
  1317.     if (var != NULL)
  1318. storeAppendPrintf(entry, "%s %sn", name, var);
  1319. }
  1320. static void
  1321. parse_string(char **var)
  1322. {
  1323.     char *token = strtok(NULL, w_space);
  1324.     safe_free(*var);
  1325.     if (token == NULL)
  1326. self_destruct();
  1327.     *var = xstrdup(token);
  1328. }
  1329. static void
  1330. free_string(char **var)
  1331. {
  1332.     safe_free(*var);
  1333. }
  1334. static void
  1335. parse_eol(char *volatile *var)
  1336. {
  1337.     char *token = strtok(NULL, null_string);
  1338.     safe_free(*var);
  1339.     if (token == NULL)
  1340. self_destruct();
  1341.     *var = xstrdup(token);
  1342. }
  1343. static void
  1344. dump_time_t(StoreEntry * entry, const char *name, time_t var)
  1345. {
  1346.     storeAppendPrintf(entry, "%s %d secondsn", name, (int) var);
  1347. }
  1348. static void
  1349. parse_time_t(time_t * var)
  1350. {
  1351.     parseTimeLine(var, T_SECOND_STR);
  1352. }
  1353. static void
  1354. free_time_t(time_t * var)
  1355. {
  1356.     *var = 0;
  1357. }
  1358. static void
  1359. dump_size_t(StoreEntry * entry, const char *name, size_t var)
  1360. {
  1361.     storeAppendPrintf(entry, "%s %dn", name, (int) var);
  1362. }
  1363. static void
  1364. dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
  1365. {
  1366.     storeAppendPrintf(entry, "%s %d %sn", name, (int) var, B_BYTES_STR);
  1367. }
  1368. static void
  1369. dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
  1370. {
  1371.     storeAppendPrintf(entry, "%s %d %sn", name, (int) var, B_KBYTES_STR);
  1372. }
  1373. static void
  1374. parse_size_t(size_t * var)
  1375. {
  1376.     char *token;
  1377.     int i;
  1378.     GetInteger(i);
  1379.     *var = (size_t) i;
  1380. }
  1381. static void
  1382. parse_b_size_t(size_t * var)
  1383. {
  1384.     parseBytesLine(var, B_BYTES_STR);
  1385. }
  1386. static void
  1387. parse_kb_size_t(size_t * var)
  1388. {
  1389.     parseBytesLine(var, B_KBYTES_STR);
  1390. }
  1391. static void
  1392. free_size_t(size_t * var)
  1393. {
  1394.     *var = 0;
  1395. }
  1396. #define free_b_size_t free_size_t
  1397. #define free_kb_size_t free_size_t
  1398. #define free_mb_size_t free_size_t
  1399. #define free_gb_size_t free_size_t
  1400. static void
  1401. dump_ushort(StoreEntry * entry, const char *name, u_short var)
  1402. {
  1403.     storeAppendPrintf(entry, "%s %dn", name, var);
  1404. }
  1405. static void
  1406. free_ushort(u_short * u)
  1407. {
  1408.     *u = 0;
  1409. }
  1410. static void
  1411. parse_ushort(u_short * var)
  1412. {
  1413.     char *token;
  1414.     int i;
  1415.     GetInteger(i);
  1416.     if (i < 0)
  1417. i = 0;
  1418.     *var = (u_short) i;
  1419. }
  1420. static void
  1421. dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
  1422. {
  1423.     while (list != NULL) {
  1424. storeAppendPrintf(entry, "%s %sn", name, list->key);
  1425. list = list->next;
  1426.     }
  1427. }
  1428. static void
  1429. parse_wordlist(wordlist ** list)
  1430. {
  1431.     char *token;
  1432.     while ((token = strtok(NULL, w_space)))
  1433. wordlistAdd(list, token);
  1434. }
  1435. static int
  1436. check_null_wordlist(wordlist * w)
  1437. {
  1438.     return w == NULL;
  1439. }
  1440. static int
  1441. check_null_acl_access(acl_access * a)
  1442. {
  1443.     return a == NULL;
  1444. }
  1445. #define free_wordlist wordlistDestroy
  1446. #define free_uri_whitespace free_int
  1447. static void
  1448. parse_uri_whitespace(int *var)
  1449. {
  1450.     char *token = strtok(NULL, w_space);
  1451.     if (token == NULL)
  1452. self_destruct();
  1453.     if (!strcasecmp(token, "deny"))
  1454. *var = URI_WHITESPACE_DENY;
  1455.     else if (!strcasecmp(token, "allow"))
  1456. *var = URI_WHITESPACE_ALLOW;
  1457.     else if (!strcasecmp(token, "encode"))
  1458. *var = URI_WHITESPACE_ENCODE;
  1459.     else if (!strcasecmp(token, "chop"))
  1460. *var = URI_WHITESPACE_CHOP;
  1461.     else
  1462. self_destruct();
  1463. }
  1464. static void
  1465. dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
  1466. {
  1467.     char *s;
  1468.     if (var == URI_WHITESPACE_ALLOW)
  1469. s = "allow";
  1470.     else if (var == URI_WHITESPACE_ENCODE)
  1471. s = "encode";
  1472.     else if (var == URI_WHITESPACE_CHOP)
  1473. s = "chop";
  1474.     else
  1475. s = "deny";
  1476.     storeAppendPrintf(entry, "%s %sn", name, s);
  1477. }
  1478. #include "cf_parser.c"
  1479. peer_t
  1480. parseNeighborType(const char *s)
  1481. {
  1482.     if (!strcasecmp(s, "parent"))
  1483. return PEER_PARENT;
  1484.     if (!strcasecmp(s, "neighbor"))
  1485. return PEER_SIBLING;
  1486.     if (!strcasecmp(s, "neighbour"))
  1487. return PEER_SIBLING;
  1488.     if (!strcasecmp(s, "sibling"))
  1489. return PEER_SIBLING;
  1490.     if (!strcasecmp(s, "multicast"))
  1491. return PEER_MULTICAST;
  1492.     debug(15, 0) ("WARNING: Unknown neighbor type: %sn", s);
  1493.     return PEER_SIBLING;
  1494. }
  1495. void
  1496. configFreeMemory(void)
  1497. {
  1498.     free_all();
  1499. }
  1500. static void
  1501. requirePathnameExists(const char *name, const char *path)
  1502. {
  1503.     struct stat sb;
  1504.     assert(path != NULL);
  1505.     if (stat(path, &sb) < 0)
  1506. fatalf("%s: %s", path, xstrerror());
  1507. }