2 * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 01 Startup and Main Loop */
12 #include "AccessLogEntry.h"
13 //#include "acl/Acl.h"
15 #include "acl/forward.h"
16 #include "anyp/UriScheme.h"
17 #include "auth/Config.h"
18 #include "auth/Gadgets.h"
20 #include "base/RunnersRegistry.h"
21 #include "base/Subscription.h"
22 #include "base/TextException.h"
24 #include "CachePeer.h"
26 #include "client_db.h"
27 #include "client_side.h"
29 #include "CommandLine.h"
30 #include "ConfigParser.h"
31 #include "CpuAffinity.h"
32 #include "DiskIO/DiskIOModule.h"
33 #include "dns/forward.h"
34 #include "errorpage.h"
36 #include "EventLoop.h"
37 #include "ExternalACL.h"
39 #include "format/Token.h"
40 #include "fqdncache.h"
41 #include "fs/Module.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"
52 #include "ident/Ident.h"
55 #include "ipc/Coordinator.h"
57 #include "ipc/Strand.h"
60 #include "neighbors.h"
61 #include "parser/Tokenizer.h"
64 #include "peer_sourcehash.h"
65 #include "peer_userhash.h"
66 #include "PeerSelectState.h"
67 #include "profiler/Profiler.h"
70 #include "sbuf/Stream.h"
71 #include "SBufStatsAction.h"
72 #include "send-announce.h"
73 #include "SquidConfig.h"
74 #include "SquidTime.h"
76 #include "StatCounters.h"
78 #include "store/Disks.h"
79 #include "store_log.h"
80 #include "StoreFileSystem.h"
88 #include "adaptation/Config.h"
91 #include "adaptation/ecap/Config.h"
94 #include "adaptation/icap/Config.h"
95 #include "adaptation/icap/icap_log.h"
98 #include "ClientDelayConfig.h"
101 #include "DelayPools.h"
103 #if USE_LOADABLE_MODULES
104 #include "LoadableModules.h"
107 #include "ssl/context_storage.h"
108 #include "ssl/helper.h"
111 #include "adaptation/icap/Config.h"
114 #include "adaptation/ecap/Config.h"
117 #include "adaptation/Config.h"
120 #include "esi/Module.h"
123 #include "snmp_core.h"
134 #include <sys/wait.h>
137 #if USE_WIN32_SERVICE
140 static int opt_install_service
= FALSE
;
141 static int opt_remove_service
= FALSE
;
142 static int opt_command_line
= FALSE
;
143 void WIN32_svcstatusupdate(DWORD
, DWORD
);
144 void WINAPI
WIN32_svcHandler(DWORD
);
147 static int opt_signal_service
= FALSE
;
148 static char *opt_syslog_facility
= NULL
;
149 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
150 static int configured_once
= 0;
152 static int malloc_debug_level
= 0;
154 static volatile int do_reconfigure
= 0;
155 static volatile int do_rotate
= 0;
156 static volatile int do_shutdown
= 0;
157 static volatile int do_revive_kids
= 0;
158 static volatile int shutdown_status
= EXIT_SUCCESS
;
159 static volatile int do_handle_stopped_child
= 0;
161 static int RotateSignal
= -1;
162 static int ReconfigureSignal
= -1;
163 static int ShutdownSignal
= -1;
164 static int ReviveKidsSignal
= -1;
166 static void mainRotate(void);
167 static void mainReconfigureStart(void);
168 static void mainReconfigureFinish(void*);
169 static void mainInitialize(void);
170 static void usage(void);
171 static void mainHandleCommandLineOption(const int optId
, const char *optValue
);
172 static void sendSignal(void);
173 static void serverConnectionsOpen(void);
174 static void serverConnectionsClose(void);
175 static void watch_child(const CommandLine
&);
176 static void setEffectiveUser(void);
177 static void SquidShutdown(void);
178 static void mainSetCwd(void);
181 static const char *squid_start_script
= "squid_start";
185 #include "test_access.c"
188 /** temporary thunk across to the unrefactored store interface */
190 class StoreRootEngine
: public AsyncEngine
194 int checkEvents(int) {
195 Store::Root().callback();
200 class SignalEngine
: public AsyncEngine
205 SignalEngine(): parentKillNotified(false) {
206 parentPid
= getppid();
210 virtual int checkEvents(int timeout
);
213 static void StopEventLoop(void *) {
214 if (EventLoop::Running
)
215 EventLoop::Running
->stop();
218 static void FinalShutdownRunners(void *) {
219 RunRegisteredHere(RegisteredRunner::endingShutdown
);
221 // XXX: this should be a Runner.
223 /* detach the auth components (only do this on full shutdown) */
224 Auth::Scheme::FreeAll();
227 eventAdd("SquidTerminate", &StopEventLoop
, NULL
, 0, 1, false);
230 void doShutdown(time_t wait
);
231 void handleStoppedChild();
234 bool parentKillNotified
;
240 SignalEngine::checkEvents(int)
242 PROF_start(SignalEngine_checkEvents
);
245 mainReconfigureStart();
248 else if (do_shutdown
)
249 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
250 if (do_handle_stopped_child
)
251 handleStoppedChild();
252 PROF_stop(SignalEngine_checkEvents
);
256 /// Decides whether the signal-controlled action X should be delayed, canceled,
257 /// or executed immediately. Clears do_X (via signalVar) as needed.
259 AvoidSignalAction(const char *description
, volatile int &signalVar
)
261 const char *avoiding
= "delaying";
262 const char *currentEvent
= "none";
264 currentEvent
= "shutdown";
265 avoiding
= "canceling";
266 // do not avoid repeated shutdown signals
267 // which just means the user wants to skip/abort shutdown timeouts
268 if (strcmp(currentEvent
, description
) == 0)
272 else if (!configured_once
)
273 currentEvent
= "startup";
274 else if (reconfiguring
)
275 currentEvent
= "reconfiguration";
278 return false; // do not avoid (i.e., execute immediately)
279 // the caller may produce a signal-specific debugging message
282 debugs(1, DBG_IMPORTANT
, avoiding
<< ' ' << description
<<
283 " request during " << currentEvent
);
288 SignalEngine::doShutdown(time_t wait
)
290 if (AvoidSignalAction("shutdown", do_shutdown
))
293 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
294 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
297 if (!IamMasterProcess() && !parentKillNotified
&& ShutdownSignal
> 0 && parentPid
> 1) {
298 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << parentPid
);
299 if (kill(parentPid
, ShutdownSignal
) < 0) {
301 debugs(1, DBG_IMPORTANT
, "kill " << parentPid
<< ": " << xstrerr(xerrno
));
303 parentKillNotified
= true;
309 // Already a shutdown signal has received and shutdown is in progress.
310 // Shutdown as soon as possible.
316 /* run the closure code which can be shared with reconfigure */
317 serverConnectionsClose();
319 RunRegisteredHere(RegisteredRunner::startShutdown
);
322 #if USE_WIN32_SERVICE
323 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
326 eventAdd("SquidShutdown", &FinalShutdownRunners
, this, (double) (wait
+ 1), 1, false);
330 SignalEngine::handleStoppedChild()
332 // no AvoidSignalAction() call: This code can run at any time because it
333 // does not depend on Squid state. It does not need debugging because it
334 // handles an "internal" signal, not an external/admin command.
335 do_handle_stopped_child
= 0;
341 pid
= WaitForAnyPid(status
, WNOHANG
);
350 while (pid
> 0 || (pid
< 0 && errno
== EINTR
));
359 "Usage: %s [-cdzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
360 #if USE_WIN32_SERVICE
361 "[-ir] [-O CommandLine]"
364 " -h | --help Print help message.\n"
365 " -v | --version Print version details.\n"
367 " -a port Specify HTTP port number (default: %d).\n"
368 " -d level Write debugging to stderr also.\n"
369 " -f file Use given config-file instead of\n"
371 #if USE_WIN32_SERVICE
372 " -i Installs as a Windows Service (see -n option).\n"
374 " -k reconfigure|rotate|shutdown|"
378 "interrupt|kill|debug|check|parse\n"
379 " Parse configuration file, then send signal to \n"
380 " running copy (except -k parse) and exit.\n"
381 " -n name Specify service name to use for service operations\n"
382 " default is: " APP_SHORTNAME
".\n"
383 #if USE_WIN32_SERVICE
384 " -r Removes a Windows Service (see -n option).\n"
386 " -s | -l facility\n"
387 " Enable logging to syslog.\n"
388 " -u port Specify ICP port number (default: %d), disable with 0.\n"
389 " -z Create missing swap directories and then exit.\n"
390 " -C Do not catch fatal signals.\n"
391 " -D OBSOLETE. Scheduled for removal.\n"
392 " -F Don't serve any requests until store is rebuilt.\n"
393 " -N Master process runs in foreground and is a worker. No kids.\n"
395 " Master process runs in foreground and creates worker kids.\n"
397 " Play a given SMP kid process role, with a given ID. Do not use\n"
398 " this option. It is meant for the master process use only.\n"
399 #if USE_WIN32_SERVICE
401 " Set Windows Service Command line options in Registry.\n"
403 " -R Do not set REUSEADDR on port.\n"
404 " -S Double-check swap during rebuild.\n"
405 " -X Force full debugging.\n"
406 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
407 APP_SHORTNAME
, CACHE_HTTP_PORT
, DEFAULT_CONFIG_FILE
, CACHE_ICP_PORT
);
411 /// CommandLine option IDs for --long options that lack a short (-x) equivalent
413 // The absolute values do not matter except that the following values should
414 // not be used: Values below 2 are for special getopt_long(3) use cases, and
415 // values in the [33,126] range are reserved for short options (-x).
421 // TODO: consider prefixing with ':' for better logging
422 // (distinguish missing required argument cases)
423 static const char *shortOpStr
=
424 #if USE_WIN32_SERVICE
427 "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?";
430 static struct option squidOptions
[] = {
431 {"foreground", no_argument
, 0, optForeground
},
432 {"kid", required_argument
, 0, optKid
},
433 {"help", no_argument
, 0, 'h'},
434 {"version", no_argument
, 0, 'v'},
438 // handle a command line parameter
440 mainHandleCommandLineOption(const int optId
, const char *optValue
)
446 * Unset/disabel global option for catchign signals. opt_catch_signals */
447 opt_catch_signals
= 0;
452 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
453 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
458 * Set global option for foreground rebuild. opt_foreground_rebuild */
459 opt_foreground_rebuild
= 1;
464 * Set global option for 'no_daemon' mode. opt_no_daemon */
468 #if USE_WIN32_SERVICE
472 * Set global option. opt_command_lin and WIN32_Command_Line */
473 opt_command_line
= 1;
474 WIN32_Command_Line
= xstrdup(optValue
);
480 * Unset/disable global option opt_reuseaddr */
486 * Set global option opt_store_doublecheck */
487 opt_store_doublecheck
= 1;
492 * Force full debugging */
493 Debug::parseOptions("rotate=0 ALL,9");
494 Debug::override_X
= 1;
495 sigusr2_handle(SIGUSR2
);
500 * Set global option opt_reload_hit_only */
501 opt_reload_hit_only
= 1;
504 #if USE_WIN32_SERVICE
508 * Set global option opt_install_service (to TRUE) */
509 opt_install_service
= TRUE
;
516 * Add optional HTTP port as given following the option */
517 char *port
= xstrdup(optValue
);
518 // use a copy to avoid optValue modification
526 * Set global option Debug::log_stderr to the number given following the option */
527 Debug::log_stderr
= xatoi(optValue
);
532 * Load the file given instead of the default squid.conf. */
534 ConfigFile
= xstrdup(optValue
);
539 * Run the administrative action given following the option */
541 /** \li When it is missing or an unknown option display the usage help. */
542 if (!optValue
|| strlen(optValue
) < 1)
545 else if (!strncmp(optValue
, "reconfigure", strlen(optValue
)))
546 /** \li On reconfigure send SIGHUP. */
547 opt_send_signal
= SIGHUP
;
548 else if (!strncmp(optValue
, "rotate", strlen(optValue
)))
549 /** \li On rotate send SIGQUIT or SIGUSR1. */
550 #if defined(_SQUID_LINUX_THREADS_)
551 opt_send_signal
= SIGQUIT
;
553 opt_send_signal
= SIGUSR1
;
556 else if (!strncmp(optValue
, "debug", strlen(optValue
)))
557 /** \li On debug send SIGTRAP or SIGUSR2. */
558 #if defined(_SQUID_LINUX_THREADS_)
559 opt_send_signal
= SIGTRAP
;
561 opt_send_signal
= SIGUSR2
;
564 else if (!strncmp(optValue
, "shutdown", strlen(optValue
)))
565 /** \li On shutdown send SIGTERM. */
566 opt_send_signal
= SIGTERM
;
567 else if (!strncmp(optValue
, "interrupt", strlen(optValue
)))
568 /** \li On interrupt send SIGINT. */
569 opt_send_signal
= SIGINT
;
570 else if (!strncmp(optValue
, "kill", strlen(optValue
)))
571 /** \li On kill send SIGKILL. */
572 opt_send_signal
= SIGKILL
;
576 else if (!strncmp(optValue
, "restart", strlen(optValue
)))
577 /** \li On restart send SIGTTIN. (exit and restart by parent) */
578 opt_send_signal
= SIGTTIN
;
582 else if (!strncmp(optValue
, "check", strlen(optValue
)))
583 /** \li On check send 0 / SIGNULL. */
584 opt_send_signal
= 0; /* SIGNULL */
585 else if (!strncmp(optValue
, "parse", strlen(optValue
)))
586 /** \li On parse set global flag to re-parse the config file only. */
587 opt_parse_cfg_only
= 1;
595 * Set global malloc_debug_level to the value given following the option.
596 * if none is given it toggles the xmalloc_trace option on/off */
599 malloc_debug_level
= xatoi(optValue
);
601 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
609 * Set global option opt_signal_service (to true).
610 * Stores the additional parameter given in global service_name */
611 if (optValue
&& *optValue
!= '\0') {
612 const SBuf
t(optValue
);
613 ::Parser::Tokenizer
tok(t
);
614 const CharacterSet chr
= CharacterSet::ALPHA
+CharacterSet::DIGIT
;
615 if (!tok
.prefix(service_name
, chr
))
616 fatalf("Expected alphanumeric service name for the -n option but got: %s", optValue
);
618 fatalf("Garbage after alphanumeric service name in the -n option value: %s", optValue
);
619 if (service_name
.length() > 32)
620 fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name
.length());
621 opt_signal_service
= true;
623 fatal("A service name is required for the -n option");
627 #if USE_WIN32_SERVICE
631 * Set global option opt_remove_service (to TRUE) */
632 opt_remove_service
= TRUE
;
640 * Stores the syslog facility name in global opt_syslog_facility
641 * then performs actions for -s option. */
642 xfree(opt_syslog_facility
); // ignore any previous options sent
643 opt_syslog_facility
= xstrdup(optValue
);
647 * Initialize the syslog for output */
650 _db_set_syslog(opt_syslog_facility
);
656 fatal("Logging to syslog not available on this platform");
663 * Store the ICP port number given in global option icpPortNumOverride
664 * ensuring its a positive number. */
665 icpPortNumOverride
= atoi(optValue
);
667 if (icpPortNumOverride
< 0)
668 icpPortNumOverride
= 0;
674 * Display squid version and build information. Then exit. */
675 printf("Squid Cache: Version %s\n",version_string
);
676 printf("Service Name: " SQUIDSBUFPH
"\n", SQUIDSBUFPRINT(service_name
));
677 if (strlen(SQUID_BUILD_INFO
))
678 printf("%s\n",SQUID_BUILD_INFO
);
680 printf("\nThis binary uses %s. ", OpenSSL_version(OPENSSL_VERSION
));
681 printf("For legal restrictions on distribution see https://www.openssl.org/source/license.html\n\n");
683 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
685 #if USE_WIN32_SERVICE
687 printf("Compiled as Windows System Service.\n");
697 * Set global option Debug::log_stderr and opt_create_swap_dirs */
698 Debug::log_stderr
= 1;
699 opt_create_swap_dirs
= 1;
703 /** \par --foreground
704 * Set global option opt_foreground */
709 // already processed in ConfigureCurrentKid()
717 /** \par h,?, or unknown
718 * \copydoc usage() */
734 signal(sig
, rotate_logs
);
744 ReconfigureSignal
= sig
;
748 signal(sig
, reconfigure
);
754 master_revive_kids(int sig
)
756 ReviveKidsSignal
= sig
;
757 do_revive_kids
= true;
761 signal(sig
, master_revive_kids
);
766 /// Shutdown signal handler for master process
768 master_shutdown(int sig
)
771 ShutdownSignal
= sig
;
775 signal(sig
, master_shutdown
);
784 do_shutdown
= sig
== SIGINT
? -1 : 1;
785 ShutdownSignal
= sig
;
788 shutdown_status
= EXIT_FAILURE
;
793 signal(sig
, shut_down
);
801 do_handle_stopped_child
= 1;
805 signal(sig
, sig_child
);
811 serverConnectionsOpen(void)
813 if (IamPrimaryProcess()) {
815 wccpConnectionOpen();
820 wccp2ConnectionOpen();
823 // start various proxying services if we are responsible for them
824 if (IamWorkerProcess()) {
825 clientOpenListenSockets();
844 peerSourceHashInit();
849 serverConnectionsClose(void)
851 assert(shutting_down
|| reconfiguring
);
853 if (IamPrimaryProcess()) {
856 wccpConnectionClose();
860 wccp2ConnectionClose();
863 if (IamWorkerProcess()) {
864 clientConnectionsClose();
865 icpConnectionShutdown();
867 htcpSocketShutdown();
880 mainReconfigureStart(void)
882 if (AvoidSignalAction("reconfiguration", do_reconfigure
))
885 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
888 RunRegisteredHere(RegisteredRunner::startReconfigure
);
890 // Initiate asynchronous closing sequence
891 serverConnectionsClose();
897 Ssl::TheGlobalContextStorage
.reconfigureStart();
902 externalAclShutdown();
903 storeDirCloseSwapLogs();
910 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
915 mainReconfigureFinish(void *)
917 debugs(1, 3, "finishing reconfiguring");
920 enter_suid(); /* root to read config file */
922 // we may have disabled the need for PURGE
923 if (Config2
.onoff
.enable_purge
)
924 Config2
.onoff
.enable_purge
= 2;
926 // parse the config returns a count of errors encountered.
927 const int oldWorkers
= Config
.workers
;
929 if (parseConfigFile(ConfigFile
) != 0) {
930 // for now any errors are a fatal condition...
934 // for now any errors are a fatal condition...
935 debugs(1, DBG_CRITICAL
, "FATAL: Unhandled exception parsing config file. " <<
936 " Run squid -k parse and check for errors.");
940 if (oldWorkers
!= Config
.workers
) {
941 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
942 oldWorkers
<< " to " << Config
.workers
<<
943 ") requires a full restart. It has been ignored by reconfigure.");
944 Config
.workers
= oldWorkers
;
947 RunRegisteredHere(RegisteredRunner::syncConfig
);
949 if (IamPrimaryProcess())
951 CpuAffinityReconfigure();
953 setUmask(Config
.umask
);
956 _db_init(Debug::cache_log
, Debug::debugOptions
);
957 ipcache_restart(); /* clear stuck entries */
958 fqdncache_restart(); /* sigh, fqdncache too */
960 errorInitialize(); /* reload error pages */
963 #if USE_LOADABLE_MODULES
964 LoadableModulesConfigure(Config
.loadable_module_names
);
968 bool enableAdaptation
= false;
970 Adaptation::Icap::TheConfig
.finalize();
971 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
974 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
975 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
977 Adaptation::Config::Finalize(enableAdaptation
);
986 Ssl::Helper::Reconfigure();
989 Ssl::CertValidationHelper::Reconfigure();
992 redirectReconfigure();
994 authenticateInit(&Auth::TheConfig
.schemes
);
998 if (IamPrimaryProcess()) {
1009 serverConnectionsOpen();
1013 storeDirOpenSwapLogs();
1015 mimeInit(Config
.mimeTablePathname
);
1017 if (unlinkdNeeded())
1021 Config
.ClientDelay
.finalize();
1024 if (Config
.onoff
.announce
) {
1025 if (!eventFind(start_announce
, NULL
))
1026 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1028 if (eventFind(start_announce
, NULL
))
1029 eventDelete(start_announce
, NULL
);
1038 if (AvoidSignalAction("log rotation", do_rotate
))
1044 authenticateRotate();
1046 externalAclShutdown();
1048 _db_rotate_log(); /* cache.log */
1049 storeDirWriteCleanLogs(1);
1050 storeLogRotate(); /* store.log */
1051 accessLogRotate(); /* access.log */
1053 icapLogRotate(); /*icap.log*/
1058 authenticateInit(&Auth::TheConfig
.schemes
);
1064 setEffectiveUser(void)
1067 leave_suid(); /* Run as non privilegied user */
1073 if (geteuid() == 0) {
1074 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
1075 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
1076 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
1077 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
1078 fatal("Don't run Squid as root, set 'cache_effective_user'!");
1082 /// changes working directory, providing error reporting
1084 mainChangeDir(const char *dir
)
1086 if (chdir(dir
) == 0)
1090 debugs(50, DBG_CRITICAL
, "ERROR: cannot change current directory to " << dir
<<
1091 ": " << xstrerr(xerrno
));
1095 /// Hack: Have we called chroot()? This exposure is needed because some code has
1096 /// to open the same files before and after chroot()
1097 bool Chrooted
= false;
1099 /// set the working directory.
1103 if (Config
.chroot_dir
&& !Chrooted
) {
1106 if (chroot(Config
.chroot_dir
) != 0) {
1108 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerr(xerrno
));
1111 if (!mainChangeDir("/"))
1112 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
1115 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
1116 if (mainChangeDir(Config
.coredump_dir
)) {
1117 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
1122 /* If we don't have coredump_dir or couldn't cd there, report current dir */
1123 char pathbuf
[MAXPATHLEN
];
1124 if (getcwd(pathbuf
, MAXPATHLEN
)) {
1125 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
1128 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerr(xerrno
));
1133 mainInitialize(void)
1135 /* chroot if configured to run inside chroot */
1138 if (opt_catch_signals
) {
1139 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
1140 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
1143 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
1144 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
1145 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1149 if (icpPortNumOverride
!= 1)
1150 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
1152 _db_init(Debug::cache_log
, Debug::debugOptions
);
1154 // Do not register cache.log descriptor with Comm (for now).
1155 // See https://bugs.squid-cache.org/show_bug.cgi?id=4796
1156 // fd_open(fileno(debug_log), FD_LOG, Debug::cache_log);
1158 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1159 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1162 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1163 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1165 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1168 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1170 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1173 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1177 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1179 if (WIN32_Socks_initialized
)
1180 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1182 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1183 WIN32_IpAddrChangeMonitorInit();
1197 Ssl::Helper::Init();
1201 Ssl::CertValidationHelper::Init();
1206 authenticateInit(&Auth::TheConfig
.schemes
);
1210 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1231 malloc_debug(0, malloc_debug_level
);
1235 if (unlinkdNeeded())
1242 mimeInit(Config
.mimeTablePathname
);
1248 FwdState::initModule();
1249 /* register the modules in the cache manager menus */
1251 cbdataRegisterWithCacheManager();
1252 SBufStatsAction::RegisterWithCacheManager();
1254 /* These use separate calls so that the comm loops can eventually
1260 // TODO: pconn is a good candidate for new-style registration
1261 // PconnModule::GetInstance()->registerWithCacheManager();
1262 // moved to PconnModule::PconnModule()
1264 if (IamPrimaryProcess()) {
1276 serverConnectionsOpen();
1280 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1282 if (Config
.chroot_dir
)
1285 #if defined(_SQUID_LINUX_THREADS_)
1287 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1289 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1293 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1295 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1299 squid_signal(SIGTERM
, shut_down
, SA_RESTART
);
1301 squid_signal(SIGINT
, shut_down
, SA_RESTART
);
1305 squid_signal(SIGTTIN
, shut_down
, SA_RESTART
);
1311 #if USE_LOADABLE_MODULES
1312 LoadableModulesConfigure(Config
.loadable_module_names
);
1316 bool enableAdaptation
= false;
1318 // We can remove this dependency on specific adaptation mechanisms
1319 // if we create a generic Registry of such mechanisms. Should we?
1321 Adaptation::Icap::TheConfig
.finalize();
1322 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1325 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1326 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1328 // must be the last adaptation-related finalize
1329 Adaptation::Config::Finalize(enableAdaptation
);
1337 Config
.ClientDelay
.finalize();
1340 eventAdd("storeMaintain", Store::Maintain
, nullptr, 1.0, 1);
1342 if (Config
.onoff
.announce
)
1343 eventAdd("start_announce", start_announce
, nullptr, 3600.0, 1);
1345 eventAdd("ipcache_purgelru", ipcache_purgelru
, nullptr, 10.0, 1);
1347 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, nullptr, 15.0, 1);
1351 eventAdd("cpuProfiling", xprof_event
, nullptr, 1.0, 1);
1355 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, nullptr, 15.0, 1);
1357 configured_once
= 1;
1363 // ignore recursive calls to avoid termination loops
1364 static bool terminating
= false;
1369 debugs(1, DBG_CRITICAL
, "FATAL: Dying from an exception handling failure; exception: " << CurrentException
);
1373 /// unsafe main routine -- may throw
1374 int SquidMain(int argc
, char **argv
);
1375 /// unsafe main routine wrapper to catch exceptions
1376 static int SquidMainSafe(int argc
, char **argv
);
1378 #if USE_WIN32_SERVICE
1379 /* Entry point for Windows services */
1380 extern "C" void WINAPI
1381 SquidWinSvcMain(int argc
, char **argv
)
1383 SquidMainSafe(argc
, argv
);
1388 main(int argc
, char **argv
)
1390 #if USE_WIN32_SERVICE
1391 SetErrorMode(SEM_NOGPFAULTERRORBOX
);
1392 if ((argc
== 2) && strstr(argv
[1], _WIN_SQUID_SERVICE_OPTION
))
1393 return WIN32_StartService(argc
, argv
);
1395 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_INTERACTIVE
;
1400 return SquidMainSafe(argc
, argv
);
1404 SquidMainSafe(int argc
, char **argv
)
1406 (void)std::set_terminate(&OnTerminate
);
1407 // XXX: This top-level catch works great for startup, but, during runtime,
1408 // it erases valuable stack info. TODO: Let stack-preserving OnTerminate()
1409 // handle FATAL runtime errors by splitting main code into protected
1410 // startup, unprotected runtime, and protected termination sections!
1412 return SquidMain(argc
, argv
);
1414 debugs(1, DBG_CRITICAL
, "FATAL: " << CurrentException
);
1416 return EXIT_FAILURE
;
1419 /// computes name and ID for the current kid process
1421 ConfigureCurrentKid(const CommandLine
&cmdLine
)
1423 const char *kidParams
= nullptr;
1424 if (cmdLine
.hasOption(optKid
, &kidParams
)) {
1425 SBuf
processName(kidParams
);
1427 Parser::Tokenizer
tok(processName
);
1428 tok
.suffix(kidId
, CharacterSet::DIGIT
);
1429 KidIdentifier
= xatoi(kidId
.c_str());
1430 tok
.skipSuffix(SBuf("-"));
1431 TheKidName
= tok
.remaining();
1432 if (TheKidName
.cmp("squid-coord") == 0)
1433 TheProcessKind
= pkCoordinator
;
1434 else if (TheKidName
.cmp("squid") == 0)
1435 TheProcessKind
= pkWorker
;
1436 else if (TheKidName
.cmp("squid-disk") == 0)
1437 TheProcessKind
= pkDisker
;
1439 TheProcessKind
= pkOther
; // including coordinator
1441 TheKidName
.assign(APP_SHORTNAME
);
1446 static void StartUsingConfig()
1448 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1449 RunRegisteredHere(RegisteredRunner::useConfig
);
1453 SquidMain(int argc
, char **argv
)
1455 const CommandLine
cmdLine(argc
, argv
, shortOpStr
, squidOptions
);
1457 ConfigureCurrentKid(cmdLine
);
1459 Debug::parseOptions(NULL
);
1461 #if defined(SQUID_MAXFD_LIMIT)
1463 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1464 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1468 /* NOP under non-windows */
1469 int WIN32_init_err
=0;
1470 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1471 return WIN32_init_err
;
1473 /* call mallopt() before anything else */
1476 /* Round up all sizes to a multiple of this */
1477 mallopt(M_GRAIN
, 16);
1481 /* biggest size that is considered a small block */
1482 mallopt(M_MXFAST
, 256);
1486 /* allocate this many small blocks at once */
1487 mallopt(M_NLBLKS
, 32);
1490 #endif /* HAVE_MALLOPT */
1494 squid_start
= current_time
;
1496 failure_notify
= fatal_dump
;
1498 #if USE_WIN32_SERVICE
1500 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1504 cmdLine
.forEachOption(mainHandleCommandLineOption
);
1506 if (opt_foreground
&& opt_no_daemon
) {
1507 debugs(1, DBG_CRITICAL
, "WARNING: --foreground command-line option has no effect with -N.");
1510 if (opt_parse_cfg_only
) {
1511 Debug::parseOptions("ALL,1");
1514 #if USE_WIN32_SERVICE
1516 if (opt_install_service
) {
1517 WIN32_InstallService();
1521 if (opt_remove_service
) {
1522 WIN32_RemoveService();
1526 if (opt_command_line
) {
1527 WIN32_SetServiceCommandLine();
1533 /* parse configuration file
1534 * note: in "normal" case this used to be called from mainInitialize() */
1539 ConfigFile
= xstrdup(DEFAULT_CONFIG_FILE
);
1541 assert(!configured_once
);
1545 AnyP::UriScheme::Init();
1547 storeFsInit(); /* required for config parsing */
1549 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1552 /* May not be needed for parsing, have not audited for such */
1553 DiskIOModule::SetupAllModules();
1555 /* Shouldn't be needed for config parsing, but have not audited for such */
1556 StoreFileSystem::SetupAllFs();
1558 /* we may want the parsing process to set this up in the future */
1561 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1562 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1564 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1567 parse_err
= parseConfigFile(ConfigFile
);
1569 // for now any errors are a fatal condition...
1570 debugs(1, DBG_CRITICAL
, "FATAL: Unhandled exception parsing config file." <<
1571 (opt_parse_cfg_only
? " Run squid -k parse and check for errors." : ""));
1577 if (opt_parse_cfg_only
|| parse_err
> 0)
1580 setUmask(Config
.umask
);
1582 // Master optimization: Where possible, avoid pointless daemon fork() and/or
1583 // pointless wait for the exclusive PID file lock. This optional/weak check
1584 // is not applicable to kids because they always co-exist with their master.
1585 if (opt_send_signal
== -1 && IamMasterProcess())
1586 Instance::ThrowIfAlreadyRunning();
1600 /* send signal to running copy and exit */
1601 if (opt_send_signal
!= -1) {
1602 /* chroot if configured to run inside chroot */
1604 if (Config
.chroot_dir
) {
1614 debugs(1,2, "Doing post-config initialization");
1616 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1618 if (IamMasterProcess()) {
1619 if (InDaemonMode()) {
1620 watch_child(cmdLine
);
1623 Instance::WriteOurPid();
1630 if (opt_create_swap_dirs
) {
1631 /* chroot if configured to run inside chroot */
1635 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1636 Store::Root().create();
1641 if (IamPrimaryProcess())
1647 /* init comm module */
1650 if (opt_no_daemon
) {
1651 /* we have to init fdstat here. */
1652 fd_open(0, FD_LOG
, "stdin");
1653 fd_open(1, FD_LOG
, "stdout");
1654 fd_open(2, FD_LOG
, "stderr");
1657 #if USE_WIN32_SERVICE
1659 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1665 #if USE_WIN32_SERVICE
1667 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1674 SignalEngine signalEngine
;
1676 mainLoop
.registerEngine(&signalEngine
);
1678 /* TODO: stop requiring the singleton here */
1679 mainLoop
.registerEngine(EventScheduler::GetInstance());
1681 StoreRootEngine store_engine
;
1683 mainLoop
.registerEngine(&store_engine
);
1685 CommSelectEngine comm_engine
;
1687 mainLoop
.registerEngine(&comm_engine
);
1689 mainLoop
.setPrimaryEngine(&comm_engine
);
1691 /* use the standard time service */
1692 TimeEngine time_engine
;
1694 mainLoop
.setTimeService(&time_engine
);
1696 if (IamCoordinatorProcess())
1697 AsyncJob::Start(Ipc::Coordinator::Instance());
1698 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1699 AsyncJob::Start(new Ipc::Strand
);
1701 /* at this point we are finished the synchronous startup. */
1706 if (mainLoop
.errcount
== 10)
1707 fatal_dump("Event loop exited with failure.");
1709 /* shutdown squid now */
1719 StopUsingDebugLog();
1721 #if USE_WIN32_SERVICE
1722 // WIN32_sendSignal() does not need the PID value to signal,
1723 // but we must exit if there is no valid PID (TODO: Why?).
1724 (void)Instance::Other();
1725 if (!opt_signal_service
)
1726 throw TexcHere("missing -n command line switch");
1727 WIN32_sendSignal(opt_send_signal
);
1729 const auto pid
= Instance::Other();
1730 if (kill(pid
, opt_send_signal
) &&
1731 /* ignore permissions if just running check */
1732 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1733 const auto savedErrno
= errno
;
1734 throw TexcHere(ToSBuf("failed to send signal ", opt_send_signal
,
1735 " to Squid instance with PID ", pid
, ": ", xstrerr(savedErrno
)));
1738 /* signal successfully sent */
1741 #if !_SQUID_WINDOWS_
1743 * This function is run when Squid is in daemon mode, just
1744 * before the parent forks and starts up the child process.
1745 * It can be used for admin-specific tasks, such as notifying
1746 * someone that Squid is (re)started.
1749 mainStartScript(const char *prog
)
1751 char script
[MAXPATHLEN
];
1756 xstrncpy(script
, prog
, MAXPATHLEN
);
1758 if ((t
= strrchr(script
, '/'))) {
1760 sl
= strlen(script
);
1763 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1765 if ((cpid
= fork()) == 0) {
1767 execl(script
, squid_start_script
, (char *)NULL
);
1772 rpid
= WaitForOnePid(cpid
, status
, 0);
1773 } while (rpid
!= cpid
);
1777 /// Initiates shutdown sequence. Shutdown ends when the last running kids stops.
1779 masterShutdownStart()
1781 if (AvoidSignalAction("shutdown", do_shutdown
))
1783 debugs(1, 2, "received shutdown command");
1787 /// Initiates reconfiguration sequence. See also: masterReconfigureFinish().
1789 masterReconfigureStart()
1791 if (AvoidSignalAction("reconfiguration", do_reconfigure
))
1793 debugs(1, 2, "received reconfiguration command");
1795 TheKids
.forgetAllFailures();
1796 // TODO: hot-reconfiguration of the number of kids, kids revival delay,
1797 // PID file location, etc.
1800 /// Ends reconfiguration sequence started by masterReconfigureStart().
1802 masterReconfigureFinish()
1807 /// Reacts to the kid revival alarm.
1811 if (AvoidSignalAction("kids revival", do_revive_kids
))
1813 debugs(1, 2, "woke up after ~" << Config
.hopelessKidRevivalDelay
<< "s");
1814 // nothing to do here -- actual revival happens elsewhere in the main loop
1815 // the alarm was needed just to wake us up so that we do a loop iteration
1819 masterCheckAndBroadcastSignals()
1822 masterShutdownStart();
1824 masterReconfigureStart();
1828 // emulate multi-step reconfiguration assumed by AvoidSignalAction()
1830 masterReconfigureFinish();
1832 BroadcastSignalIfAny(DebugSignal
);
1833 BroadcastSignalIfAny(RotateSignal
);
1834 BroadcastSignalIfAny(ReconfigureSignal
);
1835 BroadcastSignalIfAny(ShutdownSignal
);
1836 ReviveKidsSignal
= -1; // alarms are not broadcasted
1839 /// Maintains the following invariant: An alarm should be scheduled when and
1840 /// only when there are hopeless kid(s) that cannot be immediately revived.
1842 masterMaintainKidRevivalSchedule()
1844 const auto nextCheckDelay
= TheKids
.forgetOldFailures();
1845 assert(nextCheckDelay
>= 0);
1846 (void)alarm(static_cast<unsigned int>(nextCheckDelay
)); // resets or cancels
1848 debugs(1, 2, "will recheck hopeless kids in " << nextCheckDelay
<< " seconds");
1854 return (DebugSignal
> 0 || RotateSignal
> 0 || ReconfigureSignal
> 0 ||
1855 ShutdownSignal
> 0 || ReviveKidsSignal
> 0);
1858 /// makes the caller a daemon process running in the background
1863 if ((pid
= fork()) < 0) {
1865 throw TexcHere(ToSBuf("failed to fork(2) the master process: ", xstrerr(xerrno
)));
1866 } else if (pid
> 0) {
1870 // child, running as a background daemon
1871 Must(setsid() > 0); // ought to succeed after fork()
1877 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1878 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1882 if (TheKids
.allHopeless()) {
1883 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1890 #endif /* !_SQUID_WINDOWS_ */
1893 watch_child(const CommandLine
&masterCommand
)
1895 #if !_SQUID_WINDOWS_
1904 // TODO: zero values are not supported because they result in
1905 // misconfigured SMP Squid instances running forever, endlessly
1906 // restarting each dying kid.
1907 if (Config
.hopelessKidRevivalDelay
<= 0)
1908 throw TexcHere("hopeless_kid_revival_delay must be positive");
1912 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1914 if (!opt_foreground
)
1921 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1922 ioctl(i
, TIOCNOTTY
, NULL
);
1929 * RBCOLLINS - if cygwin stackdumps when squid is run without
1930 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1931 * 1.1.3. execvp had a bit overflow error in a loop..
1933 /* Connect stdio to /dev/null in daemon mode */
1934 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1938 fatalf(_PATH_DEVNULL
" %s\n", xstrerr(xerrno
));
1943 if (Debug::log_stderr
< 0) {
1949 Instance::WriteOurPid();
1953 #if defined(_SQUID_LINUX_THREADS_)
1954 squid_signal(SIGQUIT
, rotate_logs
, 0);
1955 squid_signal(SIGTRAP
, sigusr2_handle
, 0);
1957 squid_signal(SIGUSR1
, rotate_logs
, 0);
1958 squid_signal(SIGUSR2
, sigusr2_handle
, 0);
1961 squid_signal(SIGHUP
, reconfigure
, 0);
1963 squid_signal(SIGTERM
, master_shutdown
, 0);
1964 squid_signal(SIGALRM
, master_revive_kids
, 0);
1965 squid_signal(SIGINT
, master_shutdown
, 0);
1967 squid_signal(SIGTTIN
, master_shutdown
, 0);
1970 if (Config
.workers
> 128) {
1971 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1973 // but we keep going in hope that user knows best
1977 configured_once
= 1;
1979 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1981 // keep [re]starting kids until it is time to quit
1983 bool mainStartScriptCalled
= false;
1984 // start each kid that needs to be [re]started; once
1985 for (int i
= TheKids
.count() - 1; i
>= 0 && !shutting_down
; --i
) {
1986 Kid
& kid
= TheKids
.get(i
);
1987 if (!kid
.shouldRestart())
1990 if (!mainStartScriptCalled
) {
1991 mainStartScript(masterCommand
.arg0());
1992 mainStartScriptCalled
= true;
1995 // These are only needed by the forked child below, but let's keep
1996 // them out of that "no man's land" between fork() and execvp().
1997 auto kidCommand
= masterCommand
;
1998 kidCommand
.resetArg0(kid
.processName().c_str());
1999 assert(!kidCommand
.hasOption(optKid
));
2000 kidCommand
.pushFrontOption("--kid", kid
.gist().c_str());
2002 if ((pid
= fork()) == 0) {
2004 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
2005 (void)execvp(masterCommand
.arg0(), kidCommand
.argv());
2007 syslog(LOG_ALERT
, "execvp failed: %s", xstrerr(xerrno
));
2011 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
2012 kid
.processName().c_str(), pid
);
2016 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
2018 // If Squid received a signal while checking for dying kids (below) or
2019 // starting new kids (above), then do a fast check for a new dying kid
2020 // (WaitForAnyPid with the WNOHANG option) and continue to forward
2021 // signals to kids. Otherwise, wait for a kid to die or for a signal
2022 // to abort the blocking WaitForAnyPid() call.
2023 // With the WNOHANG option, we could check whether WaitForAnyPid() was
2024 // aborted by a dying kid or a signal, but it is not required: The
2025 // next do/while loop will check again for any dying kids.
2027 if (masterSignaled())
2030 pid
= WaitForAnyPid(status
, waitFlag
);
2033 // check for a stopped kid
2034 if (Kid
*kid
= pid
> 0 ? TheKids
.find(pid
) : nullptr)
2037 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
2039 masterCheckAndBroadcastSignals();
2040 masterMaintainKidRevivalSchedule();
2042 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
2044 // XXX: Master process has no main loop and, hence, should not call
2045 // RegisteredRunner::startShutdown which promises a loop iteration.
2046 RunRegisteredHere(RegisteredRunner::finishShutdown
);
2053 #endif /* _SQUID_WINDOWS_ */
2060 /* XXX: This function is called after the main loop has quit, which
2061 * means that no AsyncCalls would be called, including close handlers.
2062 * TODO: We need to close/shut/free everything that needs calls before
2066 #if USE_WIN32_SERVICE
2067 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
2070 debugs(1, DBG_IMPORTANT
, "Shutting down...");
2072 Ssl::Helper::Shutdown();
2075 Ssl::CertValidationHelper::Shutdown();
2078 externalAclShutdown();
2088 wccpConnectionClose();
2092 wccp2ConnectionClose();
2095 releaseServerSockets();
2096 commCloseAllSockets();
2103 DelayPools::FreePools();
2106 authenticateReset();
2108 #if USE_WIN32_SERVICE
2110 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
2113 Adaptation::Icap::TheConfig
.freeService();
2116 Store::Root().sync(); /* Flush pending object writes/unlinks */
2118 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
2120 storeDirWriteCleanLogs(0);
2123 Store::Root().sync(); /* Flush log writes */
2126 Store::Root().sync(); /* Flush log close */
2127 StoreFileSystem::FreeAllFs();
2128 DiskIOModule::FreeAllModules();
2129 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
2133 /*stmemFreeMemory(); */
2135 ipcacheFreeMemory();
2136 fqdncacheFreeMemory();
2138 clientdbFreeMemory();
2144 Store::FreeMemory();
2150 RunRegisteredHere(RegisteredRunner::finishShutdown
);
2154 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
2158 * We used to fclose(debug_log) here if it was set, but then
2159 * we forgot to set it to NULL. That caused some coredumps
2160 * because exit() ends up calling a bunch of destructors and
2161 * such. So rather than forcing the debug_log to close, we'll
2162 * leave it open so that those destructors can write some
2163 * debugging if necessary. The file will be closed anyway when
2164 * the process truly exits.
2167 exit(shutdown_status
);