2 * DEBUG: section 01 Startup and Main Loop
3 * AUTHOR: Harvest Derived
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "AccessLogEntry.h"
38 #include "base/RunnersRegistry.h"
39 #include "base/Subscription.h"
40 #include "base/TextException.h"
43 #include "client_db.h"
44 #include "client_side.h"
46 #include "ConfigParser.h"
47 #include "CpuAffinity.h"
49 #include "DiskIO/DiskIOModule.h"
50 #include "errorpage.h"
52 #include "EventLoop.h"
53 #include "ExternalACL.h"
55 #include "format/Token.h"
56 #include "fqdncache.h"
57 #include "fs/Module.h"
61 #include "HttpHeader.h"
62 #include "HttpReply.h"
63 #include "icmp/IcmpSquid.h"
64 #include "icmp/net_db.h"
66 #include "ident/Ident.h"
68 #include "ipc/Coordinator.h"
70 #include "ipc/Strand.h"
75 #include "neighbors.h"
77 #include "peer_sourcehash.h"
78 #include "peer_userhash.h"
79 #include "PeerSelectState.h"
80 #include "profiler/Profiler.h"
83 #include "send-announce.h"
84 #include "SquidConfig.h"
86 #include "SquidTime.h"
88 #include "StatCounters.h"
90 #include "store_log.h"
91 #include "StoreFileSystem.h"
101 #include "adaptation/Config.h"
104 #include "adaptation/ecap/Config.h"
107 #include "adaptation/icap/Config.h"
108 #include "adaptation/icap/icap_log.h"
111 #include "auth/Gadgets.h"
114 #include "ClientDelayConfig.h"
117 #include "DelayPools.h"
119 #if USE_LOADABLE_MODULES
120 #include "LoadableModules.h"
123 #include "ssl/certificate_db.h"
126 #include "ssl/context_storage.h"
127 #include "ssl/helper.h"
130 #include "adaptation/icap/Config.h"
133 #include "adaptation/ecap/Config.h"
136 #include "adaptation/Config.h"
139 #include "esi/Module.h"
142 #include "snmp_core.h"
149 #include <sys/wait.h>
155 #if USE_WIN32_SERVICE
158 static int opt_install_service
= FALSE
;
159 static int opt_remove_service
= FALSE
;
160 static int opt_signal_service
= FALSE
;
161 static int opt_command_line
= FALSE
;
162 void WIN32_svcstatusupdate(DWORD
, DWORD
);
163 void WINAPI
WIN32_svcHandler(DWORD
);
166 static char *opt_syslog_facility
= NULL
;
167 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
168 static int configured_once
= 0;
170 static int malloc_debug_level
= 0;
172 static volatile int do_reconfigure
= 0;
173 static volatile int do_rotate
= 0;
174 static volatile int do_shutdown
= 0;
175 static volatile int shutdown_status
= 0;
177 static int RotateSignal
= -1;
178 static int ReconfigureSignal
= -1;
179 static int ShutdownSignal
= -1;
181 static void mainRotate(void);
182 static void mainReconfigureStart(void);
183 static void mainReconfigureFinish(void*);
184 static void mainInitialize(void);
185 static void usage(void);
186 static void mainParseOptions(int argc
, char *argv
[]);
187 static void sendSignal(void);
188 static void serverConnectionsOpen(void);
189 static void serverConnectionsClose(void);
190 static void watch_child(char **);
191 static void setEffectiveUser(void);
193 void log_trace_done();
194 void log_trace_init(char *);
196 static void SquidShutdown(void);
197 static void mainSetCwd(void);
198 static int checkRunningPid(void);
201 static const char *squid_start_script
= "squid_start";
205 #include "test_access.c"
208 /** temporary thunk across to the unrefactored store interface */
210 class StoreRootEngine
: public AsyncEngine
214 int checkEvents(int timeout
) {
215 Store::Root().callback();
220 class SignalEngine
: public AsyncEngine
224 virtual int checkEvents(int timeout
);
227 static void StopEventLoop(void *) {
228 if (EventLoop::Running
)
229 EventLoop::Running
->stop();
232 void doShutdown(time_t wait
);
236 SignalEngine::checkEvents(int timeout
)
238 PROF_start(SignalEngine_checkEvents
);
240 if (do_reconfigure
) {
241 mainReconfigureStart();
243 } else if (do_rotate
) {
246 } else if (do_shutdown
) {
247 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
250 BroadcastSignalIfAny(DebugSignal
);
251 BroadcastSignalIfAny(RotateSignal
);
252 BroadcastSignalIfAny(ReconfigureSignal
);
253 BroadcastSignalIfAny(ShutdownSignal
);
255 PROF_stop(SignalEngine_checkEvents
);
260 SignalEngine::doShutdown(time_t wait
)
262 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
263 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
267 #if USE_WIN32_SERVICE
268 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
271 /* run the closure code which can be shared with reconfigure */
272 serverConnectionsClose();
274 /* detach the auth components (only do this on full shutdown) */
275 Auth::Scheme::FreeAll();
277 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
284 #if USE_WIN32_SERVICE
285 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
287 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
289 " -a port Specify HTTP port number (default: %d).\n"
290 " -d level Write debugging to stderr also.\n"
291 " -f file Use given config-file instead of\n"
293 " -h Print help message.\n"
294 #if USE_WIN32_SERVICE
295 " -i Installs as a Windows Service (see -n option).\n"
297 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
298 " Parse configuration file, then send signal to \n"
299 " running copy (except -k parse) and exit.\n"
300 #if USE_WIN32_SERVICE
301 " -n name Specify Windows Service name to use for service operations\n"
302 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
303 " -r Removes a Windows Service (see -n option).\n"
305 " -s | -l facility\n"
306 " Enable logging to syslog.\n"
307 " -u port Specify ICP port number (default: %d), disable with 0.\n"
308 " -v Print version.\n"
309 " -z Create missing swap directories and then exit.\n"
310 " -C Do not catch fatal signals.\n"
311 " -D OBSOLETE. Scheduled for removal.\n"
312 " -F Don't serve any requests until store is rebuilt.\n"
313 " -N No daemon mode.\n"
314 #if USE_WIN32_SERVICE
316 " Set Windows Service Command line options in Registry.\n"
318 " -R Do not set REUSEADDR on port.\n"
319 " -S Double-check swap during rebuild.\n"
320 " -X Force full debugging.\n"
321 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
322 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
327 * Parse the parameters received via command line interface.
329 \param argc Number of options received on command line
330 \param argv List of parameters received on command line
333 mainParseOptions(int argc
, char *argv
[])
338 #if USE_WIN32_SERVICE
339 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
341 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
349 * Unset/disabel global option for catchign signals. opt_catch_signals */
350 opt_catch_signals
= 0;
355 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
356 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
361 * Set global option for foreground rebuild. opt_foreground_rebuild */
362 opt_foreground_rebuild
= 1;
367 * Set global option for 'no_daemon' mode. opt_no_daemon */
371 #if USE_WIN32_SERVICE
375 * Set global option. opt_command_lin and WIN32_Command_Line */
376 opt_command_line
= 1;
377 WIN32_Command_Line
= xstrdup(optarg
);
383 * Unset/disable global option opt_reuseaddr */
389 * Set global option opt_store_doublecheck */
390 opt_store_doublecheck
= 1;
395 * Force full debugging */
396 Debug::parseOptions("rotate=0 ALL,9");
397 Debug::override_X
= 1;
398 sigusr2_handle(SIGUSR2
);
403 * Set global option opt_reload_hit_only */
404 opt_reload_hit_only
= 1;
407 #if USE_WIN32_SERVICE
411 * Set global option opt_install_service (to TRUE) */
412 opt_install_service
= TRUE
;
418 * Add optional HTTP port as given following the option */
419 add_http_port(optarg
);
424 * Set global option Debug::log_stderr to the number given follwoign the option */
425 Debug::log_stderr
= atoi(optarg
);
430 * Load the file given instead of the default squid.conf. */
432 ConfigFile
= xstrdup(optarg
);
437 * Run the administrative action given following the option */
439 /** \li When its an unknown option display the usage help. */
440 if ((int) strlen(optarg
) < 1)
443 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
444 /** \li On reconfigure send SIGHUP. */
445 opt_send_signal
= SIGHUP
;
446 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
447 /** \li On rotate send SIGQUIT or SIGUSR1. */
448 #if defined(_SQUID_LINUX_THREADS_)
449 opt_send_signal
= SIGQUIT
;
451 opt_send_signal
= SIGUSR1
;
454 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
455 /** \li On debug send SIGTRAP or SIGUSR2. */
456 #if defined(_SQUID_LINUX_THREADS_)
457 opt_send_signal
= SIGTRAP
;
459 opt_send_signal
= SIGUSR2
;
462 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
463 /** \li On shutdown send SIGTERM. */
464 opt_send_signal
= SIGTERM
;
465 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
466 /** \li On interrupt send SIGINT. */
467 opt_send_signal
= SIGINT
;
468 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
469 /** \li On kill send SIGKILL. */
470 opt_send_signal
= SIGKILL
;
474 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
475 /** \li On restart send SIGTTIN. (exit and restart by parent) */
476 opt_send_signal
= SIGTTIN
;
480 else if (!strncmp(optarg
, "check", strlen(optarg
)))
481 /** \li On check send 0 / SIGNULL. */
482 opt_send_signal
= 0; /* SIGNULL */
483 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
484 /** \li On parse set global flag to re-parse the config file only. */
485 opt_parse_cfg_only
= 1;
493 * Set global malloc_debug_level to the value given following the option.
494 * if none is given it toggles the xmalloc_trace option on/off */
497 malloc_debug_level
= atoi(optarg
);
499 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
504 xmalloc_trace
= !xmalloc_trace
;
506 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
511 #if USE_WIN32_SERVICE
515 * Set global option opt_signal_service (to TRUE).
516 * Stores the additional parameter given in global WIN32_Service_name */
517 xfree(WIN32_Service_name
);
519 WIN32_Service_name
= xstrdup(optarg
);
521 opt_signal_service
= TRUE
;
527 * Set global option opt_remove_service (to TRUE) */
528 opt_remove_service
= TRUE
;
536 * Stores the syslog facility name in global opt_syslog_facility
537 * then performs actions for -s option. */
538 xfree(opt_syslog_facility
); // ignore any previous options sent
539 opt_syslog_facility
= xstrdup(optarg
);
543 * Initialize the syslog for output */
546 _db_set_syslog(opt_syslog_facility
);
552 fatal("Logging to syslog not available on this platform");
559 * Store the ICP port number given in global option icpPortNumOverride
560 * ensuring its a positive number. */
561 icpPortNumOverride
= atoi(optarg
);
563 if (icpPortNumOverride
< 0)
564 icpPortNumOverride
= 0;
570 * Display squid version and build information. Then exit. */
571 printf("Squid Cache: Version %s\n" ,version_string
);
572 if (strlen(SQUID_BUILD_INFO
))
573 printf("%s\n",SQUID_BUILD_INFO
);
574 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
576 #if USE_WIN32_SERVICE
578 printf("Compiled as Windows System Service.\n");
588 * Set global option Debug::log_stderr and opt_create_swap_dirs */
589 Debug::log_stderr
= 1;
590 opt_create_swap_dirs
= 1;
598 /** \par h,?, or unknown
599 * \copydoc usage() */
617 signal(sig
, rotate_logs
);
627 ReconfigureSignal
= sig
;
631 signal(sig
, reconfigure
);
639 do_shutdown
= sig
== SIGINT
? -1 : 1;
640 ShutdownSignal
= sig
;
648 const pid_t ppid
= getppid();
650 if (!IamMasterProcess() && ppid
> 1) {
651 // notify master that we are shutting down
652 if (kill(ppid
, SIGUSR1
) < 0)
653 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
654 " pid " << ppid
<< ": " << xstrerror());
660 if (!IamMasterProcess() && ppid
> 1) {
661 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
663 if (kill(ppid
, sig
) < 0)
664 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
667 #endif /* KILL_PARENT_OPT */
668 #if SA_RESETHAND == 0
669 signal(SIGTERM
, SIG_DFL
);
671 signal(SIGINT
, SIG_DFL
);
678 serverConnectionsOpen(void)
680 if (IamPrimaryProcess()) {
682 wccpConnectionOpen();
687 wccp2ConnectionOpen();
690 // start various proxying services if we are responsible for them
691 if (IamWorkerProcess()) {
692 clientOpenListenSockets();
712 peerSourceHashInit();
717 serverConnectionsClose(void)
719 assert(shutting_down
|| reconfiguring
);
721 if (IamPrimaryProcess()) {
724 wccpConnectionClose();
728 wccp2ConnectionClose();
731 if (IamWorkerProcess()) {
732 clientHttpConnectionsClose();
733 icpConnectionShutdown();
735 htcpSocketShutdown();
748 mainReconfigureStart(void)
750 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
753 // Initiate asynchronous closing sequence
754 serverConnectionsClose();
761 Ssl::Helper::GetInstance()->Shutdown();
764 if (Ssl::CertValidationHelper::GetInstance())
765 Ssl::CertValidationHelper::GetInstance()->Shutdown();
766 Ssl::TheGlobalContextStorage
.reconfigureStart();
772 externalAclShutdown();
773 storeDirCloseSwapLogs();
780 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
785 mainReconfigureFinish(void *)
787 debugs(1, 3, "finishing reconfiguring");
790 enter_suid(); /* root to read config file */
792 // we may have disabled the need for PURGE
793 if (Config2
.onoff
.enable_purge
)
794 Config2
.onoff
.enable_purge
= 2;
796 // parse the config returns a count of errors encountered.
797 const int oldWorkers
= Config
.workers
;
798 if ( parseConfigFile(ConfigFile
) != 0) {
799 // for now any errors are a fatal condition...
802 if (oldWorkers
!= Config
.workers
) {
803 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
804 oldWorkers
<< " to " << Config
.workers
<<
805 ") requires a full restart. It has been ignored by reconfigure.");
806 Config
.workers
= oldWorkers
;
809 if (IamPrimaryProcess())
811 CpuAffinityReconfigure();
813 setUmask(Config
.umask
);
816 _db_init(Debug::cache_log
, Debug::debugOptions
);
817 ipcache_restart(); /* clear stuck entries */
818 fqdncache_restart(); /* sigh, fqdncache too */
820 errorInitialize(); /* reload error pages */
823 #if USE_LOADABLE_MODULES
824 LoadableModulesConfigure(Config
.loadable_module_names
);
828 bool enableAdaptation
= false;
830 Adaptation::Icap::TheConfig
.finalize();
831 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
834 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
835 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
837 Adaptation::Config::Finalize(enableAdaptation
);
846 Ssl::Helper::GetInstance()->Init();
849 if (Ssl::CertValidationHelper::GetInstance())
850 Ssl::CertValidationHelper::GetInstance()->Init();
855 authenticateInit(&Auth::TheConfig
);
859 if (IamPrimaryProcess()) {
870 serverConnectionsOpen();
874 storeDirOpenSwapLogs();
876 mimeInit(Config
.mimeTablePathname
);
882 Config
.ClientDelay
.finalize();
885 if (Config
.onoff
.announce
) {
886 if (!eventFind(start_announce
, NULL
))
887 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
889 if (eventFind(start_announce
, NULL
))
890 eventDelete(start_announce
, NULL
);
893 writePidFile(); /* write PID file */
904 authenticateRotate();
906 externalAclShutdown();
908 _db_rotate_log(); /* cache.log */
909 storeDirWriteCleanLogs(1);
910 storeLogRotate(); /* store.log */
911 accessLogRotate(); /* access.log */
913 icapLogRotate(); /*icap.log*/
918 authenticateInit(&Auth::TheConfig
);
924 setEffectiveUser(void)
927 leave_suid(); /* Run as non privilegied user */
933 if (geteuid() == 0) {
934 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
935 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
936 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
937 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
938 fatal("Don't run Squid as root, set 'cache_effective_user'!");
942 /// changes working directory, providing error reporting
944 mainChangeDir(const char *dir
)
949 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
950 ": " << xstrerror());
954 /// set the working directory.
958 static bool chrooted
= false;
959 if (Config
.chroot_dir
&& !chrooted
) {
962 if (chroot(Config
.chroot_dir
) != 0)
963 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
965 if (!mainChangeDir("/"))
966 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
969 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
970 if (mainChangeDir(Config
.coredump_dir
)) {
971 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
976 /* If we don't have coredump_dir or couldn't cd there, report current dir */
977 char pathbuf
[MAXPATHLEN
];
978 if (getcwd(pathbuf
, MAXPATHLEN
)) {
979 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
981 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
988 /* chroot if configured to run inside chroot */
991 if (opt_catch_signals
) {
992 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
993 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
996 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
997 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
1001 if (icpPortNumOverride
!= 1)
1002 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
1004 _db_init(Debug::cache_log
, Debug::debugOptions
);
1006 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1010 log_trace_init("/tmp/squid.alloc");
1014 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1017 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1018 debugs(1, DBG_CRITICAL
, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
1019 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1021 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1024 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1026 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1029 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1033 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1035 if (WIN32_Socks_initialized
)
1036 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1038 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1039 WIN32_IpAddrChangeMonitorInit();
1044 if (!configured_once
)
1045 disk_init(); /* disk_init must go before ipcache_init() */
1056 Ssl::Helper::GetInstance()->Init();
1060 if (Ssl::CertValidationHelper::GetInstance())
1061 Ssl::CertValidationHelper::GetInstance()->Init();
1066 authenticateInit(&Auth::TheConfig
);
1070 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1072 httpReplyInitModule(); /* must go before accepting replies */
1093 malloc_debug(0, malloc_debug_level
);
1097 if (!configured_once
) {
1098 if (unlinkdNeeded())
1105 /* after this point we want to see the mallinfo() output */
1107 mimeInit(Config
.mimeTablePathname
);
1113 FwdState::initModule();
1114 /* register the modules in the cache manager menus */
1116 cbdataRegisterWithCacheManager();
1117 /* These use separate calls so that the comm loops can eventually
1123 // TODO: pconn is a good candidate for new-style registration
1124 // PconnModule::GetInstance()->registerWithCacheManager();
1125 // moved to PconnModule::PconnModule()
1128 if (IamPrimaryProcess()) {
1140 serverConnectionsOpen();
1144 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1146 if (Config
.chroot_dir
)
1149 if (!configured_once
)
1150 writePidFile(); /* write PID file */
1152 #if defined(_SQUID_LINUX_THREADS_)
1154 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1156 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1160 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1162 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1166 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1168 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1170 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1174 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1180 #if USE_LOADABLE_MODULES
1181 LoadableModulesConfigure(Config
.loadable_module_names
);
1185 bool enableAdaptation
= false;
1187 // We can remove this dependency on specific adaptation mechanisms
1188 // if we create a generic Registry of such mechanisms. Should we?
1190 Adaptation::Icap::TheConfig
.finalize();
1191 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1194 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1195 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1197 // must be the last adaptation-related finalize
1198 Adaptation::Config::Finalize(enableAdaptation
);
1206 Config
.ClientDelay
.finalize();
1209 if (!configured_once
) {
1210 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1212 if (Config
.onoff
.announce
)
1213 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1215 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1217 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1221 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1225 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1228 configured_once
= 1;
1231 /// unsafe main routine -- may throw
1232 int SquidMain(int argc
, char **argv
);
1233 /// unsafe main routine wrapper to catch exceptions
1234 static int SquidMainSafe(int argc
, char **argv
);
1236 #if USE_WIN32_SERVICE
1237 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1238 extern "C" void WINAPI
1239 SquidWinSvcMain(int argc
, char **argv
)
1241 SquidMainSafe(argc
, argv
);
1245 main(int argc
, char **argv
)
1247 return SquidMainSafe(argc
, argv
);
1252 SquidMainSafe(int argc
, char **argv
)
1255 return SquidMain(argc
, argv
);
1256 } catch (const std::exception
&e
) {
1257 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1261 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1264 return -1; // not reached
1267 /// computes name and ID for the current kid process
1269 ConfigureCurrentKid(const char *processName
)
1271 // kids are marked with parenthesis around their process names
1272 if (processName
&& processName
[0] == '(') {
1273 if (const char *idStart
= strrchr(processName
, '-')) {
1274 KidIdentifier
= atoi(idStart
+ 1);
1275 const size_t nameLen
= idStart
- (processName
+ 1);
1276 assert(nameLen
< sizeof(TheKidName
));
1277 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1278 if (!strcmp(TheKidName
, "squid-coord"))
1279 TheProcessKind
= pkCoordinator
;
1280 else if (!strcmp(TheKidName
, "squid"))
1281 TheProcessKind
= pkWorker
;
1282 else if (!strcmp(TheKidName
, "squid-disk"))
1283 TheProcessKind
= pkDisker
;
1285 TheProcessKind
= pkOther
; // including coordinator
1288 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1294 SquidMain(int argc
, char **argv
)
1296 ConfigureCurrentKid(argv
[0]);
1299 sbrk_start
= sbrk(0);
1302 Debug::parseOptions(NULL
);
1305 #if defined(SQUID_MAXFD_LIMIT)
1307 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1308 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1312 /* NOP under non-windows */
1313 int WIN32_init_err
=0;
1314 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1315 return WIN32_init_err
;
1317 /* call mallopt() before anything else */
1320 /* Round up all sizes to a multiple of this */
1321 mallopt(M_GRAIN
, 16);
1325 /* biggest size that is considered a small block */
1326 mallopt(M_MXFAST
, 256);
1330 /* allocate this many small blocks at once */
1331 mallopt(M_NLBLKS
, 32);
1334 #endif /* HAVE_MALLOPT */
1336 squid_srandom(time(NULL
));
1340 squid_start
= current_time
;
1342 failure_notify
= fatal_dump
;
1344 #if USE_WIN32_SERVICE
1346 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1350 mainParseOptions(argc
, argv
);
1352 if (opt_parse_cfg_only
) {
1353 Debug::parseOptions("ALL,1");
1356 #if USE_WIN32_SERVICE
1358 if (opt_install_service
) {
1359 WIN32_InstallService();
1363 if (opt_remove_service
) {
1364 WIN32_RemoveService();
1368 if (opt_command_line
) {
1369 WIN32_SetServiceCommandLine();
1375 /* parse configuration file
1376 * note: in "normal" case this used to be called from mainInitialize() */
1381 ConfigFile
= xstrdup(DefaultConfigFile
);
1383 assert(!configured_once
);
1387 storeFsInit(); /* required for config parsing */
1389 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1392 /* May not be needed for parsing, have not audited for such */
1393 DiskIOModule::SetupAllModules();
1395 /* Shouldn't be needed for config parsing, but have not audited for such */
1396 StoreFileSystem::SetupAllFs();
1398 /* we may want the parsing process to set this up in the future */
1399 Store::Root(new StoreController
);
1400 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1401 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1403 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1405 parse_err
= parseConfigFile(ConfigFile
);
1409 if (opt_parse_cfg_only
|| parse_err
> 0)
1412 setUmask(Config
.umask
);
1413 if (-1 == opt_send_signal
)
1414 if (checkRunningPid())
1429 /* send signal to running copy and exit */
1430 if (opt_send_signal
!= -1) {
1431 /* chroot if configured to run inside chroot */
1433 if (Config
.chroot_dir
) {
1443 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1445 ActivateRegistered(rrFinalizeConfig
);
1446 ActivateRegistered(rrClaimMemoryNeeds
);
1447 ActivateRegistered(rrAfterConfig
);
1450 if (!opt_no_daemon
&& Config
.workers
> 0)
1453 if (opt_create_swap_dirs
) {
1454 /* chroot if configured to run inside chroot */
1458 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1459 Store::Root().create();
1464 if (IamPrimaryProcess())
1470 /* init comm module */
1473 if (opt_no_daemon
) {
1474 /* we have to init fdstat here. */
1475 fd_open(0, FD_LOG
, "stdin");
1476 fd_open(1, FD_LOG
, "stdout");
1477 fd_open(2, FD_LOG
, "stderr");
1480 #if USE_WIN32_SERVICE
1482 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1488 #if USE_WIN32_SERVICE
1490 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1497 SignalEngine signalEngine
;
1499 mainLoop
.registerEngine(&signalEngine
);
1501 /* TODO: stop requiring the singleton here */
1502 mainLoop
.registerEngine(EventScheduler::GetInstance());
1504 StoreRootEngine store_engine
;
1506 mainLoop
.registerEngine(&store_engine
);
1508 CommSelectEngine comm_engine
;
1510 mainLoop
.registerEngine(&comm_engine
);
1512 mainLoop
.setPrimaryEngine(&comm_engine
);
1514 /* use the standard time service */
1515 TimeEngine time_engine
;
1517 mainLoop
.setTimeService(&time_engine
);
1519 if (IamCoordinatorProcess())
1520 AsyncJob::Start(Ipc::Coordinator::Instance());
1521 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1522 AsyncJob::Start(new Ipc::Strand
);
1524 /* at this point we are finished the synchronous startup. */
1529 if (mainLoop
.errcount
== 10)
1530 fatal_dump("Event loop exited with failure.");
1532 /* shutdown squid now */
1545 if (strcmp(Config
.pidFilename
, "none") == 0) {
1546 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1549 pid
= readPidFile();
1552 #if USE_WIN32_SERVICE
1553 if (opt_signal_service
) {
1554 WIN32_sendSignal(opt_send_signal
);
1557 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1558 fprintf(stderr
, "signal to Squid Service:\n");
1559 fprintf(stderr
, "missing -n command line switch.\n");
1565 if (kill(pid
, opt_send_signal
) &&
1566 /* ignore permissions if just running check */
1567 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1568 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1569 fprintf(stderr
, "signal %d to process %d: %s\n",
1570 opt_send_signal
, (int) pid
, xstrerror());
1574 if (opt_send_signal
!= SIGTERM
) {
1575 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1578 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1583 /* signal successfully sent */
1587 #if !_SQUID_WINDOWS_
1589 * This function is run when Squid is in daemon mode, just
1590 * before the parent forks and starts up the child process.
1591 * It can be used for admin-specific tasks, such as notifying
1592 * someone that Squid is (re)started.
1595 mainStartScript(const char *prog
)
1597 char script
[MAXPATHLEN
];
1602 xstrncpy(script
, prog
, MAXPATHLEN
);
1604 if ((t
= strrchr(script
, '/'))) {
1606 sl
= strlen(script
);
1609 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1611 if ((cpid
= fork()) == 0) {
1613 execl(script
, squid_start_script
, (char *)NULL
);
1619 rpid
= wait4(cpid
, &status
, 0, NULL
);
1623 rpid
= waitpid(cpid
, &status
, 0);
1626 } while (rpid
!= cpid
);
1630 #endif /* _SQUID_WINDOWS_ */
1633 checkRunningPid(void)
1635 // master process must start alone, but its kids processes may co-exist
1636 if (!IamMasterProcess())
1644 pid
= readPidFile();
1649 if (kill(pid
, 0) < 0)
1652 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1658 watch_child(char *argv
[])
1660 #if !_SQUID_WINDOWS_
1678 if (!IamMasterProcess())
1681 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1683 if ((pid
= fork()) < 0)
1684 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1689 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1695 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1696 ioctl(i
, TIOCNOTTY
, NULL
);
1703 * RBCOLLINS - if cygwin stackdumps when squid is run without
1704 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1705 * 1.1.3. execvp had a bit overflow error in a loop..
1707 /* Connect stdio to /dev/null in daemon mode */
1708 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1711 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1715 if (Debug::log_stderr
< 0) {
1720 // handle shutdown notifications from kids
1721 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1723 if (Config
.workers
> 128) {
1724 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1726 // but we keep going in hope that user knows best
1730 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1732 // keep [re]starting kids until it is time to quit
1734 mainStartScript(argv
[0]);
1736 // start each kid that needs to be [re]started; once
1737 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1738 Kid
& kid
= TheKids
.get(i
);
1739 if (!kid
.shouldRestart())
1742 if ((pid
= fork()) == 0) {
1744 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1746 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1748 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1752 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1753 kid
.name().termedBuf(), pid
);
1757 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1759 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1763 pid
= wait3(&status
, 0, NULL
);
1767 pid
= waitpid(-1, &status
, 0);
1770 // Loop to collect all stopped kids before we go to sleep below.
1772 Kid
* kid
= TheKids
.find(pid
);
1775 if (kid
->calledExit()) {
1777 "Squid Parent: %s process %d exited with status %d",
1778 kid
->name().termedBuf(),
1779 kid
->getPid(), kid
->exitStatus());
1780 } else if (kid
->signaled()) {
1782 "Squid Parent: %s process %d exited due to signal %d with status %d",
1783 kid
->name().termedBuf(),
1784 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1786 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1787 kid
->name().termedBuf(), kid
->getPid());
1789 if (kid
->hopeless()) {
1790 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1791 " be restarted due to repeated, frequent failures",
1792 kid
->name().termedBuf(), kid
->getPid());
1795 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1798 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1801 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1804 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1806 DeactivateRegistered(rrAfterConfig
);
1807 DeactivateRegistered(rrClaimMemoryNeeds
);
1808 DeactivateRegistered(rrFinalizeConfig
);
1811 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1812 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1816 if (TheKids
.allHopeless()) {
1817 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1824 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1829 #endif /* _SQUID_WINDOWS_ */
1836 /* XXX: This function is called after the main loop has quit, which
1837 * means that no AsyncCalls would be called, including close handlers.
1838 * TODO: We need to close/shut/free everything that needs calls before
1842 #if USE_WIN32_SERVICE
1843 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1846 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1849 Ssl::Helper::GetInstance()->Shutdown();
1852 if (Ssl::CertValidationHelper::GetInstance())
1853 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1856 externalAclShutdown();
1866 wccpConnectionClose();
1870 wccp2ConnectionClose();
1873 releaseServerSockets();
1874 commCloseAllSockets();
1881 DelayPools::FreePools();
1884 authenticateReset();
1886 #if USE_WIN32_SERVICE
1888 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1891 Store::Root().sync(); /* Flush pending object writes/unlinks */
1893 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1895 storeDirWriteCleanLogs(0);
1898 Store::Root().sync(); /* Flush log writes */
1901 Store::Root().sync(); /* Flush log close */
1902 StoreFileSystem::FreeAllFs();
1903 DiskIOModule::FreeAllModules();
1904 DeactivateRegistered(rrAfterConfig
);
1905 DeactivateRegistered(rrClaimMemoryNeeds
);
1906 DeactivateRegistered(rrFinalizeConfig
);
1907 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1911 /*stmemFreeMemory(); */
1913 ipcacheFreeMemory();
1914 fqdncacheFreeMemory();
1916 clientdbFreeMemory();
1917 httpHeaderCleanModule();
1925 if (opt_no_daemon
) {
1932 // clear StoreController
1943 xmalloc_find_leaks();
1945 debugs(1, DBG_CRITICAL
, "Memory used after shutdown: " << xmalloc_total
);
1954 if (IamPrimaryProcess()) {
1955 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1957 safeunlink(Config
.pidFilename
, 0);
1962 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1966 * We used to fclose(debug_log) here if it was set, but then
1967 * we forgot to set it to NULL. That caused some coredumps
1968 * because exit() ends up calling a bunch of destructors and
1969 * such. So rather than forcing the debug_log to close, we'll
1970 * leave it open so that those destructors can write some
1971 * debugging if necessary. The file will be closed anyway when
1972 * the process truly exits.
1975 exit(shutdown_status
);