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