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