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