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