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