]> git.ipfire.org Git - thirdparty/squid.git/blame - src/main.cc
Error page auto-negotiation.
[thirdparty/squid.git] / src / main.cc
CommitLineData
30a4f2a8 1/*
63be0a78 2 * $Id: main.cc,v 1.459 2008/02/26 21:49:35 amosjeffries Exp $
30a4f2a8 3 *
4 * DEBUG: section 1 Startup and Main Loop
5 * AUTHOR: Harvest Derived
6 *
2b6662ba 7 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 8 * ----------------------------------------------------------
30a4f2a8 9 *
2b6662ba 10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
30a4f2a8 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
cbdec147 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 32 *
30a4f2a8 33 */
44a47c6e 34
35#include "squid.h"
450e0c10 36#include "AccessLogEntry.h"
e6ccf245 37#include "authenticate.h"
62ee09ca 38#include "ConfigParser.h"
aa839030 39#include "errorpage.h"
a553a5a3 40#include "event.h"
41#include "EventLoop.h"
62ee09ca 42#include "ExternalACL.h"
e6ccf245 43#include "Store.h"
44#include "ICP.h"
5a7431b8 45#include "ident.h"
528b2c61 46#include "HttpReply.h"
62ee09ca 47#include "pconn.h"
528b2c61 48#include "Mem.h"
b0dd28ba 49#include "ACLASN.h"
50#include "ACL.h"
75faaa7a 51#include "htcp.h"
59b2d47f 52#include "StoreFileSystem.h"
b9ae18aa 53#include "DiskIO/DiskIOModule.h"
f900210a 54#include "comm.h"
62ee09ca 55#if USE_EPOLL
56#include "comm_epoll.h"
57#endif
58#if USE_KQUEUE
59#include "comm_kqueue.h"
60#endif
61#if USE_POLL
62#include "comm_poll.h"
63#endif
7cdb47bc 64#if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
663c0a38 65#include "comm_select.h"
66#endif
985c86bc 67#include "SquidTime.h"
c8f4eac4 68#include "SwapDir.h"
b6b6f466 69#include "forward.h"
d9e7ee1f 70#include "MemPool.h"
cc192b50 71#include "ICMPSquid.h"
44a47c6e 72
57afc994
AR
73#if USE_LOADABLE_MODULES
74#include "LoadableModules.h"
75#endif
76
b958cb0f
AR
77#if ICAP_CLIENT
78#include "ICAP/ICAPConfig.h"
79#endif
80#if USE_ADAPTATION
81#include "adaptation/Config.h"
82#endif
83
1a774556 84#if USE_WIN32_SERVICE
85
86#include "squid_windows.h"
87#include <process.h>
88
89static int opt_install_service = FALSE;
90static int opt_remove_service = FALSE;
91static int opt_signal_service = FALSE;
92static int opt_command_line = FALSE;
93extern void WIN32_svcstatusupdate(DWORD, DWORD);
94void WINAPI WIN32_svcHandler(DWORD);
95
96#endif
97
63be0a78 98/** for error reporting from xmalloc and friends */
b293c4d8 99SQUIDCEXTERN void (*failure_notify) (const char *);
30a4f2a8 100
e13ee7ad 101static int opt_parse_cfg_only = 0;
5e6d4736 102static char *opt_syslog_facility = NULL;
30a4f2a8 103static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
e13ee7ad 104static int configured_once = 0;
30a4f2a8 105#if MALLOC_DBG
4d64d74a 106static int malloc_debug_level = 0;
30a4f2a8 107#endif
5cd39a10 108static volatile int do_reconfigure = 0;
109static volatile int do_rotate = 0;
2681d383 110static volatile int do_shutdown = 0;
ae1feb30 111static volatile int shutdown_status = 0;
4d7add01 112
5cd39a10 113static void mainRotate(void);
114static void mainReconfigure(void);
f5b8bbc4 115static void mainInitialize(void);
f5b8bbc4 116static void usage(void);
63be0a78 117static void mainParseOptions(int argc, char *argv[]);
f5b8bbc4 118static void sendSignal(void);
119static void serverConnectionsOpen(void);
bbe199dc 120static void watch_child(char **);
85407535 121static void setEffectiveUser(void);
36a97e19 122#if MEM_GEN_TRACE
123extern void log_trace_done();
124extern void log_trace_init(char *);
125#endif
8ff3fa2e 126static void SquidShutdown(void);
b6a2f15e 127static void mainSetCwd(void);
efd900cb 128static int checkRunningPid(void);
85407535 129
b293c4d8 130#ifndef _SQUID_MSWIN_
e18d7fdc 131static const char *squid_start_script = "squid_start";
b293c4d8 132#endif
e18d7fdc 133
9bc73deb 134#if TEST_ACCESS
135#include "test_access.c"
136#endif
137
63be0a78 138/** temporary thunk across to the unrefactored store interface */
8ff3fa2e 139
140class StoreRootEngine : public AsyncEngine
141{
142
143public:
144 int checkEvents(int timeout)
145 {
146 Store::Root().callback();
147 return EVENT_IDLE;
148 };
149};
150
9688b0ae 151class SignalEngine: public AsyncEngine
a553a5a3 152{
153
154public:
9688b0ae 155 SignalEngine(EventLoop &loop) : loop(loop) {}
156 virtual int checkEvents(int timeout);
a553a5a3 157
158private:
159 static void StopEventLoop(void * data)
160 {
9688b0ae 161 static_cast<SignalEngine *>(data)->loop.stop();
a553a5a3 162 }
163
9688b0ae 164 void doShutdown(time_t wait);
165
a553a5a3 166 EventLoop &loop;
167};
168
9688b0ae 169int
170SignalEngine::checkEvents(int timeout)
a553a5a3 171{
9688b0ae 172 PROF_start(SignalEngine_checkEvents);
fc68f6b1 173
a553a5a3 174 if (do_reconfigure) {
175 mainReconfigure();
176 do_reconfigure = 0;
a553a5a3 177 } else if (do_rotate) {
178 mainRotate();
179 do_rotate = 0;
180 } else if (do_shutdown) {
9688b0ae 181 doShutdown(do_shutdown > 0 ? (int) Config.shutdownLifetime : 0);
a553a5a3 182 do_shutdown = 0;
9688b0ae 183 }
a553a5a3 184
9688b0ae 185 PROF_stop(SignalEngine_checkEvents);
186 return EVENT_IDLE;
187}
a553a5a3 188
9688b0ae 189void
190SignalEngine::doShutdown(time_t wait)
191{
192 debugs(1, 1, "Preparing for shutdown after " << statCounter.client_http.requests << " requests");
193 debugs(1, 1, "Waiting " << wait << " seconds for active connections to finish");
8ff3fa2e 194
9688b0ae 195 shutting_down = 1;
196
197#if USE_WIN32_SERVICE
198 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
199#endif
200
201 serverConnectionsClose();
202 eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
a553a5a3 203}
204
b8d8561b 205static void
0673c0ba 206usage(void)
ccff9601 207{
0ee4272b 208 fprintf(stderr,
0e657244 209#if USE_WIN32_SERVICE
5e6d4736 210 "Usage: %s [-cdhirvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
0e657244 211#else
5e6d4736 212 "Usage: %s [-cdhvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
0e657244 213#endif
62e76326 214 " -a port Specify HTTP port number (default: %d).\n"
215 " -d level Write debugging to stderr also.\n"
216 " -f file Use given config-file instead of\n"
217 " %s\n"
218 " -h Print help message.\n"
0e657244 219#if USE_WIN32_SERVICE
220 " -i Installs as a Windows Service (see -n option).\n"
221#endif
62e76326 222 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
223 " Parse configuration file, then send signal to \n"
224 " running copy (except -k parse) and exit.\n"
0e657244 225#if USE_WIN32_SERVICE
226 " -n name Specify Windows Service name to use for service operations\n"
227 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
228 " -r Removes a Windows Service (see -n option).\n"
229#endif
5e6d4736 230 " -s | -l facility\n"
231 " Enable logging to syslog.\n"
62e76326 232 " -u port Specify ICP port number (default: %d), disable with 0.\n"
233 " -v Print version.\n"
234 " -z Create swap directories\n"
235 " -C Do not catch fatal signals.\n"
236 " -D Disable initial DNS tests.\n"
237 " -F Don't serve any requests until store is rebuilt.\n"
238 " -N No daemon mode.\n"
0e657244 239#if USE_WIN32_SERVICE
240 " -O options\n"
241 " Set Windows Service Command line options in Registry.\n"
242#endif
62e76326 243 " -R Do not set REUSEADDR on port.\n"
244 " -S Double-check swap during rebuild.\n"
245 " -V Virtual host httpd-accelerator.\n"
246 " -X Force full debugging.\n"
247 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
7dbca7a4 248 APP_SHORTNAME, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
77ffc99f 249 exit(1);
ccff9601 250}
251
63be0a78 252/**
253 * Parse the parameters received via command line interface.
254 *
255 \param argc[in] Number of options received on command line
256 \param argv[in] List of parameters received on command line
257 */
b8d8561b 258static void
259mainParseOptions(int argc, char *argv[])
090089c4 260{
090089c4 261 extern char *optarg;
4d64d74a 262 int c;
090089c4 263
0e657244 264#if USE_WIN32_SERVICE
5e6d4736 265 while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
0e657244 266#else
05f1c52c 267 while ((c = getopt(argc, argv, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
0e657244 268#endif
9b7292ce 269 {
270
271 switch (c)
272 {
62e76326 273
274 case 'C':
63be0a78 275 /** \par C
276 * Unset/disabel global option for catchign signals. opt_catch_signals */
62e76326 277 opt_catch_signals = 0;
278 break;
279
280 case 'D':
63be0a78 281 /** \par D
282 * Unset/disable global option for optional DNS tests. opt_dns_tests */
62e76326 283 opt_dns_tests = 0;
284 break;
285
286 case 'F':
63be0a78 287 /** \par F
288 * Set global option for foreground rebuild. opt_foreground_rebuild */
62e76326 289 opt_foreground_rebuild = 1;
290 break;
291
292 case 'N':
63be0a78 293 /** \par N
294 * Set global option for 'no_daemon' mode. opt_no_daemon */
62e76326 295 opt_no_daemon = 1;
296 break;
63be0a78 297
0e657244 298#if USE_WIN32_SERVICE
299
300 case 'O':
63be0a78 301 /** \par O
302 * Set global option. opt_command_lin and WIN32_Command_Line */
0e657244 303 opt_command_line = 1;
304 WIN32_Command_Line = xstrdup(optarg);
305 break;
306#endif
62e76326 307
308 case 'R':
63be0a78 309 /** \par R
310 * Unset/disable global option opt_reuseaddr */
62e76326 311 opt_reuseaddr = 0;
312 break;
313
314 case 'S':
63be0a78 315 /** \par S
316 * Set global option opt_store_doublecheck */
62e76326 317 opt_store_doublecheck = 1;
318 break;
319
62e76326 320 case 'X':
63be0a78 321 /** \par X
322 * Force full debugging */
37296f4c 323 Debug::parseOptions("debug_options ALL,9");
324 Config.onoff.debug_override_X = 1;
62e76326 325 sigusr2_handle(SIGUSR2);
62e76326 326 break;
327
328 case 'Y':
63be0a78 329 /** \par Y
330 * Set global option opt_reload_hit_only */
62e76326 331 opt_reload_hit_only = 1;
62e76326 332 break;
333
0e657244 334#if USE_WIN32_SERVICE
335
336 case 'i':
63be0a78 337 /** \par i
338 * Set global option opt_install_service (to TRUE) */
0e657244 339 opt_install_service = TRUE;
0e657244 340 break;
0e657244 341#endif
342
62e76326 343 case 'a':
63be0a78 344 /** \par a
345 * Add optional HTTP port as given following the option */
62e76326 346 add_http_port(optarg);
62e76326 347 break;
348
349 case 'd':
63be0a78 350 /** \par d
351 * Set global option opt_debug_stderr to the number given follwoign the option */
62e76326 352 opt_debug_stderr = atoi(optarg);
62e76326 353 break;
354
355 case 'f':
63be0a78 356 /** \par f
357 * Load the file given instead of the default squid.conf. */
62e76326 358 xfree(ConfigFile);
62e76326 359 ConfigFile = xstrdup(optarg);
62e76326 360 break;
361
362 case 'k':
63be0a78 363 /** \par k
364 * Run the administrative action given following the option */
fc68f6b1 365
63be0a78 366 /** \li When its an unknown option display the usage help. */
62e76326 367 if ((int) strlen(optarg) < 1)
368 usage();
369
370 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
63be0a78 371 /** \li On reconfigure send SIGHUP. */
62e76326 372 opt_send_signal = SIGHUP;
373 else if (!strncmp(optarg, "rotate", strlen(optarg)))
63be0a78 374 /** \li On rotate send SIGQUIT or SIGUSR1. */
7e7a0442 375#ifdef _SQUID_LINUX_THREADS_
62e76326 376
377 opt_send_signal = SIGQUIT;
378
e3175d1f 379#else
62e76326 380
381 opt_send_signal = SIGUSR1;
382
e3175d1f 383#endif
62e76326 384
385 else if (!strncmp(optarg, "debug", strlen(optarg)))
63be0a78 386 /** \li On debug send SIGTRAP or SIGUSR2. */
7e7a0442 387#ifdef _SQUID_LINUX_THREADS_
62e76326 388
389 opt_send_signal = SIGTRAP;
390
e3175d1f 391#else
62e76326 392
393 opt_send_signal = SIGUSR2;
394
395#endif
396
397 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
63be0a78 398 /** \li On shutdown send SIGTERM. */
62e76326 399 opt_send_signal = SIGTERM;
400 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
63be0a78 401 /** \li On interrupt send SIGINT. */
62e76326 402 opt_send_signal = SIGINT;
403 else if (!strncmp(optarg, "kill", strlen(optarg)))
63be0a78 404 /** \li On kill send SIGKILL. */
62e76326 405 opt_send_signal = SIGKILL;
ae1feb30 406
407#ifdef SIGTTIN
408
409 else if (!strncmp(optarg, "restart", strlen(optarg)))
63be0a78 410 /** \li On restart send SIGTTIN. (exit and restart by parent) */
411 opt_send_signal = SIGTTIN;
ae1feb30 412
413#endif
414
62e76326 415 else if (!strncmp(optarg, "check", strlen(optarg)))
63be0a78 416 /** \li On check send 0 / SIGNULL. */
62e76326 417 opt_send_signal = 0; /* SIGNULL */
418 else if (!strncmp(optarg, "parse", strlen(optarg)))
63be0a78 419 /** \li On parse set global flag to re-parse the config file only. */
420 opt_parse_cfg_only = 1;
62e76326 421 else
422 usage();
423
424 break;
425
426 case 'm':
63be0a78 427 /** \par m
428 * Set global malloc_debug_level to the value given following the option.
429 * if none is given it toggles the xmalloc_trace option on/off */
62e76326 430 if (optarg) {
30a4f2a8 431#if MALLOC_DBG
fc68f6b1 432 malloc_debug_level = atoi(optarg);
30a4f2a8 433#else
fc68f6b1 434 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
33ab18e8 435#endif
62e76326 436
437 } else {
33ab18e8 438#if XMALLOC_TRACE
62e76326 439 xmalloc_trace = !xmalloc_trace;
33ab18e8 440#else
62e76326 441 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
30a4f2a8 442#endif
62e76326 443 }
d9e7ee1f 444 break;
d9e7ee1f 445
0e657244 446#if USE_WIN32_SERVICE
447
448 case 'n':
63be0a78 449 /** \par n
450 * Set global option opt_signal_service (to TRUE).
451 * Stores the additional parameter given in global WIN32_Service_name */
0e657244 452 xfree(WIN32_Service_name);
453
454 WIN32_Service_name = xstrdup(optarg);
455
456 opt_signal_service = TRUE;
457
458 break;
459
460 case 'r':
63be0a78 461 /** \par r
462 * Set global option opt_remove_service (to TRUE) */
0e657244 463 opt_remove_service = TRUE;
464
465 break;
466
467#endif
468
5e6d4736 469 case 'l':
63be0a78 470 /** \par l
471 * Stores the syslog facility name in global opt_syslog_facility
472 * then performs actions for -s option. */
5e6d4736 473 opt_syslog_facility = xstrdup(optarg);
474
62e76326 475 case 's':
63be0a78 476 /** \par s
477 * Initialize the syslog for output */
c307aec3 478#if HAVE_SYSLOG
62e76326 479
5e6d4736 480 _db_set_syslog(opt_syslog_facility);
0e657244 481
62e76326 482 break;
0e657244 483
c307aec3 484#else
62e76326 485
486 fatal("Logging to syslog not available on this platform");
0e657244 487
62e76326 488 /* NOTREACHED */
489#endif
490
491 case 'u':
63be0a78 492 /** \par u
493 * Store the ICP port number given in global option icpPortNumOverride
494 * ensuring its a positive number. */
62e76326 495 icpPortNumOverride = atoi(optarg);
496
497 if (icpPortNumOverride < 0)
498 icpPortNumOverride = 0;
499
500 break;
501
502 case 'v':
63be0a78 503 /** \par v
504 * Display squid version and build information. Then exit. */
62e76326 505 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
506
1a774556 507#if USE_WIN32_SERVICE
508
509 printf("Compiled as Windows System Service.\n");
510
511#endif
512
62e76326 513 exit(0);
514
515 /* NOTREACHED */
516
517 case 'z':
63be0a78 518 /** \par z
519 * Set global option opt_debug_stderr and opt_create_swap_dirs */
930dea4a 520 opt_debug_stderr = 1;
521
62e76326 522 opt_create_swap_dirs = 1;
523
524 break;
525
63be0a78 526 case 'h':
527
62e76326 528 case '?':
529
530 default:
63be0a78 531 /** \par h,?, or unknown
532 * \copydoc usage() */
62e76326 533 usage();
534
535 break;
536 }
9b7292ce 537
090089c4 538 }
4d64d74a 539}
090089c4 540
7a2f978b 541/* ARGSUSED */
b293c4d8 542void
9b7292ce 543rotate_logs(int sig)
544{
5cd39a10 545 do_rotate = 1;
a50bfe93 546#ifndef _SQUID_MSWIN_
30a4f2a8 547#if !HAVE_SIGACTION
62e76326 548
30a4f2a8 549 signal(sig, rotate_logs);
550#endif
a50bfe93 551#endif
30a4f2a8 552}
553
7a2f978b 554/* ARGSUSED */
b293c4d8 555void
9b7292ce 556reconfigure(int sig)
557{
5cd39a10 558 do_reconfigure = 1;
a50bfe93 559#ifndef _SQUID_MSWIN_
30a4f2a8 560#if !HAVE_SIGACTION
62e76326 561
30a4f2a8 562 signal(sig, reconfigure);
563#endif
a50bfe93 564#endif
30a4f2a8 565}
566
b8d8561b 567void
9b7292ce 568shut_down(int sig)
569{
2681d383 570 do_shutdown = sig == SIGINT ? -1 : 1;
ae1feb30 571#ifdef SIGTTIN
572
573 if (SIGTTIN == sig)
574 shutdown_status = 1;
575
576#endif
a50bfe93 577#ifndef _SQUID_MSWIN_
cadc2d55 578#ifdef KILL_PARENT_OPT
62e76326 579
5cd39a10 580 if (getppid() > 1) {
36584579 581 debugs(1, 1, "Killing RunCache, pid " << getppid());
62e76326 582
583 if (kill(getppid(), sig) < 0)
36584579 584 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
88738790 585 }
62e76326 586
cadc2d55 587#endif
6e40f263 588#if SA_RESETHAND == 0
589 signal(SIGTERM, SIG_DFL);
62e76326 590
6e40f263 591 signal(SIGINT, SIG_DFL);
62e76326 592
a50bfe93 593#endif
6e40f263 594#endif
30a4f2a8 595}
596
24382924 597static void
9b7292ce 598serverConnectionsOpen(void)
599{
d193a436 600 clientOpenListenSockets();
15df8349 601 icpConnectionsOpen();
ace287ee 602#if USE_HTCP
62e76326 603
ace287ee 604 htcpInit();
605#endif
678c6099 606#ifdef SQUID_SNMP
62e76326 607
3265e68d 608 snmpConnectionOpen();
320e9f36 609#endif
eb824054 610#if USE_WCCP
62e76326 611
320e9f36 612 wccpConnectionOpen();
2bbd722b 613#endif
62e76326 614
0b0cfcf2 615#if USE_WCCPv2
616
617 wccp2ConnectionOpen();
618#endif
619
5ecceaa4 620 clientdbInit();
cc192b50 621 icmpEngine.Open();
67508012 622 netdbInit();
f899fac1 623 asnInit();
b0dd28ba 624 ACL::Initialize();
85034133 625 peerSelectInit();
62e76326 626
afd88fbe 627 carpInit();
f7e1d9ce
HN
628 peerUserHashInit();
629 peerSourceHashInit();
5f3f8d0e 630}
631
b8d8561b 632void
9b7292ce 633serverConnectionsClose(void)
634{
0a5a8601 635 assert(shutting_down || reconfiguring);
c0fbae16 636 clientHttpConnectionsClose();
17e6c0a1 637 icpConnectionShutdown();
72549e05 638#if USE_HTCP
62e76326 639
72549e05 640 htcpSocketShutdown();
641#endif
62e76326 642
cc192b50 643 icmpEngine.Close();
15df8349 644#ifdef SQUID_SNMP
62e76326 645
17e6c0a1 646 snmpConnectionShutdown();
320e9f36 647#endif
eb824054 648#if USE_WCCP
62e76326 649
0b0cfcf2 650 wccpConnectionClose();
651#endif
652#if USE_WCCPv2
653
654 wccp2ConnectionClose();
15df8349 655#endif
62e76326 656
4bac8de8 657 asnFreeMemory();
5f3f8d0e 658}
659
b8d8561b 660static void
9b7292ce 661mainReconfigure(void)
662{
bf8fe701 663 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string << ")...");
5cd39a10 664 reconfiguring = 1;
0ffd22bc 665 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
15df8349 666 serverConnectionsClose();
17e6c0a1 667 icpConnectionClose();
72549e05 668#if USE_HTCP
62e76326 669
72549e05 670 htcpSocketClose();
671#endif
17e6c0a1 672#ifdef SQUID_SNMP
62e76326 673
17e6c0a1 674 snmpConnectionClose();
320e9f36 675#endif
3c573763 676#if USE_DNSSERVERS
62e76326 677
74addf6c 678 dnsShutdown();
3c573763 679#else
62e76326 680
7b724b86 681 idnsShutdown();
eb824054 682#endif
62e76326 683
74addf6c 684 redirectShutdown();
685 authenticateShutdown();
d9572179 686 externalAclShutdown();
2db68ce5 687 storeDirCloseSwapLogs();
2e923080 688 storeLogClose();
689 accessLogClose();
690 useragentLogClose();
691 refererCloseLog();
c68e9c6b 692 errorClean();
3aa4adbc 693 enter_suid(); /* root to read config file */
dd9b1081 694 parseConfigFile(ConfigFile);
c642c141 695 setUmask(Config.umask);
97244680 696 Mem::Report();
3aa4adbc 697 setEffectiveUser();
b6f794d6 698 _db_init(Config.Log.log, Config.debugOptions);
429fdbec 699 ipcache_restart(); /* clear stuck entries */
94439e4e 700 authenticateUserCacheRestart(); /* clear stuck ACL entries */
429fdbec 701 fqdncache_restart(); /* sigh, fqdncache too */
0e70aa1e 702 parseEtcHosts();
53ad48e6 703 errorInitialize(); /* reload error pages */
2e923080 704 accessLogInit();
705 storeLogOpen();
706 useragentOpenLog();
707 refererOpenLog();
3c573763 708#if USE_DNSSERVERS
62e76326 709
74addf6c 710 dnsInit();
3c573763 711#else
62e76326 712
7b724b86 713 idnsInit();
eb824054 714#endif
62e76326 715
74addf6c 716 redirectInit();
e6ccf245 717 authenticateInit(&Config.authConfiguration);
d9572179 718 externalAclInit();
1f38f50a 719#if USE_WCCP
62e76326 720
1f38f50a 721 wccpInit();
722#endif
0b0cfcf2 723#if USE_WCCPv2
724
725 wccp2Init();
726#endif
62e76326 727
0ffd22bc 728 serverConnectionsOpen();
9c2e9b50 729
3ee2b4f8 730 neighbors_init();
9c2e9b50 731
2db68ce5 732 storeDirOpenSwapLogs();
9c2e9b50 733
9c021a38 734 mimeInit(Config.mimeTablePathname);
9c2e9b50 735
926375e6 736 if (Config.onoff.announce) {
737 if (!eventFind(start_announce, NULL))
738 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
739 } else {
740 if (eventFind(start_announce, NULL))
741 eventDelete(start_announce, NULL);
742 }
743
b8890359 744 writePidFile(); /* write PID file */
9c2e9b50 745
bf8fe701 746 debugs(1, 1, "Ready to serve requests.");
9c2e9b50 747
5cd39a10 748 reconfiguring = 0;
749}
750
751static void
9b7292ce 752mainRotate(void)
753{
cc192b50 754 icmpEngine.Close();
3c573763 755#if USE_DNSSERVERS
62e76326 756
e40aa8da 757 dnsShutdown();
3c573763 758#endif
62e76326 759
e40aa8da 760 redirectShutdown();
761 authenticateShutdown();
d9572179 762 externalAclShutdown();
5cd39a10 763 _db_rotate_log(); /* cache.log */
764 storeDirWriteCleanLogs(1);
765 storeLogRotate(); /* store.log */
766 accessLogRotate(); /* access.log */
767 useragentRotateLog(); /* useragent.log */
fd2c5549 768 refererRotateLog(); /* referer.log */
225644d7 769#if WIP_FWD_LOG
62e76326 770
225644d7 771 fwdLogRotate();
772#endif
62e76326 773
cc192b50 774 icmpEngine.Open();
3c573763 775#if USE_DNSSERVERS
62e76326 776
e40aa8da 777 dnsInit();
3c573763 778#endif
62e76326 779
e40aa8da 780 redirectInit();
e6ccf245 781 authenticateInit(&Config.authConfiguration);
d9572179 782 externalAclInit();
5f3f8d0e 783}
784
067bea91 785static void
9b7292ce 786setEffectiveUser(void)
787{
fc68f6b1 788 keepCapabilities();
85407535 789 leave_suid(); /* Run as non privilegied user */
cd377065 790#ifdef _SQUID_OS2_
62e76326 791
cd377065 792 return;
793#endif
62e76326 794
85407535 795 if (geteuid() == 0) {
bf8fe701 796 debugs(0, 0, "Squid is not safe to run as root! If you must");
797 debugs(0, 0, "start Squid as root, then you must configure");
798 debugs(0, 0, "it to run as a non-priveledged user with the");
799 debugs(0, 0, "'cache_effective_user' option in the config file.");
62e76326 800 fatal("Don't run Squid as root, set 'cache_effective_user'!");
85407535 801 }
802}
803
b6a2f15e 804static void
9b7292ce 805mainSetCwd(void)
806{
4a504376 807 char pathbuf[MAXPATHLEN];
62e76326 808
b6a2f15e 809 if (Config.coredump_dir) {
62e76326 810 if (0 == strcmp("none", Config.coredump_dir)) {
811 (void) 0;
812 } else if (chdir(Config.coredump_dir) == 0) {
bf8fe701 813 debugs(0, 1, "Set Current Directory to " << Config.coredump_dir);
62e76326 814 return;
815 } else {
bf8fe701 816 debugs(50, 0, "chdir: " << Config.coredump_dir << ": " << xstrerror());
62e76326 817 }
b6a2f15e 818 }
62e76326 819
02e8115e 820 /* If we don't have coredump_dir or couldn't cd there, report current dir */
4a504376 821 if (getcwd(pathbuf, MAXPATHLEN)) {
bf8fe701 822 debugs(0, 1, "Current Directory is " << pathbuf);
4a504376 823 } else {
bf8fe701 824 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
4a504376 825 }
b6a2f15e 826}
827
b67e2c8c 828#if DELAY_POOLS
829#include "DelayPools.h"
830#endif
831
b8d8561b 832static void
9b7292ce 833mainInitialize(void)
834{
efd900cb 835 /* chroot if configured to run inside chroot */
62e76326 836
64b0a10d 837 if (Config.chroot_dir && (chroot(Config.chroot_dir) != 0 || chdir("/") != 0)) {
62e76326 838 fatal("failed to chroot");
efd900cb 839 }
62e76326 840
1758c627 841 if (opt_catch_signals) {
62e76326 842 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
843 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
44f99671 844 }
62e76326 845
30a4f2a8 846 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
847 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
44f99671 848
85407535 849 setEffectiveUser();
62e76326 850
30a4f2a8 851 if (icpPortNumOverride != 1)
62e76326 852 Config.Port.icp = (u_short) icpPortNumOverride;
30a4f2a8 853
b6f794d6 854 _db_init(Config.Log.log, Config.debugOptions);
62e76326 855
5c5783a2 856 fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
62e76326 857
71a17702 858#if MEM_GEN_TRACE
62e76326 859
71a17702 860 log_trace_init("/tmp/squid.alloc");
62e76326 861
71a17702 862#endif
62e76326 863
bf8fe701 864 debugs(1, 0, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
62e76326 865
ec4daaa5 866#ifdef _SQUID_WIN32_
b293c4d8 867
868 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
bf8fe701 869 debugs(1, 0, "Running as " << WIN32_Service_name << " Windows System Service on " << WIN32_OS_string);
870 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line);
b293c4d8 871 } else
bf8fe701 872 debugs(1, 0, "Running on " << WIN32_OS_string);
b293c4d8 873
874#endif
875
36584579 876 debugs(1, 1, "Process ID " << getpid());
62e76326 877
bf8fe701 878 debugs(1, 1, "With " << Squid_MaxFD << " file descriptors available");
5f3f8d0e 879
6c1962dd 880#ifdef _SQUID_MSWIN_
881
bf8fe701 882 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
6c1962dd 883
884 if (WIN32_Socks_initialized)
bf8fe701 885 debugs(1, 1, "Windows sockets initialized");
6c1962dd 886
babd1fd5 887 if (WIN32_OS_version > _WIN_OS_WINNT) {
888 WIN32_IpAddrChangeMonitorInit();
889 }
890
6c1962dd 891#endif
892
9f75c559 893 if (!configured_once)
62e76326 894 disk_init(); /* disk_init must go before ipcache_init() */
895
5f3f8d0e 896 ipcache_init();
62e76326 897
f88bb09c 898 fqdncache_init();
62e76326 899
0e70aa1e 900 parseEtcHosts();
62e76326 901
3c573763 902#if USE_DNSSERVERS
62e76326 903
74addf6c 904 dnsInit();
62e76326 905
3c573763 906#else
62e76326 907
7b724b86 908 idnsInit();
62e76326 909
eb824054 910#endif
62e76326 911
74addf6c 912 redirectInit();
62e76326 913
e6ccf245 914 authenticateInit(&Config.authConfiguration);
62e76326 915
d9572179 916 externalAclInit();
62e76326 917
b012353a 918 useragentOpenLog();
62e76326 919
fd2c5549 920 refererOpenLog();
62e76326 921
2ac76861 922 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
62e76326 923
2246b732 924 httpReplyInitModule(); /* must go before accepting replies */
62e76326 925
9b312a19 926 errorInitialize();
62e76326 927
7a2f978b 928 accessLogInit();
62e76326 929
3898f57f 930#if USE_IDENT
62e76326 931
05832ae1 932 identInit();
62e76326 933
3898f57f 934#endif
5e14bf6d 935#ifdef SQUID_SNMP
62e76326 936
5e14bf6d 937 snmpInit();
62e76326 938
5e14bf6d 939#endif
30a4f2a8 940#if MALLOC_DBG
62e76326 941
5f3f8d0e 942 malloc_debug(0, malloc_debug_level);
62e76326 943
5f3f8d0e 944#endif
945
dbe4fd8e 946 if (!configured_once) {
a3d0a19d 947#if USE_UNLINKD
62e76326 948 unlinkdInit();
949#endif
950
951 urlInitialize();
62e76326 952 statInit();
953 storeInit();
954 mainSetCwd();
955 /* after this point we want to see the mallinfo() output */
956 do_mallinfo = 1;
957 mimeInit(Config.mimeTablePathname);
62e76326 958 refreshInit();
0d7e5d78 959#if DELAY_POOLS
62e76326 960
961 DelayPools::Init();
0d7e5d78 962#endif
62e76326 963
b6b6f466 964 FwdState::initModule();
62ee09ca 965 /* register the modules in the cache manager menus */
62ee09ca 966
a08f1b5a 967 cbdataRegisterWithCacheManager();
62ee09ca 968 /* These use separate calls so that the comm loops can eventually
969 * coexist.
970 */
62ee09ca 971
15b3c0d7 972 eventInit();
6b7d87bb 973
6852be71
FC
974 // TODO: pconn is a good candidate for new-style registration
975 // PconnModule::GetInstance()->registerWithCacheManager();
976 // moved to PconnModule::PconnModule()
5f3f8d0e 977 }
62e76326 978
1f38f50a 979#if USE_WCCP
980 wccpInit();
62e76326 981
0b0cfcf2 982#endif
983#if USE_WCCPv2
984
985 wccp2Init();
986
1f38f50a 987#endif
62e76326 988
2285407f 989 serverConnectionsOpen();
62e76326 990
3ee2b4f8 991 neighbors_init();
fc68f6b1 992
5f5e883f 993 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
62e76326 994
efd900cb 995 if (Config.chroot_dir)
62e76326 996 no_suid();
997
dbe4fd8e 998 if (!configured_once)
62e76326 999 writePidFile(); /* write PID file */
0a5b9b32 1000
7e7a0442 1001#ifdef _SQUID_LINUX_THREADS_
62e76326 1002
e3175d1f 1003 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
62e76326 1004
e3175d1f 1005 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
62e76326 1006
e3175d1f 1007#else
62e76326 1008
30a4f2a8 1009 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
62e76326 1010
30a4f2a8 1011 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
62e76326 1012
9fc0b4b8 1013#endif
62e76326 1014
30a4f2a8 1015 squid_signal(SIGHUP, reconfigure, SA_RESTART);
62e76326 1016
30a4f2a8 1017 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1018
30a4f2a8 1019 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1020
ae1feb30 1021#ifdef SIGTTIN
1022
1023 squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
1024
1025#endif
1026
58a39dc9 1027 memCheckInit();
62e76326 1028
57afc994
AR
1029#if USE_LOADABLE_MODULES
1030 LoadableModulesConfigure(Config.loadable_module_names);
1031#endif
1032
8f361c50
AR
1033#if USE_ADAPTATION
1034 bool enableAdaptation = false;
1035
1036 // We can remove this dependency on specific adaptation mechanisms
1037 // if we create a generic Registry of such mechanisms. Should we?
b958cb0f
AR
1038#if ICAP_CLIENT
1039 TheICAPConfig.finalize(); // must be after we load modules
8f361c50 1040 enableAdaptation = TheICAPConfig.onoff;
b958cb0f 1041#endif
8f361c50
AR
1042 // same for eCAP
1043
1044 // must be the last adaptation-related finalize
1045 Adaptation::Config::Finalize(enableAdaptation);
b958cb0f
AR
1046#endif
1047
1048
bf8fe701 1049 debugs(1, 1, "Ready to serve requests.");
62e76326 1050
dbe4fd8e 1051 if (!configured_once) {
c8f4eac4 1052 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
62e76326 1053
1054 if (Config.onoff.announce)
1055 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
1056
1057 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
1058
1059 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
1060
88bfe092 1061#if USE_XPROF_STATS
62e76326 1062
1063 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
1064
88bfe092 1065#endif
62e76326 1066
1067 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
f900210a 1068
1069 eventAdd("commCheckHalfClosed", commCheckHalfClosed, NULL, 1.0, false);
4d7add01 1070 }
62e76326 1071
dbe4fd8e 1072 configured_once = 1;
4d64d74a 1073}
1074
6c1962dd 1075#if USE_WIN32_SERVICE
1076/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1077extern "C" void WINAPI
a0aa9e74 1078 SquidWinSvcMain(int argc, char **argv)
1079{
1080 SquidMain(argc, argv);
1081}
1082
1083int
1084SquidMain(int argc, char **argv)
6c1962dd 1085#else
b8d8561b 1086int
1087main(int argc, char **argv)
9b7292ce 1088#endif
1089{
a0aa9e74 1090#ifdef _SQUID_WIN32_
1091
1092 int WIN32_init_err;
1093#endif
4d64d74a 1094
a4ba1105 1095#if HAVE_SBRK
62e76326 1096
9b7292ce 1097 sbrk_start = sbrk(0);
a4ba1105 1098#endif
1099
fb6a61d1 1100 Debug::parseOptions(NULL);
9b7292ce 1101 debug_log = stderr;
62e76326 1102
b9269882 1103#if defined(SQUID_MAXFD_LIMIT)
1104
1105 if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
1106 Squid_MaxFD = SQUID_MAXFD_LIMIT;
1107
1108#endif
399e85ea 1109
ec4daaa5 1110#ifdef _SQUID_WIN32_
6c1962dd 1111
a0aa9e74 1112 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
1113 return WIN32_init_err;
62e76326 1114
0e6d05ef 1115#endif
1116
9b7292ce 1117 /* call mallopt() before anything else */
0b29fe44 1118#if HAVE_MALLOPT
7328e889 1119#ifdef M_GRAIN
9b7292ce 1120 /* Round up all sizes to a multiple of this */
1121 mallopt(M_GRAIN, 16);
62e76326 1122
7328e889 1123#endif
1124#ifdef M_MXFAST
9b7292ce 1125 /* biggest size that is considered a small block */
1126 mallopt(M_MXFAST, 256);
62e76326 1127
7328e889 1128#endif
1129#ifdef M_NBLKS
9b7292ce 1130 /* allocate this many small blocks at once */
1131 mallopt(M_NLBLKS, 32);
62e76326 1132
7328e889 1133#endif
1134#endif /* HAVE_MALLOPT */
1135
9b7292ce 1136 squid_srandom(time(NULL));
4d64d74a 1137
9b7292ce 1138 getCurrentTime();
62e76326 1139
9b7292ce 1140 squid_start = current_time;
62e76326 1141
9b7292ce 1142 failure_notify = fatal_dump;
4d64d74a 1143
6c1962dd 1144#if USE_WIN32_SERVICE
1145
9b7292ce 1146 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1147
1148#endif
1149
9b7292ce 1150 mainParseOptions(argc, argv);
4d64d74a 1151
9aae6be3 1152 if (opt_parse_cfg_only) {
1153 Debug::parseOptions("ALL,1");
1154 }
1155
6c1962dd 1156#if USE_WIN32_SERVICE
1157
a0aa9e74 1158 if (opt_install_service)
1159 {
9b7292ce 1160 WIN32_InstallService();
a0aa9e74 1161 return 0;
9b7292ce 1162 }
6c1962dd 1163
a0aa9e74 1164 if (opt_remove_service)
1165 {
9b7292ce 1166 WIN32_RemoveService();
a0aa9e74 1167 return 0;
9b7292ce 1168 }
6c1962dd 1169
a0aa9e74 1170 if (opt_command_line)
1171 {
9b7292ce 1172 WIN32_SetServiceCommandLine();
a0aa9e74 1173 return 0;
9b7292ce 1174 }
6c1962dd 1175
1176#endif
1177
9b7292ce 1178 /* parse configuration file
1179 * note: in "normal" case this used to be called from mainInitialize() */
1180 {
1181 int parse_err;
62e76326 1182
9b7292ce 1183 if (!ConfigFile)
1184 ConfigFile = xstrdup(DefaultConfigFile);
62e76326 1185
9b7292ce 1186 assert(!configured_once);
62e76326 1187
9b7292ce 1188 Mem::Init();
62e76326 1189
9b7292ce 1190 storeFsInit(); /* required for config parsing */
62e76326 1191
b9ae18aa 1192 /* May not be needed for parsing, have not audited for such */
1193 DiskIOModule::SetupAllModules();
1194
59b2d47f 1195 /* Shouldn't be needed for config parsing, but have not audited for such */
1196 StoreFileSystem::SetupAllFs();
1197
c8f4eac4 1198 /* we may want the parsing process to set this up in the future */
1199 Store::Root(new StoreController);
1200
dd9b1081 1201 parse_err = parseConfigFile(ConfigFile);
62e76326 1202
97244680 1203 Mem::Report();
1204
9b7292ce 1205 if (opt_parse_cfg_only)
6c1962dd 1206
9b7292ce 1207 return parse_err;
9b7292ce 1208 }
c642c141 1209 setUmask(Config.umask);
9b7292ce 1210 if (-1 == opt_send_signal)
1211 if (checkRunningPid())
1212 exit(1);
e13ee7ad 1213
9bc73deb 1214#if TEST_ACCESS
62e76326 1215
95564b0d 1216 comm_init();
62e76326 1217
9b7292ce 1218 comm_select_init();
62e76326 1219
9b7292ce 1220 mainInitialize();
62e76326 1221
9b7292ce 1222 test_access();
62e76326 1223
9b7292ce 1224 return 0;
62e76326 1225
9bc73deb 1226#endif
1227
9b7292ce 1228 /* send signal to running copy and exit */
a0aa9e74 1229 if (opt_send_signal != -1)
1230 {
9b7292ce 1231 /* chroot if configured to run inside chroot */
62e76326 1232
a572d8be 1233 if (Config.chroot_dir) {
1234 if (chroot(Config.chroot_dir))
1235 fatal("failed to chroot");
1236
1237 no_suid();
1238 } else {
1239 leave_suid();
9b7292ce 1240 }
62e76326 1241
9b7292ce 1242 sendSignal();
1243 /* NOTREACHED */
1244 }
62e76326 1245
a0aa9e74 1246 if (opt_create_swap_dirs)
1247 {
9b7292ce 1248 /* chroot if configured to run inside chroot */
0e657244 1249
9b7292ce 1250 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1251 fatal("failed to chroot");
1252 }
62e76326 1253
9b7292ce 1254 setEffectiveUser();
bf8fe701 1255 debugs(0, 0, "Creating Swap Directories");
c8f4eac4 1256 Store::Root().create();
6c1962dd 1257
9b7292ce 1258 return 0;
9b7292ce 1259 }
62e76326 1260
9b7292ce 1261 if (!opt_no_daemon)
1262 watch_child(argv);
62e76326 1263
95564b0d 1264 setMaxFD();
1265
1266 /* init comm module */
1267 comm_init();
62e76326 1268
9b7292ce 1269 comm_select_init();
4d64d74a 1270
a0aa9e74 1271 if (opt_no_daemon)
1272 {
9b7292ce 1273 /* we have to init fdstat here. */
1274 fd_open(0, FD_LOG, "stdin");
1275 fd_open(1, FD_LOG, "stdout");
1276 fd_open(2, FD_LOG, "stderr");
1277 }
62e76326 1278
6c1962dd 1279#if USE_WIN32_SERVICE
1280
9b7292ce 1281 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1282
1283#endif
1284
9b7292ce 1285 mainInitialize();
4d64d74a 1286
6c1962dd 1287#if USE_WIN32_SERVICE
1288
9b7292ce 1289 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
6c1962dd 1290
1291#endif
1292
9b7292ce 1293 /* main loop */
a553a5a3 1294 EventLoop mainLoop;
62e76326 1295
9688b0ae 1296 SignalEngine signalEngine(mainLoop);
6c1962dd 1297
9688b0ae 1298 mainLoop.registerEngine(&signalEngine);
62e76326 1299
8ff3fa2e 1300 /* TODO: stop requiring the singleton here */
1301 mainLoop.registerEngine(EventScheduler::GetInstance());
62e76326 1302
8ff3fa2e 1303 StoreRootEngine store_engine;
615f9581 1304
8ff3fa2e 1305 mainLoop.registerEngine(&store_engine);
a774fd3f 1306
8ff3fa2e 1307 CommSelectEngine comm_engine;
1308
8ff3fa2e 1309 mainLoop.registerEngine(&comm_engine);
1310
bef81ea5 1311 mainLoop.setPrimaryEngine(&comm_engine);
1312
8ff3fa2e 1313 /* use the standard time service */
1314 TimeEngine time_engine;
1315
1316 mainLoop.setTimeService(&time_engine);
1317
1318 mainLoop.run();
1319
1320 if (mainLoop.errcount == 10)
1321 fatal_dump("Event loop exited with failure.");
1322
1323 /* shutdown squid now */
1324 SquidShutdown();
62e76326 1325
9b7292ce 1326 /* NOTREACHED */
9b7292ce 1327 return 0;
090089c4 1328}
7690e8eb 1329
b8d8561b 1330static void
0673c0ba 1331sendSignal(void)
7690e8eb 1332{
ff8d0ea6 1333 pid_t pid;
fedac7e5 1334 debug_log = stderr;
258ac4d7 1335
1336 if (strcmp(Config.pidFilename, "none") == 0) {
bf8fe701 1337 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
258ac4d7 1338 }
1339
fedac7e5 1340 pid = readPidFile();
62e76326 1341
fedac7e5 1342 if (pid > 1) {
6c1962dd 1343#if USE_WIN32_SERVICE
1344
1345 if (opt_signal_service) {
1346 WIN32_sendSignal(opt_send_signal);
1347 exit(0);
1348 } else
1349#ifdef _SQUID_MSWIN_
1350 {
7dbca7a4 1351 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
6c1962dd 1352 fprintf(stderr, "signal to Squid Service:\n");
1353 fprintf(stderr, "missing -n command line switch.\n");
1354 exit(1);
1355 }
1356
1357 /* NOTREACHED */
1358#endif
1359
1360#endif
1361
62e76326 1362 if (kill(pid, opt_send_signal) &&
1363 /* ignore permissions if just running check */
1364 !(opt_send_signal == 0 && errno == EPERM)) {
7dbca7a4 1365 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
62e76326 1366 fprintf(stderr, "signal %d to process %d: %s\n",
1367 opt_send_signal, (int) pid, xstrerror());
1368 exit(1);
1369 }
fedac7e5 1370 } else {
7dbca7a4 1371 fprintf(stderr, "%s: ERROR: No running copy\n", APP_SHORTNAME);
62e76326 1372 exit(1);
7690e8eb 1373 }
62e76326 1374
fedac7e5 1375 /* signal successfully sent */
1376 exit(0);
1377}
f95b8144 1378
a50bfe93 1379#ifndef _SQUID_MSWIN_
e18d7fdc 1380/*
1381 * This function is run when Squid is in daemon mode, just
1382 * before the parent forks and starts up the child process.
1383 * It can be used for admin-specific tasks, such as notifying
1384 * someone that Squid is (re)started.
1385 */
1386static void
1387mainStartScript(const char *prog)
1388{
1389 char script[SQUID_MAXPATHLEN];
1390 char *t;
1391 size_t sl = 0;
1392 pid_t cpid;
1393 pid_t rpid;
1394 xstrncpy(script, prog, MAXPATHLEN);
62e76326 1395
e18d7fdc 1396 if ((t = strrchr(script, '/'))) {
62e76326 1397 *(++t) = '\0';
1398 sl = strlen(script);
e18d7fdc 1399 }
62e76326 1400
e18d7fdc 1401 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
62e76326 1402
e18d7fdc 1403 if ((cpid = fork()) == 0) {
62e76326 1404 /* child */
f75662c9 1405 execl(script, squid_start_script, (char *)NULL);
482aa790 1406 _exit(-1);
e18d7fdc 1407 } else {
62e76326 1408 do {
e18d7fdc 1409#ifdef _SQUID_NEXT_
62e76326 1410 union wait status;
1411 rpid = wait3(&status, 0, NULL);
e18d7fdc 1412#else
62e76326 1413
1414 int status;
1415 rpid = waitpid(-1, &status, 0);
e18d7fdc 1416#endif
62e76326 1417
1418 } while (rpid != cpid);
e18d7fdc 1419 }
1420}
1421
a50bfe93 1422#endif /* _SQUID_MSWIN_ */
1423
efd900cb 1424static int
1425checkRunningPid(void)
1426{
1427 pid_t pid;
e0077312 1428
1429 if (!debug_log)
1430 debug_log = stderr;
1431
efd900cb 1432 pid = readPidFile();
62e76326 1433
efd900cb 1434 if (pid < 2)
62e76326 1435 return 0;
1436
efd900cb 1437 if (kill(pid, 0) < 0)
62e76326 1438 return 0;
1439
cb7a4fcb 1440 debugs(0, 0, "Squid is already running! Process ID " << pid);
62e76326 1441
efd900cb 1442 return 1;
1443}
1444
f95b8144 1445static void
bbe199dc 1446watch_child(char *argv[])
f95b8144 1447{
a50bfe93 1448#ifndef _SQUID_MSWIN_
f95b8144 1449 char *prog;
f95b8144 1450 int failcount = 0;
1451 time_t start;
1452 time_t stop;
1453#ifdef _SQUID_NEXT_
62e76326 1454
f95b8144 1455 union wait status;
1456#else
62e76326 1457
f95b8144 1458 int status;
1459#endif
62e76326 1460
e3a3b845 1461 pid_t pid;
c99c5397 1462#ifdef TIOCNOTTY
1463
54f742e7 1464 int i;
c99c5397 1465#endif
1466
742724a4 1467 int nullfd;
62e76326 1468
f95b8144 1469 if (*(argv[0]) == '(')
62e76326 1470 return;
1471
7dbca7a4 1472 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1473
54f742e7 1474 if ((pid = fork()) < 0)
62e76326 1475 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
54f742e7 1476 else if (pid > 0)
62e76326 1477 exit(0);
1478
54f742e7 1479 if (setsid() < 0)
62e76326 1480 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1481
efd900cb 1482 closelog();
62e76326 1483
54f742e7 1484#ifdef TIOCNOTTY
62e76326 1485
c4aefe96 1486 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
62e76326 1487 ioctl(i, TIOCNOTTY, NULL);
1488 close(i);
54f742e7 1489 }
62e76326 1490
54f742e7 1491#endif
b05490a8 1492
7f6ffd15 1493 /*
1494 * RBCOLLINS - if cygwin stackdumps when squid is run without
1495 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1496 * 1.1.3. execvp had a bit overflow error in a loop..
1497 */
742724a4 1498 /* Connect stdio to /dev/null in daemon mode */
4da086c4 1499 nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
62e76326 1500
e4a1325e 1501 if (nullfd < 0)
4da086c4 1502 fatalf(_PATH_DEVNULL " %s\n", xstrerror());
e4a1325e 1503
742724a4 1504 dup2(nullfd, 0);
62e76326 1505
742724a4 1506 if (opt_debug_stderr < 0) {
62e76326 1507 dup2(nullfd, 1);
1508 dup2(nullfd, 2);
742724a4 1509 }
62e76326 1510
f95b8144 1511 for (;;) {
62e76326 1512 mainStartScript(argv[0]);
1513
1514 if ((pid = fork()) == 0) {
1515 /* child */
7dbca7a4 1516 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1517 prog = xstrdup(argv[0]);
1518 argv[0] = xstrdup("(squid)");
1519 execvp(prog, argv);
1520 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1521 }
1522
1523 /* parent */
7dbca7a4 1524 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1525
1526 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
1527
1528 time(&start);
1529
1530 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1531
f95b8144 1532#ifdef _SQUID_NEXT_
62e76326 1533
1534 pid = wait3(&status, 0, NULL);
1535
f95b8144 1536#else
62e76326 1537
1538 pid = waitpid(-1, &status, 0);
1539
1540#endif
1541
1542 time(&stop);
1543
1544 if (WIFEXITED(status)) {
1545 syslog(LOG_NOTICE,
1546 "Squid Parent: child process %d exited with status %d",
1547 pid, WEXITSTATUS(status));
1548 } else if (WIFSIGNALED(status)) {
1549 syslog(LOG_NOTICE,
cc192b50 1550 "Squid Parent: child process %d exited due to signal %d with status %d",
1551 pid, WTERMSIG(status), WEXITSTATUS(status));
62e76326 1552 } else {
1553 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
1554 }
1555
1556 if (stop - start < 10)
1557 failcount++;
1558 else
1559 failcount = 0;
1560
1561 if (failcount == 5) {
1562 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1563 exit(1);
1564 }
1565
1566 if (WIFEXITED(status))
1567 if (WEXITSTATUS(status) == 0)
1568 exit(0);
1569
1570 if (WIFSIGNALED(status)) {
1571 switch (WTERMSIG(status)) {
1572
1573 case SIGKILL:
1574 exit(0);
1575 break;
1576
06a0fbd3 1577 case SIGINT:
1578 case SIGTERM:
1579 syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
1580 exit(1);
1581 break;
1582
62e76326 1583 default:
1584 break;
1585 }
1586 }
1587
1588 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1589 sleep(3);
f95b8144 1590 }
62e76326 1591
bbe199dc 1592 /* NOTREACHED */
a50bfe93 1593#endif /* _SQUID_MSWIN_ */
a572d8be 1594
f95b8144 1595}
fff6ad65 1596
9ec1a1dc 1597static void
8ff3fa2e 1598SquidShutdown()
fff6ad65 1599{
6c1962dd 1600#if USE_WIN32_SERVICE
1601 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1602#endif
1603
bf8fe701 1604 debugs(1, 1, "Shutting down...");
95a83c22 1605#if USE_DNSSERVERS
1606
1607 dnsShutdown();
1608#else
1609
1610 idnsShutdown();
1611#endif
1612
1613 redirectShutdown();
1614 externalAclShutdown();
d723bf6b 1615 icpConnectionClose();
1616#if USE_HTCP
62e76326 1617
d723bf6b 1618 htcpSocketClose();
1619#endif
1620#ifdef SQUID_SNMP
62e76326 1621
d723bf6b 1622 snmpConnectionClose();
320e9f36 1623#endif
eb824054 1624#if USE_WCCP
62e76326 1625
320e9f36 1626 wccpConnectionClose();
d723bf6b 1627#endif
0b0cfcf2 1628#if USE_WCCPv2
1629
1630 wccp2ConnectionClose();
1631#endif
62e76326 1632
fff6ad65 1633 releaseServerSockets();
d723bf6b 1634 commCloseAllSockets();
515ec4dc 1635#if DELAY_POOLS
62e76326 1636
b67e2c8c 1637 DelayPools::FreePools();
515ec4dc 1638#endif
62e76326 1639
5dae8514 1640 authenticateShutdown();
6c1962dd 1641#if USE_WIN32_SERVICE
1642
1643 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1644#endif
62e76326 1645
c8f4eac4 1646 Store::Root().sync(); /* Flush pending object writes/unlinks */
4d075ba0 1647#if USE_UNLINKD
1648
1649 unlinkdClose(); /* after sync/flush */
1650#endif
fc68f6b1 1651
fff6ad65 1652 storeDirWriteCleanLogs(0);
1653 PrintRusage();
1654 dumpMallocStats();
c8f4eac4 1655 Store::Root().sync(); /* Flush log writes */
fff6ad65 1656 storeLogClose();
1657 accessLogClose();
5b824235 1658 useragentLogClose();
c9b99797 1659 refererCloseLog();
225644d7 1660#if WIP_FWD_LOG
62e76326 1661
225644d7 1662 fwdUninit();
1663#endif
62e76326 1664
c8f4eac4 1665 Store::Root().sync(); /* Flush log close */
59b2d47f 1666 StoreFileSystem::FreeAllFs();
b9ae18aa 1667 DiskIOModule::FreeAllModules();
afec404b 1668#if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
62e76326 1669
fff6ad65 1670 configFreeMemory();
1671 storeFreeMemory();
33ab18e8 1672 /*stmemFreeMemory(); */
fff6ad65 1673 netdbFreeMemory();
1674 ipcacheFreeMemory();
1675 fqdncacheFreeMemory();
1676 asnFreeMemory();
26a369ba 1677 clientdbFreeMemory();
7021844c 1678 httpHeaderCleanModule();
d2db411c 1679 statFreeMemory();
f1fc2a8d 1680 eventFreeMemory();
c68e9c6b 1681 mimeFreeMemory();
1682 errorClean();
fff6ad65 1683#endif
26a369ba 1684#if !XMALLOC_TRACE
62e76326 1685
54f742e7 1686 if (opt_no_daemon) {
62e76326 1687 file_close(0);
1688 file_close(1);
1689 file_close(2);
54f742e7 1690 }
62e76326 1691
33ab18e8 1692#endif
fff6ad65 1693 fdDumpOpen();
62e76326 1694
236d1779 1695 comm_exit();
62e76326 1696
ddb43c58 1697 memClean();
62e76326 1698
33ab18e8 1699#if XMALLOC_TRACE
62e76326 1700
26a369ba 1701 xmalloc_find_leaks();
62e76326 1702
bf8fe701 1703 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total);
62e76326 1704
33ab18e8 1705#endif
36a97e19 1706#if MEM_GEN_TRACE
62e76326 1707
399e85ea 1708 log_trace_done();
62e76326 1709
36a97e19 1710#endif
62e76326 1711
ab50ee9e 1712 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
62e76326 1713 enter_suid();
1714 safeunlink(Config.pidFilename, 0);
1715 leave_suid();
ab50ee9e 1716 }
62e76326 1717
bf8fe701 1718 debugs(1, 1, "Squid Cache (Version " << version_string << "): Exiting normally.");
62e76326 1719
0cfa98cb 1720 /*
1721 * DPW 2006-10-23
1722 * We used to fclose(debug_log) here if it was set, but then
1723 * we forgot to set it to NULL. That caused some coredumps
1724 * because exit() ends up calling a bunch of destructors and
1725 * such. So rather than forcing the debug_log to close, we'll
1726 * leave it open so that those destructors can write some
1727 * debugging if necessary. The file will be closed anyway when
1728 * the process truly exits.
1729 */
62e76326 1730
ae1feb30 1731 exit(shutdown_status);
fff6ad65 1732}
bef81ea5 1733