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