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