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 (!configured_once
)
1061 Ssl::initialize_session_cache();
1063 if (Ssl::CertValidationHelper::GetInstance())
1064 Ssl::CertValidationHelper::GetInstance()->Init();
1069 authenticateInit(&Auth::TheConfig
);
1073 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1075 httpReplyInitModule(); /* must go before accepting replies */
1096 malloc_debug(0, malloc_debug_level
);
1100 if (!configured_once
) {
1101 if (unlinkdNeeded())
1108 /* after this point we want to see the mallinfo() output */
1110 mimeInit(Config
.mimeTablePathname
);
1116 FwdState::initModule();
1117 /* register the modules in the cache manager menus */
1119 cbdataRegisterWithCacheManager();
1120 /* These use separate calls so that the comm loops can eventually
1126 // TODO: pconn is a good candidate for new-style registration
1127 // PconnModule::GetInstance()->registerWithCacheManager();
1128 // moved to PconnModule::PconnModule()
1131 if (IamPrimaryProcess()) {
1143 serverConnectionsOpen();
1147 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1149 if (Config
.chroot_dir
)
1152 if (!configured_once
)
1153 writePidFile(); /* write PID file */
1155 #if defined(_SQUID_LINUX_THREADS_)
1157 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1159 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1163 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1165 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1169 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1171 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1173 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1177 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1183 #if USE_LOADABLE_MODULES
1184 LoadableModulesConfigure(Config
.loadable_module_names
);
1188 bool enableAdaptation
= false;
1190 // We can remove this dependency on specific adaptation mechanisms
1191 // if we create a generic Registry of such mechanisms. Should we?
1193 Adaptation::Icap::TheConfig
.finalize();
1194 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1197 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1198 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1200 // must be the last adaptation-related finalize
1201 Adaptation::Config::Finalize(enableAdaptation
);
1209 Config
.ClientDelay
.finalize();
1212 if (!configured_once
) {
1213 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1215 if (Config
.onoff
.announce
)
1216 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1218 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1220 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1224 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1228 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1231 configured_once
= 1;
1234 /// unsafe main routine -- may throw
1235 int SquidMain(int argc
, char **argv
);
1236 /// unsafe main routine wrapper to catch exceptions
1237 static int SquidMainSafe(int argc
, char **argv
);
1239 #if USE_WIN32_SERVICE
1240 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1241 extern "C" void WINAPI
1242 SquidWinSvcMain(int argc
, char **argv
)
1244 SquidMainSafe(argc
, argv
);
1248 main(int argc
, char **argv
)
1250 return SquidMainSafe(argc
, argv
);
1255 SquidMainSafe(int argc
, char **argv
)
1258 return SquidMain(argc
, argv
);
1259 } catch (const std::exception
&e
) {
1260 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1264 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1267 return -1; // not reached
1270 /// computes name and ID for the current kid process
1272 ConfigureCurrentKid(const char *processName
)
1274 // kids are marked with parenthesis around their process names
1275 if (processName
&& processName
[0] == '(') {
1276 if (const char *idStart
= strrchr(processName
, '-')) {
1277 KidIdentifier
= atoi(idStart
+ 1);
1278 const size_t nameLen
= idStart
- (processName
+ 1);
1279 assert(nameLen
< sizeof(TheKidName
));
1280 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1281 if (!strcmp(TheKidName
, "squid-coord"))
1282 TheProcessKind
= pkCoordinator
;
1283 else if (!strcmp(TheKidName
, "squid"))
1284 TheProcessKind
= pkWorker
;
1285 else if (!strcmp(TheKidName
, "squid-disk"))
1286 TheProcessKind
= pkDisker
;
1288 TheProcessKind
= pkOther
; // including coordinator
1291 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1297 SquidMain(int argc
, char **argv
)
1299 ConfigureCurrentKid(argv
[0]);
1302 sbrk_start
= sbrk(0);
1305 Debug::parseOptions(NULL
);
1308 #if defined(SQUID_MAXFD_LIMIT)
1310 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1311 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1315 /* NOP under non-windows */
1316 int WIN32_init_err
=0;
1317 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1318 return WIN32_init_err
;
1320 /* call mallopt() before anything else */
1323 /* Round up all sizes to a multiple of this */
1324 mallopt(M_GRAIN
, 16);
1328 /* biggest size that is considered a small block */
1329 mallopt(M_MXFAST
, 256);
1333 /* allocate this many small blocks at once */
1334 mallopt(M_NLBLKS
, 32);
1337 #endif /* HAVE_MALLOPT */
1339 squid_srandom(time(NULL
));
1343 squid_start
= current_time
;
1345 failure_notify
= fatal_dump
;
1347 #if USE_WIN32_SERVICE
1349 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1353 mainParseOptions(argc
, argv
);
1355 if (opt_parse_cfg_only
) {
1356 Debug::parseOptions("ALL,1");
1359 #if USE_WIN32_SERVICE
1361 if (opt_install_service
) {
1362 WIN32_InstallService();
1366 if (opt_remove_service
) {
1367 WIN32_RemoveService();
1371 if (opt_command_line
) {
1372 WIN32_SetServiceCommandLine();
1378 /* parse configuration file
1379 * note: in "normal" case this used to be called from mainInitialize() */
1384 ConfigFile
= xstrdup(DefaultConfigFile
);
1386 assert(!configured_once
);
1390 storeFsInit(); /* required for config parsing */
1392 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1395 /* May not be needed for parsing, have not audited for such */
1396 DiskIOModule::SetupAllModules();
1398 /* Shouldn't be needed for config parsing, but have not audited for such */
1399 StoreFileSystem::SetupAllFs();
1401 /* we may want the parsing process to set this up in the future */
1402 Store::Root(new StoreController
);
1403 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1404 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1406 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1408 parse_err
= parseConfigFile(ConfigFile
);
1412 if (opt_parse_cfg_only
|| parse_err
> 0)
1415 setUmask(Config
.umask
);
1416 if (-1 == opt_send_signal
)
1417 if (checkRunningPid())
1432 /* send signal to running copy and exit */
1433 if (opt_send_signal
!= -1) {
1434 /* chroot if configured to run inside chroot */
1436 if (Config
.chroot_dir
) {
1446 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1448 ActivateRegistered(rrFinalizeConfig
);
1449 ActivateRegistered(rrClaimMemoryNeeds
);
1450 ActivateRegistered(rrAfterConfig
);
1453 if (!opt_no_daemon
&& Config
.workers
> 0)
1456 if (opt_create_swap_dirs
) {
1457 /* chroot if configured to run inside chroot */
1461 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1462 Store::Root().create();
1467 if (IamPrimaryProcess())
1473 /* init comm module */
1476 if (opt_no_daemon
) {
1477 /* we have to init fdstat here. */
1478 fd_open(0, FD_LOG
, "stdin");
1479 fd_open(1, FD_LOG
, "stdout");
1480 fd_open(2, FD_LOG
, "stderr");
1483 #if USE_WIN32_SERVICE
1485 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1491 #if USE_WIN32_SERVICE
1493 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1500 SignalEngine signalEngine
;
1502 mainLoop
.registerEngine(&signalEngine
);
1504 /* TODO: stop requiring the singleton here */
1505 mainLoop
.registerEngine(EventScheduler::GetInstance());
1507 StoreRootEngine store_engine
;
1509 mainLoop
.registerEngine(&store_engine
);
1511 CommSelectEngine comm_engine
;
1513 mainLoop
.registerEngine(&comm_engine
);
1515 mainLoop
.setPrimaryEngine(&comm_engine
);
1517 /* use the standard time service */
1518 TimeEngine time_engine
;
1520 mainLoop
.setTimeService(&time_engine
);
1522 if (IamCoordinatorProcess())
1523 AsyncJob::Start(Ipc::Coordinator::Instance());
1524 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1525 AsyncJob::Start(new Ipc::Strand
);
1527 /* at this point we are finished the synchronous startup. */
1532 if (mainLoop
.errcount
== 10)
1533 fatal_dump("Event loop exited with failure.");
1535 /* shutdown squid now */
1548 if (strcmp(Config
.pidFilename
, "none") == 0) {
1549 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1552 pid
= readPidFile();
1555 #if USE_WIN32_SERVICE
1556 if (opt_signal_service
) {
1557 WIN32_sendSignal(opt_send_signal
);
1560 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1561 fprintf(stderr
, "signal to Squid Service:\n");
1562 fprintf(stderr
, "missing -n command line switch.\n");
1568 if (kill(pid
, opt_send_signal
) &&
1569 /* ignore permissions if just running check */
1570 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1571 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1572 fprintf(stderr
, "signal %d to process %d: %s\n",
1573 opt_send_signal
, (int) pid
, xstrerror());
1577 if (opt_send_signal
!= SIGTERM
) {
1578 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1581 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1586 /* signal successfully sent */
1590 #if !_SQUID_WINDOWS_
1592 * This function is run when Squid is in daemon mode, just
1593 * before the parent forks and starts up the child process.
1594 * It can be used for admin-specific tasks, such as notifying
1595 * someone that Squid is (re)started.
1598 mainStartScript(const char *prog
)
1600 char script
[MAXPATHLEN
];
1605 xstrncpy(script
, prog
, MAXPATHLEN
);
1607 if ((t
= strrchr(script
, '/'))) {
1609 sl
= strlen(script
);
1612 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1614 if ((cpid
= fork()) == 0) {
1616 execl(script
, squid_start_script
, (char *)NULL
);
1622 rpid
= wait4(cpid
, &status
, 0, NULL
);
1626 rpid
= waitpid(cpid
, &status
, 0);
1629 } while (rpid
!= cpid
);
1633 #endif /* _SQUID_WINDOWS_ */
1636 checkRunningPid(void)
1638 // master process must start alone, but its kids processes may co-exist
1639 if (!IamMasterProcess())
1647 pid
= readPidFile();
1652 if (kill(pid
, 0) < 0)
1655 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1661 watch_child(char *argv
[])
1663 #if !_SQUID_WINDOWS_
1681 if (!IamMasterProcess())
1684 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1686 if ((pid
= fork()) < 0)
1687 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1692 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1698 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1699 ioctl(i
, TIOCNOTTY
, NULL
);
1706 * RBCOLLINS - if cygwin stackdumps when squid is run without
1707 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1708 * 1.1.3. execvp had a bit overflow error in a loop..
1710 /* Connect stdio to /dev/null in daemon mode */
1711 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1714 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1718 if (Debug::log_stderr
< 0) {
1723 // handle shutdown notifications from kids
1724 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1726 if (Config
.workers
> 128) {
1727 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1729 // but we keep going in hope that user knows best
1733 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1735 // keep [re]starting kids until it is time to quit
1737 mainStartScript(argv
[0]);
1739 // start each kid that needs to be [re]started; once
1740 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1741 Kid
& kid
= TheKids
.get(i
);
1742 if (!kid
.shouldRestart())
1745 if ((pid
= fork()) == 0) {
1747 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1749 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1751 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1755 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1756 kid
.name().termedBuf(), pid
);
1760 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1762 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1766 pid
= wait3(&status
, 0, NULL
);
1770 pid
= waitpid(-1, &status
, 0);
1773 // Loop to collect all stopped kids before we go to sleep below.
1775 Kid
* kid
= TheKids
.find(pid
);
1778 if (kid
->calledExit()) {
1780 "Squid Parent: %s process %d exited with status %d",
1781 kid
->name().termedBuf(),
1782 kid
->getPid(), kid
->exitStatus());
1783 } else if (kid
->signaled()) {
1785 "Squid Parent: %s process %d exited due to signal %d with status %d",
1786 kid
->name().termedBuf(),
1787 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1789 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1790 kid
->name().termedBuf(), kid
->getPid());
1792 if (kid
->hopeless()) {
1793 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1794 " be restarted due to repeated, frequent failures",
1795 kid
->name().termedBuf(), kid
->getPid());
1798 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1801 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1804 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1807 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1809 DeactivateRegistered(rrAfterConfig
);
1810 DeactivateRegistered(rrClaimMemoryNeeds
);
1811 DeactivateRegistered(rrFinalizeConfig
);
1814 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1815 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1819 if (TheKids
.allHopeless()) {
1820 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1827 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1832 #endif /* _SQUID_WINDOWS_ */
1839 /* XXX: This function is called after the main loop has quit, which
1840 * means that no AsyncCalls would be called, including close handlers.
1841 * TODO: We need to close/shut/free everything that needs calls before
1845 #if USE_WIN32_SERVICE
1846 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1849 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1852 Ssl::Helper::GetInstance()->Shutdown();
1855 if (Ssl::CertValidationHelper::GetInstance())
1856 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1859 externalAclShutdown();
1869 wccpConnectionClose();
1873 wccp2ConnectionClose();
1876 releaseServerSockets();
1877 commCloseAllSockets();
1884 DelayPools::FreePools();
1887 authenticateReset();
1889 #if USE_WIN32_SERVICE
1891 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1894 Store::Root().sync(); /* Flush pending object writes/unlinks */
1896 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1898 storeDirWriteCleanLogs(0);
1901 Store::Root().sync(); /* Flush log writes */
1904 Store::Root().sync(); /* Flush log close */
1905 StoreFileSystem::FreeAllFs();
1906 DiskIOModule::FreeAllModules();
1907 DeactivateRegistered(rrAfterConfig
);
1908 DeactivateRegistered(rrClaimMemoryNeeds
);
1909 DeactivateRegistered(rrFinalizeConfig
);
1910 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1914 /*stmemFreeMemory(); */
1916 ipcacheFreeMemory();
1917 fqdncacheFreeMemory();
1919 clientdbFreeMemory();
1920 httpHeaderCleanModule();
1928 if (opt_no_daemon
) {
1935 // clear StoreController
1946 xmalloc_find_leaks();
1948 debugs(1, DBG_CRITICAL
, "Memory used after shutdown: " << xmalloc_total
);
1957 if (IamPrimaryProcess()) {
1958 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1960 safeunlink(Config
.pidFilename
, 0);
1965 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1969 * We used to fclose(debug_log) here if it was set, but then
1970 * we forgot to set it to NULL. That caused some coredumps
1971 * because exit() ends up calling a bunch of destructors and
1972 * such. So rather than forcing the debug_log to close, we'll
1973 * leave it open so that those destructors can write some
1974 * debugging if necessary. The file will be closed anyway when
1975 * the process truly exits.
1978 exit(shutdown_status
);