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