]> git.ipfire.org Git - thirdparty/squid.git/blame - src/main.cc
Added one more note that http_reply_max_size is in bytes, not kilobytes.
[thirdparty/squid.git] / src / main.cc
CommitLineData
a47b9029 1
30a4f2a8 2/*
528b2c61 3 * $Id: main.cc,v 1.362 2003/01/23 00:37:23 robertc Exp $
30a4f2a8 4 *
5 * DEBUG: section 1 Startup and Main Loop
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 */
44a47c6e 35
36#include "squid.h"
e6ccf245 37#include "authenticate.h"
38#include "Store.h"
39#include "ICP.h"
528b2c61 40#include "HttpReply.h"
41#include "Mem.h"
44a47c6e 42
30a4f2a8 43/* for error reporting from xmalloc and friends */
ea3a2a69 44extern void (*failure_notify) (const char *);
30a4f2a8 45
f1dc9b30 46static int opt_send_signal = -1;
f95b8144 47static int opt_no_daemon = 0;
e13ee7ad 48static int opt_parse_cfg_only = 0;
30a4f2a8 49static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
e13ee7ad 50static int configured_once = 0;
30a4f2a8 51#if MALLOC_DBG
4d64d74a 52static int malloc_debug_level = 0;
30a4f2a8 53#endif
5cd39a10 54static volatile int do_reconfigure = 0;
55static volatile int do_rotate = 0;
2681d383 56static volatile int do_shutdown = 0;
4d7add01 57
5cd39a10 58static void mainRotate(void);
59static void mainReconfigure(void);
b984c445 60static SIGHDLR rotate_logs;
61static SIGHDLR reconfigure;
f5b8bbc4 62static void mainInitialize(void);
f5b8bbc4 63static void usage(void);
64static void mainParseOptions(int, char **);
65static void sendSignal(void);
66static void serverConnectionsOpen(void);
bbe199dc 67static void watch_child(char **);
85407535 68static void setEffectiveUser(void);
36a97e19 69#if MEM_GEN_TRACE
70extern void log_trace_done();
71extern void log_trace_init(char *);
72#endif
d723bf6b 73static EVH SquidShutdown;
b6a2f15e 74static void mainSetCwd(void);
efd900cb 75static int checkRunningPid(void);
85407535 76
e18d7fdc 77static const char *squid_start_script = "squid_start";
78
9bc73deb 79#if TEST_ACCESS
80#include "test_access.c"
81#endif
82
b8d8561b 83static void
0673c0ba 84usage(void)
ccff9601 85{
0ee4272b 86 fprintf(stderr,
969c39b9 87 "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n"
15df8349 88 " -a port Specify HTTP port number (default: %d).\n"
b6157f5e 89 " -d level Write debugging to stderr also.\n"
0ee4272b 90 " -f file Use given config-file instead of\n"
91 " %s\n"
92 " -h Print help message.\n"
e13ee7ad 93 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
94 " Parse configuration file, then send signal to \n"
95 " running copy (except -k parse) and exit.\n"
0ee4272b 96 " -s Enable logging to syslog.\n"
97 " -u port Specify ICP port number (default: %d), disable with 0.\n"
98 " -v Print version.\n"
85407535 99 " -z Create swap directories\n"
0ee4272b 100 " -C Do not catch fatal signals.\n"
101 " -D Disable initial DNS tests.\n"
a411c763 102 " -F Don't serve any requests until store is rebuilt.\n"
969c39b9 103 " -N No daemon mode.\n"
0ee4272b 104 " -R Do not set REUSEADDR on port.\n"
504123ec 105 " -S Double-check swap during rebuild.\n"
0ee4272b 106 " -V Virtual host httpd-accelerator.\n"
3013ac6d 107 " -X Force full debugging.\n"
429fdbec 108 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
30a4f2a8 109 appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
77ffc99f 110 exit(1);
ccff9601 111}
112
b8d8561b 113static void
114mainParseOptions(int argc, char *argv[])
090089c4 115{
090089c4 116 extern char *optarg;
4d64d74a 117 int c;
090089c4 118
504123ec 119 while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) {
090089c4 120 switch (c) {
090089c4 121 case 'C':
1758c627 122 opt_catch_signals = 0;
090089c4 123 break;
124 case 'D':
30a4f2a8 125 opt_dns_tests = 0;
090089c4 126 break;
30a4f2a8 127 case 'F':
128 opt_foreground_rebuild = 1;
090089c4 129 break;
f95b8144 130 case 'N':
131 opt_no_daemon = 1;
9e2225aa 132 break;
090089c4 133 case 'R':
3b4be6a6 134 opt_reuseaddr = 0;
090089c4 135 break;
b109de6b 136 case 'S':
504123ec 137 opt_store_doublecheck = 1;
b109de6b 138 break;
30a4f2a8 139 case 'V':
140 vhost_mode = 1;
141 break;
e924600d 142 case 'X':
143 /* force full debugging */
144 sigusr2_handle(SIGUSR2);
145 break;
30a4f2a8 146 case 'Y':
147 opt_reload_hit_only = 1;
148 break;
149 case 'a':
52f772de 150 parse_sockaddr_in_list_token(&Config.Sockaddr.http, optarg);
30a4f2a8 151 break;
0d90407c 152 case 'd':
723e8aa3 153 opt_debug_stderr = atoi(optarg);
0d90407c 154 break;
090089c4 155 case 'f':
00fac1f8 156 xfree(ConfigFile);
157 ConfigFile = xstrdup(optarg);
090089c4 158 break;
30a4f2a8 159 case 'h':
160 usage();
090089c4 161 break;
7690e8eb 162 case 'k':
24382924 163 if ((int) strlen(optarg) < 1)
7690e8eb 164 usage();
165 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
166 opt_send_signal = SIGHUP;
167 else if (!strncmp(optarg, "rotate", strlen(optarg)))
7e7a0442 168#ifdef _SQUID_LINUX_THREADS_
e3175d1f 169 opt_send_signal = SIGQUIT;
170#else
7690e8eb 171 opt_send_signal = SIGUSR1;
e3175d1f 172#endif
7690e8eb 173 else if (!strncmp(optarg, "debug", strlen(optarg)))
7e7a0442 174#ifdef _SQUID_LINUX_THREADS_
e3175d1f 175 opt_send_signal = SIGTRAP;
176#else
7690e8eb 177 opt_send_signal = SIGUSR2;
e3175d1f 178#endif
7690e8eb 179 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
180 opt_send_signal = SIGTERM;
6759a5fb 181 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
182 opt_send_signal = SIGINT;
7690e8eb 183 else if (!strncmp(optarg, "kill", strlen(optarg)))
184 opt_send_signal = SIGKILL;
185 else if (!strncmp(optarg, "check", strlen(optarg)))
fedac7e5 186 opt_send_signal = 0; /* SIGNULL */
e13ee7ad 187 else if (!strncmp(optarg, "parse", strlen(optarg)))
8a6218c6 188 opt_parse_cfg_only = 1; /* parse cfg file only */
7690e8eb 189 else
190 usage();
191 break;
090089c4 192 case 'm':
33ab18e8 193 if (optarg) {
30a4f2a8 194#if MALLOC_DBG
33ab18e8 195 malloc_debug_level = atoi(optarg);
196 /* NOTREACHED */
197 break;
30a4f2a8 198#else
33ab18e8 199 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
200 /* NOTREACHED */
201#endif
202 } else {
203#if XMALLOC_TRACE
204 xmalloc_trace = !xmalloc_trace;
205#else
206 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
30a4f2a8 207#endif
33ab18e8 208 }
30a4f2a8 209 case 's':
c307aec3 210#if HAVE_SYSLOG
6e40f263 211 opt_syslog_enable = 1;
30a4f2a8 212 break;
c307aec3 213#else
214 fatal("Logging to syslog not available on this platform");
215 /* NOTREACHED */
216#endif
30a4f2a8 217 case 'u':
218 icpPortNumOverride = atoi(optarg);
219 if (icpPortNumOverride < 0)
220 icpPortNumOverride = 0;
221 break;
222 case 'v':
781ba3fb 223 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
30a4f2a8 224 exit(0);
225 /* NOTREACHED */
090089c4 226 case 'z':
85407535 227 opt_create_swap_dirs = 1;
090089c4 228 break;
229 case '?':
090089c4 230 default:
ccff9601 231 usage();
090089c4 232 break;
233 }
090089c4 234 }
4d64d74a 235}
090089c4 236
7a2f978b 237/* ARGSUSED */
b8d8561b 238static void
239rotate_logs(int sig)
30a4f2a8 240{
5cd39a10 241 do_rotate = 1;
30a4f2a8 242#if !HAVE_SIGACTION
243 signal(sig, rotate_logs);
244#endif
245}
246
7a2f978b 247/* ARGSUSED */
b8d8561b 248static void
249reconfigure(int sig)
30a4f2a8 250{
5cd39a10 251 do_reconfigure = 1;
30a4f2a8 252#if !HAVE_SIGACTION
253 signal(sig, reconfigure);
254#endif
255}
256
b8d8561b 257void
258shut_down(int sig)
30a4f2a8 259{
2681d383 260 do_shutdown = sig == SIGINT ? -1 : 1;
cadc2d55 261#ifdef KILL_PARENT_OPT
5cd39a10 262 if (getppid() > 1) {
263 debug(1, 1) ("Killing RunCache, pid %d\n", getppid());
a0a9b12d 264 if (kill(getppid(), sig) < 0)
265 debug(1, 1) ("kill %d: %s\n", getppid(), xstrerror());
88738790 266 }
cadc2d55 267#endif
6e40f263 268#if SA_RESETHAND == 0
269 signal(SIGTERM, SIG_DFL);
270 signal(SIGINT, SIG_DFL);
271#endif
30a4f2a8 272}
273
24382924 274static void
0673c0ba 275serverConnectionsOpen(void)
4d64d74a 276{
d193a436 277 clientOpenListenSockets();
15df8349 278 icpConnectionsOpen();
ace287ee 279#if USE_HTCP
280 htcpInit();
281#endif
678c6099 282#ifdef SQUID_SNMP
3265e68d 283 snmpConnectionOpen();
320e9f36 284#endif
eb824054 285#if USE_WCCP
320e9f36 286 wccpConnectionOpen();
2bbd722b 287#endif
5ecceaa4 288 clientdbInit();
16b204c4 289 icmpOpen();
67508012 290 netdbInit();
f899fac1 291 asnInit();
85034133 292 peerSelectInit();
afd88fbe 293#if USE_CARP
294 carpInit();
295#endif
5f3f8d0e 296}
297
b8d8561b 298void
0673c0ba 299serverConnectionsClose(void)
5f3f8d0e 300{
0a5a8601 301 assert(shutting_down || reconfiguring);
c0fbae16 302 clientHttpConnectionsClose();
17e6c0a1 303 icpConnectionShutdown();
72549e05 304#if USE_HTCP
305 htcpSocketShutdown();
306#endif
c0fbae16 307 icmpClose();
15df8349 308#ifdef SQUID_SNMP
17e6c0a1 309 snmpConnectionShutdown();
320e9f36 310#endif
eb824054 311#if USE_WCCP
320e9f36 312 wccpConnectionShutdown();
15df8349 313#endif
4bac8de8 314 asnFreeMemory();
5f3f8d0e 315}
316
b8d8561b 317static void
dbe4fd8e 318mainReconfigure(void)
5f3f8d0e 319{
a60f7062 320 debug(1, 1) ("Restarting Squid Cache (version %s)...\n", version_string);
5cd39a10 321 reconfiguring = 1;
0ffd22bc 322 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
15df8349 323 serverConnectionsClose();
17e6c0a1 324 icpConnectionClose();
72549e05 325#if USE_HTCP
326 htcpSocketClose();
327#endif
17e6c0a1 328#ifdef SQUID_SNMP
329 snmpConnectionClose();
320e9f36 330#endif
eb824054 331#if USE_WCCP
320e9f36 332 wccpConnectionClose();
17e6c0a1 333#endif
3c573763 334#if USE_DNSSERVERS
74addf6c 335 dnsShutdown();
3c573763 336#else
7b724b86 337 idnsShutdown();
eb824054 338#endif
74addf6c 339 redirectShutdown();
340 authenticateShutdown();
d9572179 341 externalAclShutdown();
2db68ce5 342 storeDirCloseSwapLogs();
c68e9c6b 343 errorClean();
3aa4adbc 344 enter_suid(); /* root to read config file */
00fac1f8 345 parseConfigFile(ConfigFile);
3aa4adbc 346 setEffectiveUser();
b6f794d6 347 _db_init(Config.Log.log, Config.debugOptions);
429fdbec 348 ipcache_restart(); /* clear stuck entries */
94439e4e 349 authenticateUserCacheRestart(); /* clear stuck ACL entries */
429fdbec 350 fqdncache_restart(); /* sigh, fqdncache too */
0e70aa1e 351 parseEtcHosts();
53ad48e6 352 errorInitialize(); /* reload error pages */
3c573763 353#if USE_DNSSERVERS
74addf6c 354 dnsInit();
3c573763 355#else
7b724b86 356 idnsInit();
eb824054 357#endif
74addf6c 358 redirectInit();
e6ccf245 359 authenticateInit(&Config.authConfiguration);
d9572179 360 externalAclInit();
1f38f50a 361#if USE_WCCP
362 wccpInit();
363#endif
0ffd22bc 364 serverConnectionsOpen();
e06ce23a 365 if (theOutIcpConnection >= 0) {
5942e8d4 366 if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
e06ce23a 367 neighbors_open(theOutIcpConnection);
368 else
369 debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
370 }
2db68ce5 371 storeDirOpenSwapLogs();
9c021a38 372 mimeInit(Config.mimeTablePathname);
b8890359 373 writePidFile(); /* write PID file */
aebbcd07 374 debug(1, 1) ("Ready to serve requests.\n");
5cd39a10 375 reconfiguring = 0;
376}
377
378static void
379mainRotate(void)
380{
381 icmpClose();
3c573763 382#if USE_DNSSERVERS
e40aa8da 383 dnsShutdown();
3c573763 384#endif
e40aa8da 385 redirectShutdown();
386 authenticateShutdown();
d9572179 387 externalAclShutdown();
5cd39a10 388 _db_rotate_log(); /* cache.log */
389 storeDirWriteCleanLogs(1);
390 storeLogRotate(); /* store.log */
391 accessLogRotate(); /* access.log */
392 useragentRotateLog(); /* useragent.log */
fd2c5549 393 refererRotateLog(); /* referer.log */
225644d7 394#if WIP_FWD_LOG
395 fwdLogRotate();
396#endif
5cd39a10 397 icmpOpen();
3c573763 398#if USE_DNSSERVERS
e40aa8da 399 dnsInit();
3c573763 400#endif
e40aa8da 401 redirectInit();
e6ccf245 402 authenticateInit(&Config.authConfiguration);
d9572179 403 externalAclInit();
5f3f8d0e 404}
405
067bea91 406static void
85407535 407setEffectiveUser(void)
408{
409 leave_suid(); /* Run as non privilegied user */
cd377065 410#ifdef _SQUID_OS2_
411 return;
412#endif
85407535 413 if (geteuid() == 0) {
414 debug(0, 0) ("Squid is not safe to run as root! If you must\n");
415 debug(0, 0) ("start Squid as root, then you must configure\n");
416 debug(0, 0) ("it to run as a non-priveledged user with the\n");
417 debug(0, 0) ("'cache_effective_user' option in the config file.\n");
418 fatal("Don't run Squid as root, set 'cache_effective_user'!");
419 }
420}
421
b6a2f15e 422static void
423mainSetCwd(void)
424{
4a504376 425 char pathbuf[MAXPATHLEN];
b6a2f15e 426 if (Config.coredump_dir) {
0ce9df27 427 if (0 == strcmp("none", Config.coredump_dir)) {
428 (void) 0;
429 } else if (chdir(Config.coredump_dir) == 0) {
b6a2f15e 430 debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
431 return;
432 } else {
433 debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
434 }
435 }
02e8115e 436 /* If we don't have coredump_dir or couldn't cd there, report current dir */
4a504376 437 if (getcwd(pathbuf, MAXPATHLEN)) {
438 debug(0, 1) ("Current Directory is %s\n", pathbuf);
439 } else {
440 debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
441 }
b6a2f15e 442}
443
b8d8561b 444static void
0673c0ba 445mainInitialize(void)
5f3f8d0e 446{
efd900cb 447 /* chroot if configured to run inside chroot */
448 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
449 fatal("failed to chroot");
450 }
1758c627 451 if (opt_catch_signals) {
30a4f2a8 452 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
453 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
44f99671 454 }
30a4f2a8 455 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
456 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
44f99671 457
85407535 458 setEffectiveUser();
30a4f2a8 459 if (icpPortNumOverride != 1)
f2052513 460 Config.Port.icp = (u_short) icpPortNumOverride;
30a4f2a8 461
b6f794d6 462 _db_init(Config.Log.log, Config.debugOptions);
5c5783a2 463 fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
71a17702 464#if MEM_GEN_TRACE
465 log_trace_init("/tmp/squid.alloc");
466#endif
a3d5953d 467 debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
30a4f2a8 468 version_string,
469 CONFIG_HOST_TYPE);
aebbcd07 470 debug(1, 1) ("Process ID %d\n", (int) getpid());
a3d5953d 471 debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
5f3f8d0e 472
9f75c559 473 if (!configured_once)
234967c9 474 disk_init(); /* disk_init must go before ipcache_init() */
5f3f8d0e 475 ipcache_init();
f88bb09c 476 fqdncache_init();
0e70aa1e 477 parseEtcHosts();
3c573763 478#if USE_DNSSERVERS
74addf6c 479 dnsInit();
3c573763 480#else
7b724b86 481 idnsInit();
eb824054 482#endif
74addf6c 483 redirectInit();
e6ccf245 484 authenticateInit(&Config.authConfiguration);
d9572179 485 externalAclInit();
b012353a 486 useragentOpenLog();
fd2c5549 487 refererOpenLog();
2ac76861 488 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
2246b732 489 httpReplyInitModule(); /* must go before accepting replies */
9b312a19 490 errorInitialize();
7a2f978b 491 accessLogInit();
3898f57f 492#if USE_IDENT
05832ae1 493 identInit();
3898f57f 494#endif
5e14bf6d 495#ifdef SQUID_SNMP
496 snmpInit();
497#endif
30a4f2a8 498#if MALLOC_DBG
5f3f8d0e 499 malloc_debug(0, malloc_debug_level);
500#endif
501
dbe4fd8e 502 if (!configured_once) {
a3d0a19d 503#if USE_UNLINKD
429fdbec 504 unlinkdInit();
a3d0a19d 505#endif
7111c86a 506 urlInitialize();
22f3fd98 507 cachemgrInit();
a7c05555 508 statInit();
5f3f8d0e 509 storeInit();
b6a2f15e 510 mainSetCwd();
5f3f8d0e 511 /* after this point we want to see the mallinfo() output */
512 do_mallinfo = 1;
812ed90c 513 mimeInit(Config.mimeTablePathname);
603a02fd 514 pconnInit();
1c3e77cd 515 refreshInit();
0d7e5d78 516#if DELAY_POOLS
95e36d02 517 delayPoolsInit();
0d7e5d78 518#endif
8ddcc35d 519 fwdInit();
5f3f8d0e 520 }
1f38f50a 521#if USE_WCCP
522 wccpInit();
523#endif
2285407f 524 serverConnectionsOpen();
e06ce23a 525 if (theOutIcpConnection >= 0) {
5942e8d4 526 if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
e06ce23a 527 neighbors_open(theOutIcpConnection);
528 else
529 debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
530 }
efd900cb 531 if (Config.chroot_dir)
532 no_suid();
dbe4fd8e 533 if (!configured_once)
0a5b9b32 534 writePidFile(); /* write PID file */
535
7e7a0442 536#ifdef _SQUID_LINUX_THREADS_
e3175d1f 537 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
538 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
539#else
30a4f2a8 540 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
541 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
9fc0b4b8 542#endif
30a4f2a8 543 squid_signal(SIGHUP, reconfigure, SA_RESTART);
544 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
545 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
58a39dc9 546 memCheckInit();
aebbcd07 547 debug(1, 1) ("Ready to serve requests.\n");
dbe4fd8e 548 if (!configured_once) {
52040193 549 eventAdd("storeMaintain", storeMaintainSwapSpace, NULL, 1.0, 1);
17a0a4ee 550 if (Config.onoff.announce)
52040193 551 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
552 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
553 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
88bfe092 554#if USE_XPROF_STATS
555 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
556#endif
e6ccf245 557
528b2c61 558 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
4d7add01 559 }
dbe4fd8e 560 configured_once = 1;
4d64d74a 561}
562
b8d8561b 563int
564main(int argc, char **argv)
4d64d74a 565{
566 int errcount = 0;
4d64d74a 567 int n; /* # of GC'd objects */
7e3ce7b9 568 mode_t oldmask;
0e6d05ef 569#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
570 int WIN32_init_err;
571#endif
4d64d74a 572
a4ba1105 573#if HAVE_SBRK
574 sbrk_start = sbrk(0);
575#endif
576
88738790 577 debug_log = stderr;
e83892e9 578 if (FD_SETSIZE < Squid_MaxFD)
579 Squid_MaxFD = FD_SETSIZE;
399e85ea 580
0e6d05ef 581#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
35fb8810 582 if ((WIN32_init_err = WIN32_Subsystem_Init()))
0e6d05ef 583 return WIN32_init_err;
584#endif
585
7328e889 586 /* call mallopt() before anything else */
0b29fe44 587#if HAVE_MALLOPT
7328e889 588#ifdef M_GRAIN
589 /* Round up all sizes to a multiple of this */
590 mallopt(M_GRAIN, 16);
591#endif
592#ifdef M_MXFAST
593 /* biggest size that is considered a small block */
594 mallopt(M_MXFAST, 256);
595#endif
596#ifdef M_NBLKS
597 /* allocate this many small blocks at once */
598 mallopt(M_NLBLKS, 32);
599#endif
600#endif /* HAVE_MALLOPT */
601
7e3ce7b9 602 /*
603 * The plan here is to set the umask to 007 (deny others for
604 * read,write,execute), but only if the umask is not already
605 * set. Unfortunately, there is no way to get the current
606 * umask value without setting it.
607 */
608 oldmask = umask(S_IRWXO);
609 if (oldmask)
610 umask(oldmask);
611
30a4f2a8 612 memset(&local_addr, '\0', sizeof(struct in_addr));
429fdbec 613 safe_inet_addr(localhost, &local_addr);
28070024 614 memset(&any_addr, '\0', sizeof(struct in_addr));
429fdbec 615 safe_inet_addr("0.0.0.0", &any_addr);
28070024 616 memset(&no_addr, '\0', sizeof(struct in_addr));
429fdbec 617 safe_inet_addr("255.255.255.255", &no_addr);
88738790 618 squid_srandom(time(NULL));
4d64d74a 619
f2908497 620 getCurrentTime();
621 squid_start = current_time;
4d64d74a 622 failure_notify = fatal_dump;
623
624 mainParseOptions(argc, argv);
625
e13ee7ad 626 /* parse configuration file
627 * note: in "normal" case this used to be called from mainInitialize() */
628 {
629 int parse_err;
630 if (!ConfigFile)
631 ConfigFile = xstrdup(DefaultConfigFile);
3cc5715b 632 assert(!configured_once);
5d620373 633#if USE_LEAKFINDER
634 leakInit();
635#endif
528b2c61 636 Mem::Init();
28c60158 637 cbdataInit();
9bc73deb 638 eventInit(); /* eventInit() is required for config parsing */
cd748f27 639 storeFsInit(); /* required for config parsing */
94439e4e 640 authenticateSchemeInit(); /* required for config parsign */
e13ee7ad 641 parse_err = parseConfigFile(ConfigFile);
8a6218c6 642
e13ee7ad 643 if (opt_parse_cfg_only)
644 return parse_err;
645 }
efd900cb 646 if (-1 == opt_send_signal)
647 if (checkRunningPid())
648 exit(1);
e13ee7ad 649
9bc73deb 650#if TEST_ACCESS
651 comm_init();
652 comm_select_init();
653 mainInitialize();
654 test_access();
655 return 0;
656#endif
657
7690e8eb 658 /* send signal to running copy and exit */
659 if (opt_send_signal != -1) {
efd900cb 660 /* chroot if configured to run inside chroot */
661 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
662 fatal("failed to chroot");
663 }
7690e8eb 664 sendSignal();
665 /* NOTREACHED */
666 }
85407535 667 if (opt_create_swap_dirs) {
efd900cb 668 /* chroot if configured to run inside chroot */
669 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
670 fatal("failed to chroot");
671 }
067bea91 672 setEffectiveUser();
673 debug(0, 0) ("Creating Swap Directories\n");
674 storeCreateSwapDirectories();
675 return 0;
676 }
f95b8144 677 if (!opt_no_daemon)
bbe199dc 678 watch_child(argv);
4d64d74a 679 setMaxFD();
680
1758c627 681 if (opt_catch_signals)
e83892e9 682 for (n = Squid_MaxFD; n > 2; n--)
30a4f2a8 683 close(n);
4d64d74a 684
e13ee7ad 685 /* init comm module */
4d64d74a 686 comm_init();
6a988308 687 comm_select_init();
4d64d74a 688
54f742e7 689 if (opt_no_daemon) {
690 /* we have to init fdstat here. */
691 fd_open(0, FD_LOG, "stdin");
692 fd_open(1, FD_LOG, "stdout");
693 fd_open(2, FD_LOG, "stderr");
694 }
4d64d74a 695 mainInitialize();
696
090089c4 697 /* main loop */
983061ed 698 for (;;) {
5cd39a10 699 if (do_reconfigure) {
969c39b9 700 mainReconfigure();
5cd39a10 701 do_reconfigure = 0;
702 } else if (do_rotate) {
703 mainRotate();
704 do_rotate = 0;
2681d383 705 } else if (do_shutdown) {
73c9ccc5 706 time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
5cd39a10 707 debug(1, 1) ("Preparing for shutdown after %d requests\n",
83704487 708 statCounter.client_http.requests);
5cd39a10 709 debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
84f2d773 710 (int) wait);
2681d383 711 do_shutdown = 0;
712 shutting_down = 1;
d723bf6b 713 serverConnectionsClose();
3c573763 714#if USE_DNSSERVERS
74addf6c 715 dnsShutdown();
3c573763 716#else
7b724b86 717 idnsShutdown();
eb824054 718#endif
74addf6c 719 redirectShutdown();
d9572179 720 externalAclShutdown();
d723bf6b 721 eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
30a4f2a8 722 }
48f44632 723 eventRun();
f24629ba 724 int loop_delay = eventNextTime();
725 if (loop_delay < 0)
4d7add01 726 loop_delay = 0;
a48a31d5 727 /* Attempt any pending storedir IO */
728 storeDirCallback();
c4b7a5a9 729 comm_calliocallback();
9ca89c5a 730 switch (comm_select(loop_delay)) {
090089c4 731 case COMM_OK:
234967c9 732 errcount = 0; /* reset if successful */
090089c4 733 break;
734 case COMM_ERROR:
735 errcount++;
a3d5953d 736 debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
090089c4 737 if (errcount == 10)
4d64d74a 738 fatal_dump("Select Loop failed!");
090089c4 739 break;
9ca89c5a 740 case COMM_TIMEOUT:
6c93e119 741 break;
d723bf6b 742 case COMM_SHUTDOWN:
743 SquidShutdown(NULL);
744 break;
090089c4 745 default:
6eb42cae 746 fatal_dump("MAIN: Internal error -- this should never happen.");
090089c4 747 break;
748 }
749 }
750 /* NOTREACHED */
983061ed 751 return 0;
090089c4 752}
7690e8eb 753
b8d8561b 754static void
0673c0ba 755sendSignal(void)
7690e8eb 756{
ff8d0ea6 757 pid_t pid;
fedac7e5 758 debug_log = stderr;
fedac7e5 759 pid = readPidFile();
760 if (pid > 1) {
761 if (kill(pid, opt_send_signal) &&
762 /* ignore permissions if just running check */
763 !(opt_send_signal == 0 && errno == EPERM)) {
764 fprintf(stderr, "%s: ERROR: Could not send ", appname);
765 fprintf(stderr, "signal %d to process %d: %s\n",
41d30aa8 766 opt_send_signal, (int) pid, xstrerror());
7690e8eb 767 exit(1);
768 }
fedac7e5 769 } else {
770 fprintf(stderr, "%s: ERROR: No running copy\n", appname);
771 exit(1);
7690e8eb 772 }
fedac7e5 773 /* signal successfully sent */
774 exit(0);
775}
f95b8144 776
e18d7fdc 777/*
778 * This function is run when Squid is in daemon mode, just
779 * before the parent forks and starts up the child process.
780 * It can be used for admin-specific tasks, such as notifying
781 * someone that Squid is (re)started.
782 */
783static void
784mainStartScript(const char *prog)
785{
786 char script[SQUID_MAXPATHLEN];
787 char *t;
788 size_t sl = 0;
789 pid_t cpid;
790 pid_t rpid;
791 xstrncpy(script, prog, MAXPATHLEN);
792 if ((t = strrchr(script, '/'))) {
793 *(++t) = '\0';
794 sl = strlen(script);
795 }
796 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
797 if ((cpid = fork()) == 0) {
798 /* child */
799 execl(script, squid_start_script, 0);
800 _exit(0);
801 } else {
802 do {
803#ifdef _SQUID_NEXT_
804 union wait status;
805 rpid = wait3(&status, 0, NULL);
806#else
807 int status;
808 rpid = waitpid(-1, &status, 0);
809#endif
810 } while (rpid != cpid);
811 }
812}
813
efd900cb 814static int
815checkRunningPid(void)
816{
817 pid_t pid;
818 debug_log = stderr;
819 pid = readPidFile();
820 if (pid < 2)
821 return 0;
822 if (kill(pid, 0) < 0)
823 return 0;
824 debug(0, 0) ("Squid is already running! Process ID %d\n", pid);
825 return 1;
826}
827
f95b8144 828static void
bbe199dc 829watch_child(char *argv[])
f95b8144 830{
831 char *prog;
f95b8144 832 int failcount = 0;
833 time_t start;
834 time_t stop;
835#ifdef _SQUID_NEXT_
836 union wait status;
837#else
838 int status;
839#endif
e3a3b845 840 pid_t pid;
54f742e7 841 int i;
742724a4 842 int nullfd;
f95b8144 843 if (*(argv[0]) == '(')
844 return;
54f742e7 845 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
846 if ((pid = fork()) < 0)
847 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
848 else if (pid > 0)
849 exit(0);
850 if (setsid() < 0)
851 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
efd900cb 852 closelog();
54f742e7 853#ifdef TIOCNOTTY
c4aefe96 854 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
54f742e7 855 ioctl(i, TIOCNOTTY, NULL);
856 close(i);
857 }
858#endif
b05490a8 859
860
7f6ffd15 861 /*
862 * RBCOLLINS - if cygwin stackdumps when squid is run without
863 * -N, check the cygwin1.dll version, it needs to be AT LEAST
864 * 1.1.3. execvp had a bit overflow error in a loop..
865 */
742724a4 866 /* Connect stdio to /dev/null in daemon mode */
c4aefe96 867 nullfd = open("/dev/null", O_RDWR | O_TEXT);
742724a4 868 dup2(nullfd, 0);
869 if (opt_debug_stderr < 0) {
870 dup2(nullfd, 1);
871 dup2(nullfd, 2);
872 }
873 /* Close all else */
874 for (i = 3; i < Squid_MaxFD; i++)
54f742e7 875 close(i);
f95b8144 876 for (;;) {
e18d7fdc 877 mainStartScript(argv[0]);
54f742e7 878 if ((pid = fork()) == 0) {
f95b8144 879 /* child */
efd900cb 880 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
f95b8144 881 prog = xstrdup(argv[0]);
bbe199dc 882 argv[0] = xstrdup("(squid)");
883 execvp(prog, argv);
54f742e7 884 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
f95b8144 885 }
54f742e7 886 /* parent */
efd900cb 887 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
54f742e7 888 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
889 time(&start);
890 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
f95b8144 891#ifdef _SQUID_NEXT_
54f742e7 892 pid = wait3(&status, 0, NULL);
f95b8144 893#else
54f742e7 894 pid = waitpid(-1, &status, 0);
f95b8144 895#endif
896 time(&stop);
54f742e7 897 if (WIFEXITED(status)) {
898 syslog(LOG_NOTICE,
899 "Squid Parent: child process %d exited with status %d",
900 pid, WEXITSTATUS(status));
901 } else if (WIFSIGNALED(status)) {
902 syslog(LOG_NOTICE,
903 "Squid Parent: child process %d exited due to signal %d",
904 pid, WTERMSIG(status));
905 } else {
906 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
907 }
f95b8144 908 if (stop - start < 10)
909 failcount++;
a8e69881 910 else
911 failcount = 0;
54f742e7 912 if (failcount == 5) {
913 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
f95b8144 914 exit(1);
54f742e7 915 }
f95b8144 916 if (WIFEXITED(status))
917 if (WEXITSTATUS(status) == 0)
918 exit(0);
08949224 919 if (WIFSIGNALED(status)) {
920 switch (WTERMSIG(status)) {
921 case SIGKILL:
922 exit(0);
923 break;
924 default:
925 break;
926 }
927 }
0fb4fc71 928 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
f95b8144 929 sleep(3);
930 }
bbe199dc 931 /* NOTREACHED */
f95b8144 932}
fff6ad65 933
9ec1a1dc 934static void
d723bf6b 935SquidShutdown(void *unused)
fff6ad65 936{
937 debug(1, 1) ("Shutting down...\n");
938 if (Config.pidFilename && strcmp(Config.pidFilename, "none")) {
939 enter_suid();
940 safeunlink(Config.pidFilename, 0);
941 leave_suid();
942 }
d723bf6b 943 icpConnectionClose();
944#if USE_HTCP
945 htcpSocketClose();
946#endif
947#ifdef SQUID_SNMP
948 snmpConnectionClose();
320e9f36 949#endif
eb824054 950#if USE_WCCP
320e9f36 951 wccpConnectionClose();
d723bf6b 952#endif
fff6ad65 953 releaseServerSockets();
d723bf6b 954 commCloseAllSockets();
5dae8514 955 authenticateShutdown();
a3d0a19d 956#if USE_UNLINKD
fff6ad65 957 unlinkdClose();
a3d0a19d 958#endif
cd748f27 959 storeDirSync(); /* Flush pending object writes/unlinks */
fff6ad65 960 storeDirWriteCleanLogs(0);
961 PrintRusage();
962 dumpMallocStats();
cd748f27 963 storeDirSync(); /* Flush log writes */
fff6ad65 964 storeLogClose();
965 accessLogClose();
5b824235 966 useragentLogClose();
c9b99797 967 refererCloseLog();
225644d7 968#if WIP_FWD_LOG
969 fwdUninit();
970#endif
cd748f27 971 storeDirSync(); /* Flush log close */
33ab18e8 972#if PURIFY || XMALLOC_TRACE
cd748f27 973 storeFsDone();
fff6ad65 974 configFreeMemory();
975 storeFreeMemory();
33ab18e8 976 /*stmemFreeMemory(); */
fff6ad65 977 netdbFreeMemory();
978 ipcacheFreeMemory();
979 fqdncacheFreeMemory();
980 asnFreeMemory();
26a369ba 981 clientdbFreeMemory();
7021844c 982 httpHeaderCleanModule();
d2db411c 983 statFreeMemory();
f1fc2a8d 984 eventFreeMemory();
c68e9c6b 985 mimeFreeMemory();
986 errorClean();
fff6ad65 987#endif
26a369ba 988#if !XMALLOC_TRACE
54f742e7 989 if (opt_no_daemon) {
990 file_close(0);
991 file_close(1);
992 file_close(2);
993 }
33ab18e8 994#endif
fff6ad65 995 fdDumpOpen();
996 fdFreeMemory();
ddb43c58 997 memClean();
33ab18e8 998#if XMALLOC_TRACE
26a369ba 999 xmalloc_find_leaks();
1000 debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
33ab18e8 1001#endif
36a97e19 1002#if MEM_GEN_TRACE
399e85ea 1003 log_trace_done();
36a97e19 1004#endif
a60f7062 1005 debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
fff6ad65 1006 version_string);
7e3ce7b9 1007 if (debug_log)
1008 fclose(debug_log);
fff6ad65 1009 exit(0);
1010}