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