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