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