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