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