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