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