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