]> git.ipfire.org Git - thirdparty/squid.git/blame - src/main.cc
Polished comments.
[thirdparty/squid.git] / src / main.cc
CommitLineData
30a4f2a8 1/*
262a0e14 2 * $Id$
30a4f2a8 3 *
b510f3a1 4 * DEBUG: section 01 Startup and Main Loop
30a4f2a8 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.
26ac0430 23 *
30a4f2a8 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.
26ac0430 28 *
30a4f2a8 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"
e0d28505
AJ
37#if USE_ADAPTATION
38#include "adaptation/Config.h"
39#endif
40#if USE_ECAP
41#include "adaptation/ecap/Config.h"
42#endif
3ff65596 43#if ICAP_CLIENT
e0d28505 44#include "adaptation/icap/Config.h"
3ff65596
AR
45#include "adaptation/icap/icap_log.h"
46#endif
2f1431ea 47#if USE_AUTH
3ad63615 48#include "auth/Gadgets.h"
2f1431ea 49#endif
6d57128b 50#include "base/RunnersRegistry.h"
e0d28505 51#include "base/Subscription.h"
3d93a84d 52#include "base/TextException.h"
9a0a18de
AJ
53#if USE_DELAY_POOLS
54#include "ClientDelayConfig.h"
55#endif
d841c88d 56#include "comm.h"
62ee09ca 57#include "ConfigParser.h"
96c2bb61 58#include "CpuAffinity.h"
9a0a18de
AJ
59#if USE_DELAY_POOLS
60#include "DelayPools.h"
61#endif
aa839030 62#include "errorpage.h"
a553a5a3 63#include "event.h"
64#include "EventLoop.h"
62ee09ca 65#include "ExternalACL.h"
1b76e6c1
AJ
66#include "fs/Module.h"
67#include "PeerSelectState.h"
e6ccf245 68#include "Store.h"
69#include "ICP.h"
4daaf3cb 70#include "ident/Ident.h"
528b2c61 71#include "HttpReply.h"
62ee09ca 72#include "pconn.h"
528b2c61 73#include "Mem.h"
3ad63615
AR
74#include "acl/Asn.h"
75#include "acl/Acl.h"
75faaa7a 76#include "htcp.h"
59b2d47f 77#include "StoreFileSystem.h"
b9ae18aa 78#include "DiskIO/DiskIOModule.h"
40daaeb8 79#include "ipc/Kids.h"
10cefb7b 80#include "ipc/Coordinator.h"
81#include "ipc/Strand.h"
055421ee 82#include "ip/tools.h"
985c86bc 83#include "SquidTime.h"
c8f4eac4 84#include "SwapDir.h"
b6b6f466 85#include "forward.h"
d9e7ee1f 86#include "MemPool.h"
9b5c4a9a
AJ
87#include "icmp/IcmpSquid.h"
88#include "icmp/net_db.h"
44a47c6e 89
57afc994
AR
90#if USE_LOADABLE_MODULES
91#include "LoadableModules.h"
92#endif
93
95d2589c
CT
94#if USE_SSL_CRTD
95#include "ssl/helper.h"
96#include "ssl/certificate_db.h"
97#endif
98
99#if USE_SSL
100#include "ssl/context_storage.h"
101#endif
102
b958cb0f 103#if ICAP_CLIENT
26cc52cb 104#include "adaptation/icap/Config.h"
b958cb0f 105#endif
6e5db507 106#if USE_ECAP
1f3c65fc 107#include "adaptation/ecap/Config.h"
6e5db507 108#endif
b958cb0f
AR
109#if USE_ADAPTATION
110#include "adaptation/Config.h"
111#endif
79039294
AR
112#if USE_SQUID_ESI
113#include "esi/Module.h"
114#endif
7b5b7ba8
CT
115#include "fs/Module.h"
116
25f98340
AJ
117#if HAVE_PATHS_H
118#include <paths.h>
119#endif
1a774556 120
25f98340 121#if USE_WIN32_SERVICE
1a774556 122#include "squid_windows.h"
123#include <process.h>
124
125static int opt_install_service = FALSE;
126static int opt_remove_service = FALSE;
127static int opt_signal_service = FALSE;
128static int opt_command_line = FALSE;
129extern void WIN32_svcstatusupdate(DWORD, DWORD);
130void WINAPI WIN32_svcHandler(DWORD);
131
132#endif
133
1191b93b 134#if !defined(SQUID_BUILD_INFO)
4fe75473
FC
135#define SQUID_BUILD_INFO ""
136#endif
137
5e6d4736 138static char *opt_syslog_facility = NULL;
30a4f2a8 139static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
e13ee7ad 140static int configured_once = 0;
30a4f2a8 141#if MALLOC_DBG
4d64d74a 142static int malloc_debug_level = 0;
30a4f2a8 143#endif
5cd39a10 144static volatile int do_reconfigure = 0;
145static volatile int do_rotate = 0;
2681d383 146static volatile int do_shutdown = 0;
ae1feb30 147static volatile int shutdown_status = 0;
4d7add01 148
a2c48c98
AR
149static int RotateSignal = -1;
150static int ReconfigureSignal = -1;
151static int ShutdownSignal = -1;
152
5cd39a10 153static void mainRotate(void);
d71e4674
AR
154static void mainReconfigureStart(void);
155static void mainReconfigureFinish(void*);
f5b8bbc4 156static void mainInitialize(void);
f5b8bbc4 157static void usage(void);
63be0a78 158static void mainParseOptions(int argc, char *argv[]);
f5b8bbc4 159static void sendSignal(void);
160static void serverConnectionsOpen(void);
d71e4674 161static void serverConnectionsClose(void);
bbe199dc 162static void watch_child(char **);
85407535 163static void setEffectiveUser(void);
36a97e19 164#if MEM_GEN_TRACE
165extern void log_trace_done();
166extern void log_trace_init(char *);
167#endif
8ff3fa2e 168static void SquidShutdown(void);
b6a2f15e 169static void mainSetCwd(void);
efd900cb 170static int checkRunningPid(void);
85407535 171
1191b93b 172#if !_SQUID_MSWIN_
e18d7fdc 173static const char *squid_start_script = "squid_start";
b293c4d8 174#endif
e18d7fdc 175
9bc73deb 176#if TEST_ACCESS
177#include "test_access.c"
178#endif
179
63be0a78 180/** temporary thunk across to the unrefactored store interface */
8ff3fa2e 181
182class StoreRootEngine : public AsyncEngine
183{
184
185public:
26ac0430 186 int checkEvents(int timeout) {
8ff3fa2e 187 Store::Root().callback();
188 return EVENT_IDLE;
189 };
190};
191
9688b0ae 192class SignalEngine: public AsyncEngine
a553a5a3 193{
194
195public:
e053c141 196 SignalEngine(EventLoop &evtLoop) : loop(evtLoop) {}
9688b0ae 197 virtual int checkEvents(int timeout);
a553a5a3 198
199private:
26ac0430 200 static void StopEventLoop(void * data) {
9688b0ae 201 static_cast<SignalEngine *>(data)->loop.stop();
a553a5a3 202 }
203
9688b0ae 204 void doShutdown(time_t wait);
205
a553a5a3 206 EventLoop &loop;
207};
208
9688b0ae 209int
210SignalEngine::checkEvents(int timeout)
a553a5a3 211{
9688b0ae 212 PROF_start(SignalEngine_checkEvents);
fc68f6b1 213
a553a5a3 214 if (do_reconfigure) {
d71e4674 215 mainReconfigureStart();
a553a5a3 216 do_reconfigure = 0;
a553a5a3 217 } else if (do_rotate) {
218 mainRotate();
219 do_rotate = 0;
220 } else if (do_shutdown) {
9688b0ae 221 doShutdown(do_shutdown > 0 ? (int) Config.shutdownLifetime : 0);
a553a5a3 222 do_shutdown = 0;
26ac0430 223 }
a2c48c98
AR
224 BroadcastSignalIfAny(DebugSignal);
225 BroadcastSignalIfAny(RotateSignal);
226 BroadcastSignalIfAny(ReconfigureSignal);
227 BroadcastSignalIfAny(ShutdownSignal);
a553a5a3 228
9688b0ae 229 PROF_stop(SignalEngine_checkEvents);
230 return EVENT_IDLE;
231}
a553a5a3 232
9688b0ae 233void
234SignalEngine::doShutdown(time_t wait)
235{
236 debugs(1, 1, "Preparing for shutdown after " << statCounter.client_http.requests << " requests");
237 debugs(1, 1, "Waiting " << wait << " seconds for active connections to finish");
8ff3fa2e 238
9688b0ae 239 shutting_down = 1;
240
241#if USE_WIN32_SERVICE
242 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
243#endif
244
0bcb6908 245 /* run the closure code which can be shared with reconfigure */
9688b0ae 246 serverConnectionsClose();
2f1431ea 247#if USE_AUTH
0bcb6908 248 /* detach the auth components (only do this on full shutdown) */
c6cf8dee 249 Auth::Scheme::FreeAll();
2f1431ea 250#endif
9688b0ae 251 eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
a553a5a3 252}
253
b8d8561b 254static void
0673c0ba 255usage(void)
ccff9601 256{
0ee4272b 257 fprintf(stderr,
0e657244 258#if USE_WIN32_SERVICE
8eb28163 259 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
0e657244 260#else
8eb28163 261 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
0e657244 262#endif
62e76326 263 " -a port Specify HTTP port number (default: %d).\n"
264 " -d level Write debugging to stderr also.\n"
265 " -f file Use given config-file instead of\n"
266 " %s\n"
267 " -h Print help message.\n"
0e657244 268#if USE_WIN32_SERVICE
269 " -i Installs as a Windows Service (see -n option).\n"
270#endif
62e76326 271 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
272 " Parse configuration file, then send signal to \n"
273 " running copy (except -k parse) and exit.\n"
0e657244 274#if USE_WIN32_SERVICE
275 " -n name Specify Windows Service name to use for service operations\n"
276 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
277 " -r Removes a Windows Service (see -n option).\n"
278#endif
5e6d4736 279 " -s | -l facility\n"
280 " Enable logging to syslog.\n"
62e76326 281 " -u port Specify ICP port number (default: %d), disable with 0.\n"
282 " -v Print version.\n"
283 " -z Create swap directories\n"
284 " -C Do not catch fatal signals.\n"
8eb28163 285 " -D OBSOLETE. Scheduled for removal.\n"
62e76326 286 " -F Don't serve any requests until store is rebuilt.\n"
287 " -N No daemon mode.\n"
0e657244 288#if USE_WIN32_SERVICE
289 " -O options\n"
290 " Set Windows Service Command line options in Registry.\n"
291#endif
62e76326 292 " -R Do not set REUSEADDR on port.\n"
293 " -S Double-check swap during rebuild.\n"
62e76326 294 " -X Force full debugging.\n"
295 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
7dbca7a4 296 APP_SHORTNAME, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
77ffc99f 297 exit(1);
ccff9601 298}
299
63be0a78 300/**
301 * Parse the parameters received via command line interface.
302 *
d85b8894
AJ
303 \param argc Number of options received on command line
304 \param argv List of parameters received on command line
63be0a78 305 */
b8d8561b 306static void
307mainParseOptions(int argc, char *argv[])
090089c4 308{
090089c4 309 extern char *optarg;
4d64d74a 310 int c;
090089c4 311
0e657244 312#if USE_WIN32_SERVICE
5e6d4736 313 while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
0e657244 314#else
05f1c52c 315 while ((c = getopt(argc, argv, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
0e657244 316#endif
9b7292ce 317 {
318
26ac0430 319 switch (c) {
62e76326 320
321 case 'C':
63be0a78 322 /** \par C
323 * Unset/disabel global option for catchign signals. opt_catch_signals */
62e76326 324 opt_catch_signals = 0;
325 break;
326
327 case 'D':
63be0a78 328 /** \par D
8eb28163
AJ
329 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
330 debugs(1,DBG_CRITICAL, "WARNING: -D command-line option is obsolete.");
62e76326 331 break;
332
333 case 'F':
63be0a78 334 /** \par F
335 * Set global option for foreground rebuild. opt_foreground_rebuild */
62e76326 336 opt_foreground_rebuild = 1;
337 break;
338
339 case 'N':
63be0a78 340 /** \par N
341 * Set global option for 'no_daemon' mode. opt_no_daemon */
62e76326 342 opt_no_daemon = 1;
343 break;
63be0a78 344
0e657244 345#if USE_WIN32_SERVICE
346
347 case 'O':
63be0a78 348 /** \par O
349 * Set global option. opt_command_lin and WIN32_Command_Line */
0e657244 350 opt_command_line = 1;
351 WIN32_Command_Line = xstrdup(optarg);
352 break;
353#endif
62e76326 354
355 case 'R':
63be0a78 356 /** \par R
357 * Unset/disable global option opt_reuseaddr */
62e76326 358 opt_reuseaddr = 0;
359 break;
360
361 case 'S':
63be0a78 362 /** \par S
363 * Set global option opt_store_doublecheck */
62e76326 364 opt_store_doublecheck = 1;
365 break;
366
62e76326 367 case 'X':
63be0a78 368 /** \par X
369 * Force full debugging */
62493678
AJ
370 Debug::parseOptions("rotate=0 ALL,9");
371 Debug::override_X = 1;
62e76326 372 sigusr2_handle(SIGUSR2);
62e76326 373 break;
374
375 case 'Y':
63be0a78 376 /** \par Y
377 * Set global option opt_reload_hit_only */
62e76326 378 opt_reload_hit_only = 1;
62e76326 379 break;
380
0e657244 381#if USE_WIN32_SERVICE
382
383 case 'i':
63be0a78 384 /** \par i
385 * Set global option opt_install_service (to TRUE) */
0e657244 386 opt_install_service = TRUE;
0e657244 387 break;
0e657244 388#endif
389
62e76326 390 case 'a':
63be0a78 391 /** \par a
392 * Add optional HTTP port as given following the option */
62e76326 393 add_http_port(optarg);
62e76326 394 break;
395
396 case 'd':
63be0a78 397 /** \par d
62493678
AJ
398 * Set global option Debug::log_stderr to the number given follwoign the option */
399 Debug::log_stderr = atoi(optarg);
62e76326 400 break;
401
402 case 'f':
63be0a78 403 /** \par f
404 * Load the file given instead of the default squid.conf. */
62e76326 405 xfree(ConfigFile);
62e76326 406 ConfigFile = xstrdup(optarg);
62e76326 407 break;
408
409 case 'k':
63be0a78 410 /** \par k
411 * Run the administrative action given following the option */
fc68f6b1 412
63be0a78 413 /** \li When its an unknown option display the usage help. */
62e76326 414 if ((int) strlen(optarg) < 1)
415 usage();
416
417 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
63be0a78 418 /** \li On reconfigure send SIGHUP. */
62e76326 419 opt_send_signal = SIGHUP;
420 else if (!strncmp(optarg, "rotate", strlen(optarg)))
63be0a78 421 /** \li On rotate send SIGQUIT or SIGUSR1. */
7e7a0442 422#ifdef _SQUID_LINUX_THREADS_
62e76326 423
424 opt_send_signal = SIGQUIT;
425
e3175d1f 426#else
62e76326 427
428 opt_send_signal = SIGUSR1;
429
e3175d1f 430#endif
62e76326 431
432 else if (!strncmp(optarg, "debug", strlen(optarg)))
63be0a78 433 /** \li On debug send SIGTRAP or SIGUSR2. */
7e7a0442 434#ifdef _SQUID_LINUX_THREADS_
62e76326 435
436 opt_send_signal = SIGTRAP;
437
e3175d1f 438#else
62e76326 439
440 opt_send_signal = SIGUSR2;
441
442#endif
443
444 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
63be0a78 445 /** \li On shutdown send SIGTERM. */
62e76326 446 opt_send_signal = SIGTERM;
447 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
63be0a78 448 /** \li On interrupt send SIGINT. */
62e76326 449 opt_send_signal = SIGINT;
450 else if (!strncmp(optarg, "kill", strlen(optarg)))
63be0a78 451 /** \li On kill send SIGKILL. */
62e76326 452 opt_send_signal = SIGKILL;
ae1feb30 453
454#ifdef SIGTTIN
455
456 else if (!strncmp(optarg, "restart", strlen(optarg)))
63be0a78 457 /** \li On restart send SIGTTIN. (exit and restart by parent) */
458 opt_send_signal = SIGTTIN;
ae1feb30 459
460#endif
461
62e76326 462 else if (!strncmp(optarg, "check", strlen(optarg)))
63be0a78 463 /** \li On check send 0 / SIGNULL. */
62e76326 464 opt_send_signal = 0; /* SIGNULL */
465 else if (!strncmp(optarg, "parse", strlen(optarg)))
63be0a78 466 /** \li On parse set global flag to re-parse the config file only. */
467 opt_parse_cfg_only = 1;
62e76326 468 else
469 usage();
470
471 break;
472
473 case 'm':
63be0a78 474 /** \par m
475 * Set global malloc_debug_level to the value given following the option.
476 * if none is given it toggles the xmalloc_trace option on/off */
62e76326 477 if (optarg) {
30a4f2a8 478#if MALLOC_DBG
fc68f6b1 479 malloc_debug_level = atoi(optarg);
30a4f2a8 480#else
fc68f6b1 481 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
33ab18e8 482#endif
62e76326 483
484 } else {
33ab18e8 485#if XMALLOC_TRACE
62e76326 486 xmalloc_trace = !xmalloc_trace;
33ab18e8 487#else
62e76326 488 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
30a4f2a8 489#endif
62e76326 490 }
d9e7ee1f 491 break;
d9e7ee1f 492
0e657244 493#if USE_WIN32_SERVICE
494
495 case 'n':
63be0a78 496 /** \par n
497 * Set global option opt_signal_service (to TRUE).
498 * Stores the additional parameter given in global WIN32_Service_name */
0e657244 499 xfree(WIN32_Service_name);
500
501 WIN32_Service_name = xstrdup(optarg);
502
503 opt_signal_service = TRUE;
504
505 break;
506
507 case 'r':
63be0a78 508 /** \par r
509 * Set global option opt_remove_service (to TRUE) */
0e657244 510 opt_remove_service = TRUE;
511
512 break;
513
514#endif
515
5e6d4736 516 case 'l':
63be0a78 517 /** \par l
518 * Stores the syslog facility name in global opt_syslog_facility
519 * then performs actions for -s option. */
5e6d4736 520 opt_syslog_facility = xstrdup(optarg);
521
62e76326 522 case 's':
63be0a78 523 /** \par s
524 * Initialize the syslog for output */
c307aec3 525#if HAVE_SYSLOG
62e76326 526
5e6d4736 527 _db_set_syslog(opt_syslog_facility);
0e657244 528
62e76326 529 break;
0e657244 530
c307aec3 531#else
62e76326 532
533 fatal("Logging to syslog not available on this platform");
0e657244 534
62e76326 535 /* NOTREACHED */
536#endif
537
538 case 'u':
63be0a78 539 /** \par u
540 * Store the ICP port number given in global option icpPortNumOverride
541 * ensuring its a positive number. */
62e76326 542 icpPortNumOverride = atoi(optarg);
543
544 if (icpPortNumOverride < 0)
545 icpPortNumOverride = 0;
546
547 break;
548
549 case 'v':
63be0a78 550 /** \par v
551 * Display squid version and build information. Then exit. */
4fe75473
FC
552 printf("Squid Cache: Version %s\n" ,version_string);
553 if (strlen(SQUID_BUILD_INFO))
554 printf("%s\n",SQUID_BUILD_INFO);
555 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS);
62e76326 556
1a774556 557#if USE_WIN32_SERVICE
558
559 printf("Compiled as Windows System Service.\n");
560
561#endif
562
62e76326 563 exit(0);
564
565 /* NOTREACHED */
566
567 case 'z':
63be0a78 568 /** \par z
62493678
AJ
569 * Set global option Debug::log_stderr and opt_create_swap_dirs */
570 Debug::log_stderr = 1;
62e76326 571 opt_create_swap_dirs = 1;
62e76326 572 break;
573
63be0a78 574 case 'h':
575
62e76326 576 case '?':
577
578 default:
63be0a78 579 /** \par h,?, or unknown
580 * \copydoc usage() */
62e76326 581 usage();
582
583 break;
584 }
9b7292ce 585
090089c4 586 }
4d64d74a 587}
090089c4 588
7a2f978b 589/* ARGSUSED */
b293c4d8 590void
9b7292ce 591rotate_logs(int sig)
592{
5cd39a10 593 do_rotate = 1;
a2c48c98 594 RotateSignal = sig;
1191b93b 595#if !_SQUID_MSWIN_
30a4f2a8 596#if !HAVE_SIGACTION
62e76326 597
30a4f2a8 598 signal(sig, rotate_logs);
599#endif
a50bfe93 600#endif
30a4f2a8 601}
602
7a2f978b 603/* ARGSUSED */
b293c4d8 604void
9b7292ce 605reconfigure(int sig)
606{
5cd39a10 607 do_reconfigure = 1;
a2c48c98 608 ReconfigureSignal = sig;
1191b93b 609#if !_SQUID_MSWIN_
30a4f2a8 610#if !HAVE_SIGACTION
62e76326 611
30a4f2a8 612 signal(sig, reconfigure);
613#endif
a50bfe93 614#endif
30a4f2a8 615}
616
b8d8561b 617void
9b7292ce 618shut_down(int sig)
619{
2681d383 620 do_shutdown = sig == SIGINT ? -1 : 1;
a2c48c98 621 ShutdownSignal = sig;
ae1feb30 622#ifdef SIGTTIN
623
624 if (SIGTTIN == sig)
625 shutdown_status = 1;
626
627#endif
ca4b9ee6
DK
628
629 const pid_t ppid = getppid();
630
bd9fe5b4 631 if (!IamMasterProcess() && ppid > 1) {
ca4b9ee6
DK
632 // notify master that we are shutting down
633 if (kill(ppid, SIGUSR1) < 0)
634 debugs(1, DBG_IMPORTANT, "Failed to send SIGUSR1 to master process,"
635 " pid " << ppid << ": " << xstrerror());
636 }
637
1191b93b 638#if !_SQUID_MSWIN_
a67d2b2e 639#if KILL_PARENT_OPT
62e76326 640
bd9fe5b4 641 if (!IamMasterProcess() && ppid > 1) {
ca4b9ee6 642 debugs(1, DBG_IMPORTANT, "Killing master process, pid " << ppid);
62e76326 643
ca4b9ee6
DK
644 if (kill(ppid, sig) < 0)
645 debugs(1, DBG_IMPORTANT, "kill " << ppid << ": " << xstrerror());
88738790 646 }
62e76326 647
0f658b5b 648#endif /* KILL_PARENT_OPT */
6e40f263 649#if SA_RESETHAND == 0
650 signal(SIGTERM, SIG_DFL);
62e76326 651
6e40f263 652 signal(SIGINT, SIG_DFL);
62e76326 653
a50bfe93 654#endif
6e40f263 655#endif
30a4f2a8 656}
657
24382924 658static void
9b7292ce 659serverConnectionsOpen(void)
660{
7de94c8c
AR
661 if (IamPrimaryProcess()) {
662#if USE_WCCP
663
5667a628 664 wccpConnectionOpen();
7de94c8c 665#endif
45aae82b 666
7de94c8c
AR
667#if USE_WCCPv2
668
5667a628 669 wccp2ConnectionOpen();
7de94c8c
AR
670#endif
671 }
095ec2b1
AR
672 // start various proxying services if we are responsible for them
673 if (IamWorkerProcess()) {
5667a628
AR
674 clientOpenListenSockets();
675 icpConnectionsOpen();
ace287ee 676#if USE_HTCP
62e76326 677
5667a628 678 htcpInit();
ace287ee 679#endif
a67d2b2e 680#if SQUID_SNMP
62e76326 681
5667a628 682 snmpConnectionOpen();
320e9f36 683#endif
0b0cfcf2 684
5667a628
AR
685 clientdbInit();
686 icmpEngine.Open();
687 netdbInit();
688 asnInit();
689 ACL::Initialize();
690 peerSelectInit();
691
692 carpInit();
2f1431ea 693#if USE_AUTH
5667a628 694 peerUserHashInit();
2f1431ea 695#endif
5667a628 696 peerSourceHashInit();
7de94c8c 697 }
5f3f8d0e 698}
699
d71e4674 700static void
9b7292ce 701serverConnectionsClose(void)
702{
0a5a8601 703 assert(shutting_down || reconfiguring);
7de94c8c
AR
704
705 if (IamPrimaryProcess()) {
706#if USE_WCCP
707
5667a628 708 wccpConnectionClose();
7de94c8c
AR
709#endif
710#if USE_WCCPv2
711
5667a628 712 wccp2ConnectionClose();
7de94c8c
AR
713#endif
714 }
095ec2b1 715 if (IamWorkerProcess()) {
5667a628
AR
716 clientHttpConnectionsClose();
717 icpConnectionShutdown();
72549e05 718#if USE_HTCP
62e76326 719
5667a628 720 htcpSocketShutdown();
72549e05 721#endif
62e76326 722
5667a628 723 icmpEngine.Close();
a67d2b2e 724#if SQUID_SNMP
62e76326 725
5667a628 726 snmpConnectionShutdown();
320e9f36 727#endif
62e76326 728
5667a628 729 asnFreeMemory();
7de94c8c 730 }
5f3f8d0e 731}
732
b8d8561b 733static void
d71e4674 734mainReconfigureStart(void)
9b7292ce 735{
bf8fe701 736 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string << ")...");
5cd39a10 737 reconfiguring = 1;
d71e4674
AR
738
739 // Initiate asynchronous closing sequence
15df8349 740 serverConnectionsClose();
17e6c0a1 741 icpConnectionClose();
72549e05 742#if USE_HTCP
62e76326 743
72549e05 744 htcpSocketClose();
745#endif
59ad6d31 746#if SQUID_SNMP
62e76326 747
17e6c0a1 748 snmpConnectionClose();
320e9f36 749#endif
3c573763 750#if USE_DNSSERVERS
62e76326 751
74addf6c 752 dnsShutdown();
3c573763 753#else
62e76326 754
7b724b86 755 idnsShutdown();
eb824054 756#endif
95d2589c
CT
757#if USE_SSL_CRTD
758 Ssl::Helper::GetInstance()->Shutdown();
759#endif
760#if USE_SSL
761 Ssl::TheGlobalContextStorage.reconfigureStart();
762#endif
74addf6c 763 redirectShutdown();
2f1431ea 764#if USE_AUTH
0bcb6908 765 authenticateReset();
2f1431ea 766#endif
d9572179 767 externalAclShutdown();
2db68ce5 768 storeDirCloseSwapLogs();
2e923080 769 storeLogClose();
770 accessLogClose();
3ff65596
AR
771#if ICAP_CLIENT
772 icapLogClose();
773#endif
d71e4674
AR
774
775 eventAdd("mainReconfigureFinish", &mainReconfigureFinish, NULL, 0, 1,
26ac0430 776 false);
d71e4674
AR
777}
778
779static void
26ac0430
AJ
780mainReconfigureFinish(void *)
781{
d71e4674
AR
782 debugs(1, 3, "finishing reconfiguring");
783
c68e9c6b 784 errorClean();
3aa4adbc 785 enter_suid(); /* root to read config file */
936b23cd
AJ
786
787 // we may have disabled the need for PURGE
e1381638 788 if (Config2.onoff.enable_purge)
936b23cd
AJ
789 Config2.onoff.enable_purge = 2;
790
18631119 791 // parse the config returns a count of errors encountered.
13aeac35 792 const int oldWorkers = Config.workers;
18631119
AJ
793 if ( parseConfigFile(ConfigFile) != 0) {
794 // for now any errors are a fatal condition...
795 self_destruct();
796 }
13aeac35
AR
797 if (oldWorkers != Config.workers) {
798 debugs(1, DBG_CRITICAL, "WARNING: Changing 'workers' (from " <<
5667a628
AR
799 oldWorkers << " to " << Config.workers <<
800 ") is not supported and ignored");
13aeac35 801 Config.workers = oldWorkers;
a2c48c98 802 }
936b23cd 803
96c2bb61
AR
804 if (IamPrimaryProcess())
805 CpuAffinityCheck();
806 CpuAffinityReconfigure();
807
c642c141 808 setUmask(Config.umask);
97244680 809 Mem::Report();
3aa4adbc 810 setEffectiveUser();
62493678 811 _db_init(Debug::cache_log, Debug::debugOptions);
429fdbec 812 ipcache_restart(); /* clear stuck entries */
813 fqdncache_restart(); /* sigh, fqdncache too */
0e70aa1e 814 parseEtcHosts();
53ad48e6 815 errorInitialize(); /* reload error pages */
2e923080 816 accessLogInit();
76fc7e57
AJ
817
818#if USE_LOADABLE_MODULES
819 LoadableModulesConfigure(Config.loadable_module_names);
820#endif
821
822#if USE_ADAPTATION
823 bool enableAdaptation = false;
824#if ICAP_CLIENT
825 Adaptation::Icap::TheConfig.finalize();
826 enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
827#endif
828#if USE_ECAP
829 Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
830 enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
831#endif
832 Adaptation::Config::Finalize(enableAdaptation);
833#endif
d090e020 834
3ff65596
AR
835#if ICAP_CLIENT
836 icapLogOpen();
837#endif
2e923080 838 storeLogOpen();
3c573763 839#if USE_DNSSERVERS
62e76326 840
74addf6c 841 dnsInit();
3c573763 842#else
62e76326 843
7b724b86 844 idnsInit();
eb824054 845#endif
95d2589c
CT
846#if USE_SSL_CRTD
847 Ssl::Helper::GetInstance()->Init();
848#endif
62e76326 849
74addf6c 850 redirectInit();
2f1431ea 851#if USE_AUTH
5817ee13 852 authenticateInit(&Auth::TheConfig);
2f1431ea 853#endif
d9572179 854 externalAclInit();
7de94c8c
AR
855
856 if (IamPrimaryProcess()) {
1f38f50a 857#if USE_WCCP
62e76326 858
5667a628 859 wccpInit();
1f38f50a 860#endif
0b0cfcf2 861#if USE_WCCPv2
862
5667a628 863 wccp2Init();
0b0cfcf2 864#endif
7de94c8c 865 }
62e76326 866
0ffd22bc 867 serverConnectionsOpen();
9c2e9b50 868
3ee2b4f8 869 neighbors_init();
9c2e9b50 870
2db68ce5 871 storeDirOpenSwapLogs();
9c2e9b50 872
9c021a38 873 mimeInit(Config.mimeTablePathname);
9c2e9b50 874
9a0a18de 875#if USE_DELAY_POOLS
b4cd430a
CT
876 Config.ClientDelay.finalize();
877#endif
878
926375e6 879 if (Config.onoff.announce) {
880 if (!eventFind(start_announce, NULL))
881 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
882 } else {
883 if (eventFind(start_announce, NULL))
884 eventDelete(start_announce, NULL);
885 }
886
b8890359 887 writePidFile(); /* write PID file */
9c2e9b50 888
bf8fe701 889 debugs(1, 1, "Ready to serve requests.");
9c2e9b50 890
5cd39a10 891 reconfiguring = 0;
892}
893
894static void
9b7292ce 895mainRotate(void)
896{
cc192b50 897 icmpEngine.Close();
3c573763 898#if USE_DNSSERVERS
e40aa8da 899 dnsShutdown();
3c573763 900#endif
e40aa8da 901 redirectShutdown();
2f1431ea 902#if USE_AUTH
0bcb6908 903 authenticateRotate();
2f1431ea 904#endif
d9572179 905 externalAclShutdown();
0a6dd8fb 906
5cd39a10 907 _db_rotate_log(); /* cache.log */
908 storeDirWriteCleanLogs(1);
909 storeLogRotate(); /* store.log */
910 accessLogRotate(); /* access.log */
3ff65596
AR
911#if ICAP_CLIENT
912 icapLogRotate(); /*icap.log*/
913#endif
cc192b50 914 icmpEngine.Open();
3c573763 915#if USE_DNSSERVERS
e40aa8da 916 dnsInit();
3c573763 917#endif
e40aa8da 918 redirectInit();
2f1431ea 919#if USE_AUTH
5817ee13 920 authenticateInit(&Auth::TheConfig);
2f1431ea 921#endif
d9572179 922 externalAclInit();
5f3f8d0e 923}
924
067bea91 925static void
9b7292ce 926setEffectiveUser(void)
927{
fc68f6b1 928 keepCapabilities();
85407535 929 leave_suid(); /* Run as non privilegied user */
1191b93b 930#if _SQUID_OS2_
62e76326 931
cd377065 932 return;
933#endif
62e76326 934
85407535 935 if (geteuid() == 0) {
bf8fe701 936 debugs(0, 0, "Squid is not safe to run as root! If you must");
937 debugs(0, 0, "start Squid as root, then you must configure");
938 debugs(0, 0, "it to run as a non-priveledged user with the");
939 debugs(0, 0, "'cache_effective_user' option in the config file.");
62e76326 940 fatal("Don't run Squid as root, set 'cache_effective_user'!");
85407535 941 }
942}
943
b6a2f15e 944static void
9b7292ce 945mainSetCwd(void)
946{
4a504376 947 char pathbuf[MAXPATHLEN];
62e76326 948
b6a2f15e 949 if (Config.coredump_dir) {
62e76326 950 if (0 == strcmp("none", Config.coredump_dir)) {
951 (void) 0;
952 } else if (chdir(Config.coredump_dir) == 0) {
bf8fe701 953 debugs(0, 1, "Set Current Directory to " << Config.coredump_dir);
62e76326 954 return;
955 } else {
bf8fe701 956 debugs(50, 0, "chdir: " << Config.coredump_dir << ": " << xstrerror());
62e76326 957 }
b6a2f15e 958 }
62e76326 959
02e8115e 960 /* If we don't have coredump_dir or couldn't cd there, report current dir */
4a504376 961 if (getcwd(pathbuf, MAXPATHLEN)) {
bf8fe701 962 debugs(0, 1, "Current Directory is " << pathbuf);
4a504376 963 } else {
bf8fe701 964 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
4a504376 965 }
b6a2f15e 966}
967
b8d8561b 968static void
9b7292ce 969mainInitialize(void)
970{
efd900cb 971 /* chroot if configured to run inside chroot */
62e76326 972
64b0a10d 973 if (Config.chroot_dir && (chroot(Config.chroot_dir) != 0 || chdir("/") != 0)) {
62e76326 974 fatal("failed to chroot");
efd900cb 975 }
62e76326 976
1758c627 977 if (opt_catch_signals) {
62e76326 978 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
979 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
44f99671 980 }
62e76326 981
30a4f2a8 982 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
983 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
44f99671 984
85407535 985 setEffectiveUser();
62e76326 986
30a4f2a8 987 if (icpPortNumOverride != 1)
f45dd259 988 Config.Port.icp = (unsigned short) icpPortNumOverride;
30a4f2a8 989
62493678 990 _db_init(Debug::cache_log, Debug::debugOptions);
62e76326 991
62493678 992 fd_open(fileno(debug_log), FD_LOG, Debug::cache_log);
62e76326 993
71a17702 994#if MEM_GEN_TRACE
62e76326 995
71a17702 996 log_trace_init("/tmp/squid.alloc");
62e76326 997
71a17702 998#endif
62e76326 999
bf8fe701 1000 debugs(1, 0, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
62e76326 1001
be266cb2 1002#if _SQUID_WINDOWS_
b293c4d8 1003 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
bf8fe701 1004 debugs(1, 0, "Running as " << WIN32_Service_name << " Windows System Service on " << WIN32_OS_string);
1005 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line);
b293c4d8 1006 } else
bf8fe701 1007 debugs(1, 0, "Running on " << WIN32_OS_string);
b293c4d8 1008#endif
1009
36584579 1010 debugs(1, 1, "Process ID " << getpid());
095ec2b1
AR
1011
1012 debugs(1, 1, "Process Roles:" << ProcessRoles());
1013
f3f0f563 1014 setSystemLimits();
bf8fe701 1015 debugs(1, 1, "With " << Squid_MaxFD << " file descriptors available");
5f3f8d0e 1016
1191b93b 1017#if _SQUID_MSWIN_
6c1962dd 1018
bf8fe701 1019 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
6c1962dd 1020
1021 if (WIN32_Socks_initialized)
bf8fe701 1022 debugs(1, 1, "Windows sockets initialized");
6c1962dd 1023
babd1fd5 1024 if (WIN32_OS_version > _WIN_OS_WINNT) {
26ac0430 1025 WIN32_IpAddrChangeMonitorInit();
babd1fd5 1026 }
1027
6c1962dd 1028#endif
1029
9f75c559 1030 if (!configured_once)
62e76326 1031 disk_init(); /* disk_init must go before ipcache_init() */
1032
5f3f8d0e 1033 ipcache_init();
62e76326 1034
f88bb09c 1035 fqdncache_init();
62e76326 1036
0e70aa1e 1037 parseEtcHosts();
62e76326 1038
3c573763 1039#if USE_DNSSERVERS
62e76326 1040
74addf6c 1041 dnsInit();
62e76326 1042
3c573763 1043#else
62e76326 1044
7b724b86 1045 idnsInit();
62e76326 1046
eb824054 1047#endif
62e76326 1048
586089cd
CT
1049#if USE_SSL_CRTD
1050 Ssl::Helper::GetInstance()->Init();
1051#endif
1052
74addf6c 1053 redirectInit();
2f1431ea 1054#if USE_AUTH
5817ee13 1055 authenticateInit(&Auth::TheConfig);
2f1431ea 1056#endif
d9572179 1057 externalAclInit();
62e76326 1058
2ac76861 1059 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
62e76326 1060
2246b732 1061 httpReplyInitModule(); /* must go before accepting replies */
62e76326 1062
9b312a19 1063 errorInitialize();
62e76326 1064
7a2f978b 1065 accessLogInit();
62e76326 1066
e1381638 1067#if ICAP_CLIENT
3ff65596
AR
1068 icapLogOpen();
1069#endif
1070
3898f57f 1071#if USE_IDENT
4daaf3cb 1072 Ident::Init();
3898f57f 1073#endif
4daaf3cb 1074
59ad6d31 1075#if SQUID_SNMP
62e76326 1076
5e14bf6d 1077 snmpInit();
62e76326 1078
5e14bf6d 1079#endif
30a4f2a8 1080#if MALLOC_DBG
62e76326 1081
5f3f8d0e 1082 malloc_debug(0, malloc_debug_level);
62e76326 1083
5f3f8d0e 1084#endif
1085
dbe4fd8e 1086 if (!configured_once) {
a3d0a19d 1087#if USE_UNLINKD
62e76326 1088 unlinkdInit();
1089#endif
1090
1091 urlInitialize();
62e76326 1092 statInit();
1093 storeInit();
1094 mainSetCwd();
1095 /* after this point we want to see the mallinfo() output */
1096 do_mallinfo = 1;
1097 mimeInit(Config.mimeTablePathname);
62e76326 1098 refreshInit();
9a0a18de 1099#if USE_DELAY_POOLS
62e76326 1100 DelayPools::Init();
0d7e5d78 1101#endif
62e76326 1102
b6b6f466 1103 FwdState::initModule();
62ee09ca 1104 /* register the modules in the cache manager menus */
62ee09ca 1105
a08f1b5a 1106 cbdataRegisterWithCacheManager();
62ee09ca 1107 /* These use separate calls so that the comm loops can eventually
1108 * coexist.
1109 */
62ee09ca 1110
15b3c0d7 1111 eventInit();
610ee341 1112
26ac0430 1113 // TODO: pconn is a good candidate for new-style registration
6852be71 1114 // PconnModule::GetInstance()->registerWithCacheManager();
26ac0430 1115 // moved to PconnModule::PconnModule()
5f3f8d0e 1116 }
62e76326 1117
7de94c8c 1118 if (IamPrimaryProcess()) {
1f38f50a 1119#if USE_WCCP
5667a628 1120 wccpInit();
62e76326 1121
0b0cfcf2 1122#endif
1123#if USE_WCCPv2
1124
5667a628 1125 wccp2Init();
0b0cfcf2 1126
1f38f50a 1127#endif
7de94c8c 1128 }
62e76326 1129
2285407f 1130 serverConnectionsOpen();
62e76326 1131
3ee2b4f8 1132 neighbors_init();
fc68f6b1 1133
5f5e883f 1134 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
62e76326 1135
efd900cb 1136 if (Config.chroot_dir)
62e76326 1137 no_suid();
1138
dbe4fd8e 1139 if (!configured_once)
62e76326 1140 writePidFile(); /* write PID file */
0a5b9b32 1141
7e7a0442 1142#ifdef _SQUID_LINUX_THREADS_
62e76326 1143
e3175d1f 1144 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
62e76326 1145
e3175d1f 1146 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
62e76326 1147
e3175d1f 1148#else
62e76326 1149
30a4f2a8 1150 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
62e76326 1151
30a4f2a8 1152 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
62e76326 1153
9fc0b4b8 1154#endif
62e76326 1155
30a4f2a8 1156 squid_signal(SIGHUP, reconfigure, SA_RESTART);
62e76326 1157
30a4f2a8 1158 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1159
30a4f2a8 1160 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1161
ae1feb30 1162#ifdef SIGTTIN
1163
1164 squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
1165
1166#endif
1167
58a39dc9 1168 memCheckInit();
62e76326 1169
57afc994
AR
1170#if USE_LOADABLE_MODULES
1171 LoadableModulesConfigure(Config.loadable_module_names);
1172#endif
1173
8f361c50
AR
1174#if USE_ADAPTATION
1175 bool enableAdaptation = false;
1176
1177 // We can remove this dependency on specific adaptation mechanisms
1178 // if we create a generic Registry of such mechanisms. Should we?
b958cb0f 1179#if ICAP_CLIENT
26cc52cb
AR
1180 Adaptation::Icap::TheConfig.finalize();
1181 enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
6e5db507
AR
1182#endif
1183#if USE_ECAP
574b508c
AR
1184 Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
1185 enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
b958cb0f 1186#endif
8f361c50
AR
1187 // must be the last adaptation-related finalize
1188 Adaptation::Config::Finalize(enableAdaptation);
b958cb0f
AR
1189#endif
1190
79039294
AR
1191#if USE_SQUID_ESI
1192 Esi::Init();
1193#endif
b958cb0f 1194
9a0a18de 1195#if USE_DELAY_POOLS
b4cd430a
CT
1196 Config.ClientDelay.finalize();
1197#endif
1198
bf8fe701 1199 debugs(1, 1, "Ready to serve requests.");
62e76326 1200
dbe4fd8e 1201 if (!configured_once) {
c8f4eac4 1202 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
62e76326 1203
1204 if (Config.onoff.announce)
1205 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
1206
1207 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
1208
1209 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
1210
88bfe092 1211#if USE_XPROF_STATS
62e76326 1212
1213 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
1214
88bfe092 1215#endif
62e76326 1216
1217 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
4d7add01 1218 }
62e76326 1219
dbe4fd8e 1220 configured_once = 1;
4d64d74a 1221}
1222
c842329d 1223/// unsafe main routine -- may throw
f3f3e961 1224int SquidMain(int argc, char **argv);
c842329d 1225/// unsafe main routine wrapper to catch exceptions
6e5db507
AR
1226static int SquidMainSafe(int argc, char **argv);
1227
6c1962dd 1228#if USE_WIN32_SERVICE
1229/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1230extern "C" void WINAPI
e1381638 1231SquidWinSvcMain(int argc, char **argv)
18631119
AJ
1232{
1233 SquidMainSafe(argc, argv);
1234}
6c1962dd 1235#else
b8d8561b 1236int
1237main(int argc, char **argv)
6e5db507 1238{
18631119 1239 return SquidMainSafe(argc, argv);
6e5db507 1240}
18631119 1241#endif
6e5db507
AR
1242
1243static int
1244SquidMainSafe(int argc, char **argv)
1245{
1246 try {
1247 return SquidMain(argc, argv);
26ac0430 1248 } catch (const std::exception &e) {
51618c6a
AR
1249 debugs(1, DBG_CRITICAL, "FATAL: dying from an unhandled exception: " <<
1250 e.what());
26ac0430
AJ
1251 throw;
1252 } catch (...) {
51618c6a 1253 debugs(1, DBG_CRITICAL, "FATAL: dying from an unhandled exception.");
26ac0430
AJ
1254 throw;
1255 }
1256 return -1; // not reached
6e5db507
AR
1257}
1258
d4a3e179
AR
1259/// computes name and ID for the current kid process
1260static void
1261ConfigureCurrentKid(const char *processName)
1262{
5667a628 1263 // kids are marked with parenthesis around their process names
d4a3e179
AR
1264 if (processName && processName[0] == '(') {
1265 if (const char *idStart = strrchr(processName, '-')) {
1266 KidIdentifier = atoi(idStart + 1);
9de6c973
AR
1267 const size_t nameLen = idStart - (processName + 1);
1268 assert(nameLen < sizeof(TheKidName));
1269 xstrncpy(TheKidName, processName + 1, nameLen + 1);
095ec2b1
AR
1270 if (!strcmp(TheKidName, "squid-coord"))
1271 TheProcessKind = pkCoordinator;
1272 else
1273 if (!strcmp(TheKidName, "squid"))
1274 TheProcessKind = pkWorker;
1275 else
1276 if (!strcmp(TheKidName, "squid-disk"))
1277 TheProcessKind = pkDisker;
1278 else
1279 TheProcessKind = pkOther; // including coordinator
d4a3e179 1280 }
2664c457 1281 } else {
9de6c973 1282 xstrncpy(TheKidName, APP_SHORTNAME, sizeof(TheKidName));
2664c457 1283 KidIdentifier = 0;
d4a3e179 1284 }
d4a3e179
AR
1285}
1286
f3f3e961 1287int
6e5db507 1288SquidMain(int argc, char **argv)
9b7292ce 1289{
d4a3e179 1290 ConfigureCurrentKid(argv[0]);
007d775d 1291
be266cb2 1292#if _SQUID_WINDOWS_
a0aa9e74 1293 int WIN32_init_err;
1294#endif
4d64d74a 1295
a4ba1105 1296#if HAVE_SBRK
62e76326 1297
9b7292ce 1298 sbrk_start = sbrk(0);
a4ba1105 1299#endif
1300
fb6a61d1 1301 Debug::parseOptions(NULL);
9b7292ce 1302 debug_log = stderr;
62e76326 1303
b9269882 1304#if defined(SQUID_MAXFD_LIMIT)
1305
1306 if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
1307 Squid_MaxFD = SQUID_MAXFD_LIMIT;
1308
1309#endif
399e85ea 1310
be266cb2 1311#if _SQUID_WINDOWS_
a0aa9e74 1312 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
1313 return WIN32_init_err;
0e6d05ef 1314#endif
1315
9b7292ce 1316 /* call mallopt() before anything else */
0b29fe44 1317#if HAVE_MALLOPT
7328e889 1318#ifdef M_GRAIN
9b7292ce 1319 /* Round up all sizes to a multiple of this */
1320 mallopt(M_GRAIN, 16);
62e76326 1321
7328e889 1322#endif
1323#ifdef M_MXFAST
9b7292ce 1324 /* biggest size that is considered a small block */
1325 mallopt(M_MXFAST, 256);
62e76326 1326
7328e889 1327#endif
1328#ifdef M_NBLKS
9b7292ce 1329 /* allocate this many small blocks at once */
1330 mallopt(M_NLBLKS, 32);
62e76326 1331
7328e889 1332#endif
1333#endif /* HAVE_MALLOPT */
1334
9b7292ce 1335 squid_srandom(time(NULL));
4d64d74a 1336
9b7292ce 1337 getCurrentTime();
62e76326 1338
9b7292ce 1339 squid_start = current_time;
62e76326 1340
9b7292ce 1341 failure_notify = fatal_dump;
4d64d74a 1342
6c1962dd 1343#if USE_WIN32_SERVICE
1344
9b7292ce 1345 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1346
1347#endif
1348
9b7292ce 1349 mainParseOptions(argc, argv);
4d64d74a 1350
9aae6be3 1351 if (opt_parse_cfg_only) {
26ac0430 1352 Debug::parseOptions("ALL,1");
9aae6be3 1353 }
1354
6c1962dd 1355#if USE_WIN32_SERVICE
1356
26ac0430 1357 if (opt_install_service) {
9b7292ce 1358 WIN32_InstallService();
a0aa9e74 1359 return 0;
9b7292ce 1360 }
6c1962dd 1361
26ac0430 1362 if (opt_remove_service) {
9b7292ce 1363 WIN32_RemoveService();
a0aa9e74 1364 return 0;
9b7292ce 1365 }
6c1962dd 1366
26ac0430 1367 if (opt_command_line) {
9b7292ce 1368 WIN32_SetServiceCommandLine();
a0aa9e74 1369 return 0;
9b7292ce 1370 }
6c1962dd 1371
1372#endif
1373
9b7292ce 1374 /* parse configuration file
1375 * note: in "normal" case this used to be called from mainInitialize() */
1376 {
1377 int parse_err;
62e76326 1378
9b7292ce 1379 if (!ConfigFile)
1380 ConfigFile = xstrdup(DefaultConfigFile);
62e76326 1381
9b7292ce 1382 assert(!configured_once);
62e76326 1383
9b7292ce 1384 Mem::Init();
62e76326 1385
9b7292ce 1386 storeFsInit(); /* required for config parsing */
62e76326 1387
7b5b7ba8 1388 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
af6a12ee 1389 Fs::Init();
7b5b7ba8 1390
b9ae18aa 1391 /* May not be needed for parsing, have not audited for such */
1392 DiskIOModule::SetupAllModules();
1393
59b2d47f 1394 /* Shouldn't be needed for config parsing, but have not audited for such */
1395 StoreFileSystem::SetupAllFs();
1396
c8f4eac4 1397 /* we may want the parsing process to set this up in the future */
1398 Store::Root(new StoreController);
2f1431ea 1399#if USE_AUTH
ccd8a22a 1400 Auth::Init(); /* required for config parsing */
2f1431ea 1401#endif
055421ee
AJ
1402 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1403
dd9b1081 1404 parse_err = parseConfigFile(ConfigFile);
62e76326 1405
97244680 1406 Mem::Report();
26ac0430 1407
18631119 1408 if (opt_parse_cfg_only || parse_err > 0)
9b7292ce 1409 return parse_err;
9b7292ce 1410 }
c642c141 1411 setUmask(Config.umask);
9b7292ce 1412 if (-1 == opt_send_signal)
1413 if (checkRunningPid())
205d7c3b 1414 exit(0);
e13ee7ad 1415
9bc73deb 1416#if TEST_ACCESS
62e76326 1417
95564b0d 1418 comm_init();
62e76326 1419
9b7292ce 1420 mainInitialize();
62e76326 1421
9b7292ce 1422 test_access();
62e76326 1423
9b7292ce 1424 return 0;
62e76326 1425
9bc73deb 1426#endif
1427
9b7292ce 1428 /* send signal to running copy and exit */
26ac0430 1429 if (opt_send_signal != -1) {
9b7292ce 1430 /* chroot if configured to run inside chroot */
62e76326 1431
a572d8be 1432 if (Config.chroot_dir) {
1433 if (chroot(Config.chroot_dir))
1434 fatal("failed to chroot");
1435
1436 no_suid();
1437 } else {
1438 leave_suid();
9b7292ce 1439 }
62e76326 1440
9b7292ce 1441 sendSignal();
1442 /* NOTREACHED */
1443 }
62e76326 1444
6d57128b 1445 debugs(1,2, HERE << "Doing post-config initialization\n");
520e0073 1446 leave_suid();
6d57128b 1447 ActivateRegistered(rrAfterConfig);
520e0073 1448 enter_suid();
9487bae9 1449
2ae5c85f
AJ
1450 if (!opt_no_daemon && Config.workers > 0)
1451 watch_child(argv);
1452
26ac0430 1453 if (opt_create_swap_dirs) {
9b7292ce 1454 /* chroot if configured to run inside chroot */
0e657244 1455
9b7292ce 1456 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1457 fatal("failed to chroot");
1458 }
62e76326 1459
9b7292ce 1460 setEffectiveUser();
bf8fe701 1461 debugs(0, 0, "Creating Swap Directories");
c8f4eac4 1462 Store::Root().create();
6c1962dd 1463
9b7292ce 1464 return 0;
9b7292ce 1465 }
62e76326 1466
96c2bb61
AR
1467 if (IamPrimaryProcess())
1468 CpuAffinityCheck();
1469 CpuAffinityInit();
1470
95564b0d 1471 setMaxFD();
1472
1473 /* init comm module */
1474 comm_init();
62e76326 1475
26ac0430 1476 if (opt_no_daemon) {
9b7292ce 1477 /* we have to init fdstat here. */
1478 fd_open(0, FD_LOG, "stdin");
1479 fd_open(1, FD_LOG, "stdout");
1480 fd_open(2, FD_LOG, "stderr");
1481 }
62e76326 1482
6c1962dd 1483#if USE_WIN32_SERVICE
1484
9b7292ce 1485 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1486
1487#endif
1488
9b7292ce 1489 mainInitialize();
4d64d74a 1490
6c1962dd 1491#if USE_WIN32_SERVICE
1492
9b7292ce 1493 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
6c1962dd 1494
1495#endif
1496
9b7292ce 1497 /* main loop */
a553a5a3 1498 EventLoop mainLoop;
62e76326 1499
9688b0ae 1500 SignalEngine signalEngine(mainLoop);
6c1962dd 1501
9688b0ae 1502 mainLoop.registerEngine(&signalEngine);
62e76326 1503
8ff3fa2e 1504 /* TODO: stop requiring the singleton here */
1505 mainLoop.registerEngine(EventScheduler::GetInstance());
62e76326 1506
8ff3fa2e 1507 StoreRootEngine store_engine;
615f9581 1508
8ff3fa2e 1509 mainLoop.registerEngine(&store_engine);
a774fd3f 1510
8ff3fa2e 1511 CommSelectEngine comm_engine;
1512
8ff3fa2e 1513 mainLoop.registerEngine(&comm_engine);
1514
bef81ea5 1515 mainLoop.setPrimaryEngine(&comm_engine);
1516
8ff3fa2e 1517 /* use the standard time service */
1518 TimeEngine time_engine;
1519
1520 mainLoop.setTimeService(&time_engine);
1521
7de94c8c 1522 if (IamCoordinatorProcess())
4299f876 1523 AsyncJob::Start(Ipc::Coordinator::Instance());
095ec2b1 1524 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
4299f876 1525 AsyncJob::Start(new Ipc::Strand);
10cefb7b 1526
48d54e4d
AJ
1527 /* at this point we are finished the synchronous startup. */
1528 starting_up = 0;
1529
8ff3fa2e 1530 mainLoop.run();
1531
1532 if (mainLoop.errcount == 10)
1533 fatal_dump("Event loop exited with failure.");
1534
1535 /* shutdown squid now */
1536 SquidShutdown();
62e76326 1537
9b7292ce 1538 /* NOTREACHED */
9b7292ce 1539 return 0;
090089c4 1540}
7690e8eb 1541
b8d8561b 1542static void
0673c0ba 1543sendSignal(void)
7690e8eb 1544{
ff8d0ea6 1545 pid_t pid;
fedac7e5 1546 debug_log = stderr;
258ac4d7 1547
1548 if (strcmp(Config.pidFilename, "none") == 0) {
bf8fe701 1549 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
258ac4d7 1550 }
1551
fedac7e5 1552 pid = readPidFile();
62e76326 1553
fedac7e5 1554 if (pid > 1) {
6c1962dd 1555#if USE_WIN32_SERVICE
1556
1557 if (opt_signal_service) {
1558 WIN32_sendSignal(opt_send_signal);
1559 exit(0);
1560 } else
1191b93b 1561#if _SQUID_MSWIN_
6c1962dd 1562 {
7dbca7a4 1563 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
6c1962dd 1564 fprintf(stderr, "signal to Squid Service:\n");
1565 fprintf(stderr, "missing -n command line switch.\n");
1566 exit(1);
1567 }
1568
1569 /* NOTREACHED */
1570#endif
1571
1572#endif
1573
62e76326 1574 if (kill(pid, opt_send_signal) &&
1575 /* ignore permissions if just running check */
1576 !(opt_send_signal == 0 && errno == EPERM)) {
7dbca7a4 1577 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
62e76326 1578 fprintf(stderr, "signal %d to process %d: %s\n",
1579 opt_send_signal, (int) pid, xstrerror());
1580 exit(1);
1581 }
fedac7e5 1582 } else {
205d7c3b 1583 if (opt_send_signal != SIGTERM) {
e08d498f 1584 fprintf(stderr, "%s: ERROR: No running copy\n", APP_SHORTNAME);
205d7c3b
AJ
1585 exit(1);
1586 } else {
e08d498f 1587 fprintf(stderr, "%s: No running copy\n", APP_SHORTNAME);
205d7c3b
AJ
1588 exit(0);
1589 }
7690e8eb 1590 }
62e76326 1591
fedac7e5 1592 /* signal successfully sent */
1593 exit(0);
1594}
f95b8144 1595
1191b93b 1596#if !_SQUID_MSWIN_
e18d7fdc 1597/*
1598 * This function is run when Squid is in daemon mode, just
1599 * before the parent forks and starts up the child process.
1600 * It can be used for admin-specific tasks, such as notifying
1601 * someone that Squid is (re)started.
1602 */
1603static void
1604mainStartScript(const char *prog)
1605{
ef364f64 1606 char script[MAXPATHLEN];
e18d7fdc 1607 char *t;
1608 size_t sl = 0;
1609 pid_t cpid;
1610 pid_t rpid;
1611 xstrncpy(script, prog, MAXPATHLEN);
62e76326 1612
e18d7fdc 1613 if ((t = strrchr(script, '/'))) {
62e76326 1614 *(++t) = '\0';
1615 sl = strlen(script);
e18d7fdc 1616 }
62e76326 1617
e18d7fdc 1618 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
62e76326 1619
e18d7fdc 1620 if ((cpid = fork()) == 0) {
62e76326 1621 /* child */
f75662c9 1622 execl(script, squid_start_script, (char *)NULL);
482aa790 1623 _exit(-1);
e18d7fdc 1624 } else {
62e76326 1625 do {
1191b93b 1626#if _SQUID_NEXT_
62e76326 1627 union wait status;
007d775d 1628 rpid = wait4(cpid, &status, 0, NULL);
e18d7fdc 1629#else
62e76326 1630
1631 int status;
007d775d 1632 rpid = waitpid(cpid, &status, 0);
e18d7fdc 1633#endif
62e76326 1634
1635 } while (rpid != cpid);
e18d7fdc 1636 }
1637}
1638
a50bfe93 1639#endif /* _SQUID_MSWIN_ */
1640
efd900cb 1641static int
1642checkRunningPid(void)
1643{
b81949b9 1644 // master process must start alone, but its kids processes may co-exist
7de94c8c 1645 if (!IamMasterProcess())
b81949b9
AR
1646 return 0;
1647
efd900cb 1648 pid_t pid;
e0077312 1649
1650 if (!debug_log)
1651 debug_log = stderr;
1652
efd900cb 1653 pid = readPidFile();
62e76326 1654
efd900cb 1655 if (pid < 2)
62e76326 1656 return 0;
1657
efd900cb 1658 if (kill(pid, 0) < 0)
62e76326 1659 return 0;
1660
cb7a4fcb 1661 debugs(0, 0, "Squid is already running! Process ID " << pid);
62e76326 1662
efd900cb 1663 return 1;
1664}
1665
f95b8144 1666static void
bbe199dc 1667watch_child(char *argv[])
f95b8144 1668{
1191b93b 1669#if !_SQUID_MSWIN_
f95b8144 1670 char *prog;
1191b93b 1671#if _SQUID_NEXT_
62e76326 1672
f95b8144 1673 union wait status;
1674#else
62e76326 1675
f95b8144 1676 int status;
1677#endif
62e76326 1678
e3a3b845 1679 pid_t pid;
c99c5397 1680#ifdef TIOCNOTTY
1681
54f742e7 1682 int i;
c99c5397 1683#endif
1684
742724a4 1685 int nullfd;
62e76326 1686
7de94c8c 1687 if (!IamMasterProcess())
62e76326 1688 return;
1689
7dbca7a4 1690 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1691
54f742e7 1692 if ((pid = fork()) < 0)
62e76326 1693 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
54f742e7 1694 else if (pid > 0)
62e76326 1695 exit(0);
1696
54f742e7 1697 if (setsid() < 0)
62e76326 1698 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1699
efd900cb 1700 closelog();
62e76326 1701
54f742e7 1702#ifdef TIOCNOTTY
62e76326 1703
c4aefe96 1704 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
62e76326 1705 ioctl(i, TIOCNOTTY, NULL);
1706 close(i);
54f742e7 1707 }
62e76326 1708
54f742e7 1709#endif
b05490a8 1710
7f6ffd15 1711 /*
1712 * RBCOLLINS - if cygwin stackdumps when squid is run without
1713 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1714 * 1.1.3. execvp had a bit overflow error in a loop..
1715 */
742724a4 1716 /* Connect stdio to /dev/null in daemon mode */
4da086c4 1717 nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
62e76326 1718
e4a1325e 1719 if (nullfd < 0)
4da086c4 1720 fatalf(_PATH_DEVNULL " %s\n", xstrerror());
e4a1325e 1721
742724a4 1722 dup2(nullfd, 0);
62e76326 1723
62493678 1724 if (Debug::log_stderr < 0) {
62e76326 1725 dup2(nullfd, 1);
1726 dup2(nullfd, 2);
742724a4 1727 }
62e76326 1728
ca4b9ee6
DK
1729 // handle shutdown notifications from kids
1730 squid_signal(SIGUSR1, sig_shutdown, SA_RESTART);
1731
13aeac35
AR
1732 if (Config.workers > 128) {
1733 syslog(LOG_ALERT, "Suspiciously high workers value: %d",
5667a628 1734 Config.workers);
007d775d 1735 // but we keep going in hope that user knows best
5667a628 1736 }
095ec2b1
AR
1737 TheKids.init();
1738
a2515f86 1739 syslog(LOG_NOTICE, "Squid Parent: will start %d kids", (int)TheKids.count());
007d775d
AR
1740
1741 // keep [re]starting kids until it is time to quit
f95b8144 1742 for (;;) {
62e76326 1743 mainStartScript(argv[0]);
1744
007d775d 1745 // start each kid that needs to be [re]started; once
10cefb7b 1746 for (int i = TheKids.count() - 1; i >= 0; --i) {
007d775d 1747 Kid& kid = TheKids.get(i);
ca4b9ee6 1748 if (!kid.shouldRestart())
007d775d
AR
1749 continue;
1750
1751 if ((pid = fork()) == 0) {
1752 /* child */
1753 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
bc91a636 1754 prog = argv[0];
007d775d
AR
1755 argv[0] = const_cast<char*>(kid.name().termedBuf());
1756 execvp(prog, argv);
1757 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1758 }
1759
1760 kid.start(pid);
095ec2b1
AR
1761 syslog(LOG_NOTICE, "Squid Parent: %s process %d started",
1762 kid.name().termedBuf(), pid);
62e76326 1763 }
1764
1765 /* parent */
7dbca7a4 1766 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1767
62e76326 1768 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1769
1191b93b 1770#if _SQUID_NEXT_
62e76326 1771
1772 pid = wait3(&status, 0, NULL);
1773
f95b8144 1774#else
62e76326 1775
1776 pid = waitpid(-1, &status, 0);
1777
007d775d 1778#endif
86b91dcd 1779 // Loop to collect all stopped kids before we go to sleep below.
5667a628 1780 do {
007d775d
AR
1781 Kid* kid = TheKids.find(pid);
1782 if (kid) {
1783 kid->stop(status);
1784 if (kid->calledExit()) {
1785 syslog(LOG_NOTICE,
095ec2b1
AR
1786 "Squid Parent: %s process %d exited with status %d",
1787 kid->name().termedBuf(),
5667a628 1788 kid->getPid(), kid->exitStatus());
007d775d
AR
1789 } else if (kid->signaled()) {
1790 syslog(LOG_NOTICE,
095ec2b1
AR
1791 "Squid Parent: %s process %d exited due to signal %d with status %d",
1792 kid->name().termedBuf(),
5667a628 1793 kid->getPid(), kid->termSignal(), kid->exitStatus());
007d775d 1794 } else {
095ec2b1
AR
1795 syslog(LOG_NOTICE, "Squid Parent: %s process %d exited",
1796 kid->name().termedBuf(), kid->getPid());
007d775d 1797 }
ca4b9ee6 1798 if (kid->hopeless()) {
1a98557c 1799 syslog(LOG_NOTICE, "Squid Parent: %s process %d will not"
ca4b9ee6 1800 " be restarted due to repeated, frequent failures",
1a98557c 1801 kid->name().termedBuf(), kid->getPid());
ca4b9ee6 1802 }
007d775d
AR
1803 } else {
1804 syslog(LOG_NOTICE, "Squid Parent: unknown child process %d exited", pid);
1805 }
1191b93b 1806#if _SQUID_NEXT_
007d775d
AR
1807 } while ((pid = wait3(&status, WNOHANG, NULL)) > 0);
1808#else
5667a628
AR
1809 }
1810 while ((pid = waitpid(-1, &status, WNOHANG)) > 0);
62e76326 1811#endif
1812
ca4b9ee6 1813 if (!TheKids.someRunning() && !TheKids.shouldRestartSome()) {
520e0073 1814 leave_suid();
c011f9bc 1815 DeactivateRegistered(rrAfterConfig);
520e0073 1816 enter_suid();
c011f9bc 1817
ca4b9ee6
DK
1818 if (TheKids.someSignaled(SIGINT) || TheKids.someSignaled(SIGTERM)) {
1819 syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
1820 exit(1);
1821 }
62e76326 1822
ca4b9ee6
DK
1823 if (TheKids.allHopeless()) {
1824 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1825 exit(1);
1826 }
62e76326 1827
007d775d
AR
1828 exit(0);
1829 }
06a0fbd3 1830
62e76326 1831 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1832 sleep(3);
f95b8144 1833 }
62e76326 1834
bbe199dc 1835 /* NOTREACHED */
a50bfe93 1836#endif /* _SQUID_MSWIN_ */
a572d8be 1837
f95b8144 1838}
fff6ad65 1839
9ec1a1dc 1840static void
8ff3fa2e 1841SquidShutdown()
fff6ad65 1842{
d71e4674
AR
1843 /* XXX: This function is called after the main loop has quit, which
1844 * means that no AsyncCalls would be called, including close handlers.
1845 * TODO: We need to close/shut/free everything that needs calls before
1846 * exiting the loop.
26ac0430 1847 */
d71e4674 1848
6c1962dd 1849#if USE_WIN32_SERVICE
1850 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1851#endif
1852
bf8fe701 1853 debugs(1, 1, "Shutting down...");
95a83c22 1854#if USE_DNSSERVERS
1855
1856 dnsShutdown();
1857#else
1858
1859 idnsShutdown();
1860#endif
95d2589c
CT
1861#if USE_SSL_CRTD
1862 Ssl::Helper::GetInstance()->Shutdown();
1863#endif
95a83c22 1864 redirectShutdown();
1865 externalAclShutdown();
d723bf6b 1866 icpConnectionClose();
1867#if USE_HTCP
62e76326 1868
d723bf6b 1869 htcpSocketClose();
1870#endif
59ad6d31 1871#if SQUID_SNMP
62e76326 1872
d723bf6b 1873 snmpConnectionClose();
320e9f36 1874#endif
eb824054 1875#if USE_WCCP
62e76326 1876
320e9f36 1877 wccpConnectionClose();
d723bf6b 1878#endif
0b0cfcf2 1879#if USE_WCCPv2
1880
1881 wccp2ConnectionClose();
1882#endif
62e76326 1883
fff6ad65 1884 releaseServerSockets();
d723bf6b 1885 commCloseAllSockets();
79039294
AR
1886
1887#if USE_SQUID_ESI
1888 Esi::Clean();
1889#endif
1890
9a0a18de 1891#if USE_DELAY_POOLS
b67e2c8c 1892 DelayPools::FreePools();
515ec4dc 1893#endif
2f1431ea 1894#if USE_AUTH
0bcb6908 1895 authenticateReset();
2f1431ea 1896#endif
6c1962dd 1897#if USE_WIN32_SERVICE
1898
1899 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1900#endif
62e76326 1901
c8f4eac4 1902 Store::Root().sync(); /* Flush pending object writes/unlinks */
4d075ba0 1903#if USE_UNLINKD
1904
1905 unlinkdClose(); /* after sync/flush */
1906#endif
fc68f6b1 1907
fff6ad65 1908 storeDirWriteCleanLogs(0);
1909 PrintRusage();
1910 dumpMallocStats();
c8f4eac4 1911 Store::Root().sync(); /* Flush log writes */
fff6ad65 1912 storeLogClose();
1913 accessLogClose();
c8f4eac4 1914 Store::Root().sync(); /* Flush log close */
59b2d47f 1915 StoreFileSystem::FreeAllFs();
b9ae18aa 1916 DiskIOModule::FreeAllModules();
c011f9bc 1917 DeactivateRegistered(rrAfterConfig);
afec404b 1918#if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
62e76326 1919
fff6ad65 1920 configFreeMemory();
1921 storeFreeMemory();
33ab18e8 1922 /*stmemFreeMemory(); */
fff6ad65 1923 netdbFreeMemory();
1924 ipcacheFreeMemory();
1925 fqdncacheFreeMemory();
1926 asnFreeMemory();
26a369ba 1927 clientdbFreeMemory();
7021844c 1928 httpHeaderCleanModule();
d2db411c 1929 statFreeMemory();
f1fc2a8d 1930 eventFreeMemory();
c68e9c6b 1931 mimeFreeMemory();
1932 errorClean();
fff6ad65 1933#endif
26a369ba 1934#if !XMALLOC_TRACE
62e76326 1935
54f742e7 1936 if (opt_no_daemon) {
62e76326 1937 file_close(0);
1938 file_close(1);
1939 file_close(2);
54f742e7 1940 }
62e76326 1941
33ab18e8 1942#endif
fff6ad65 1943 fdDumpOpen();
62e76326 1944
236d1779 1945 comm_exit();
62e76326 1946
ddb43c58 1947 memClean();
62e76326 1948
33ab18e8 1949#if XMALLOC_TRACE
62e76326 1950
26a369ba 1951 xmalloc_find_leaks();
62e76326 1952
bf8fe701 1953 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total);
62e76326 1954
33ab18e8 1955#endif
36a97e19 1956#if MEM_GEN_TRACE
62e76326 1957
399e85ea 1958 log_trace_done();
62e76326 1959
36a97e19 1960#endif
62e76326 1961
7de94c8c 1962 if (IamPrimaryProcess()) {
a2c48c98
AR
1963 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
1964 enter_suid();
1965 safeunlink(Config.pidFilename, 0);
1966 leave_suid();
1967 }
ab50ee9e 1968 }
62e76326 1969
bf8fe701 1970 debugs(1, 1, "Squid Cache (Version " << version_string << "): Exiting normally.");
62e76326 1971
0cfa98cb 1972 /*
1973 * DPW 2006-10-23
1974 * We used to fclose(debug_log) here if it was set, but then
1975 * we forgot to set it to NULL. That caused some coredumps
1976 * because exit() ends up calling a bunch of destructors and
1977 * such. So rather than forcing the debug_log to close, we'll
1978 * leave it open so that those destructors can write some
1979 * debugging if necessary. The file will be closed anyway when
1980 * the process truly exits.
1981 */
62e76326 1982
ae1feb30 1983 exit(shutdown_status);
fff6ad65 1984}
bef81ea5 1985