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_command_line
= FALSE
;
161 void WIN32_svcstatusupdate(DWORD
, DWORD
);
162 void WINAPI
WIN32_svcHandler(DWORD
);
165 static int opt_signal_service
= FALSE
;
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();
278 RunRegisteredHere(RegisteredRunner::startShutdown
);
279 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
286 "Usage: %s [-cdhvzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
287 #if USE_WIN32_SERVICE
288 "[-ir] [-O CommandLine]"
291 " -a port Specify HTTP port number (default: %d).\n"
292 " -d level Write debugging to stderr also.\n"
293 " -f file Use given config-file instead of\n"
295 " -h Print help message.\n"
296 #if USE_WIN32_SERVICE
297 " -i Installs as a Windows Service (see -n option).\n"
299 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
300 " Parse configuration file, then send signal to \n"
301 " running copy (except -k parse) and exit.\n"
302 " -n name Specify service name to use for service operations\n"
303 " default is: " APP_SHORTNAME
".\n"
304 #if USE_WIN32_SERVICE
305 " -r Removes a Windows Service (see -n option).\n"
307 " -s | -l facility\n"
308 " Enable logging to syslog.\n"
309 " -u port Specify ICP port number (default: %d), disable with 0.\n"
310 " -v Print version.\n"
311 " -z Create missing swap directories and then exit.\n"
312 " -C Do not catch fatal signals.\n"
313 " -D OBSOLETE. Scheduled for removal.\n"
314 " -F Don't serve any requests until store is rebuilt.\n"
315 " -N No daemon mode.\n"
316 #if USE_WIN32_SERVICE
318 " Set Windows Service Command line options in Registry.\n"
320 " -R Do not set REUSEADDR on port.\n"
321 " -S Double-check swap during rebuild.\n"
322 " -X Force full debugging.\n"
323 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
324 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
329 * Parse the parameters received via command line interface.
331 \param argc Number of options received on command line
332 \param argv List of parameters received on command line
335 mainParseOptions(int argc
, char *argv
[])
340 #if USE_WIN32_SERVICE
341 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
343 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?")) != -1)
351 * Unset/disabel global option for catchign signals. opt_catch_signals */
352 opt_catch_signals
= 0;
357 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
358 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
363 * Set global option for foreground rebuild. opt_foreground_rebuild */
364 opt_foreground_rebuild
= 1;
369 * Set global option for 'no_daemon' mode. opt_no_daemon */
373 #if USE_WIN32_SERVICE
377 * Set global option. opt_command_lin and WIN32_Command_Line */
378 opt_command_line
= 1;
379 WIN32_Command_Line
= xstrdup(optarg
);
385 * Unset/disable global option opt_reuseaddr */
391 * Set global option opt_store_doublecheck */
392 opt_store_doublecheck
= 1;
397 * Force full debugging */
398 Debug::parseOptions("rotate=0 ALL,9");
399 Debug::override_X
= 1;
400 sigusr2_handle(SIGUSR2
);
405 * Set global option opt_reload_hit_only */
406 opt_reload_hit_only
= 1;
409 #if USE_WIN32_SERVICE
413 * Set global option opt_install_service (to TRUE) */
414 opt_install_service
= TRUE
;
420 * Add optional HTTP port as given following the option */
421 add_http_port(optarg
);
426 * Set global option Debug::log_stderr to the number given follwoign the option */
427 Debug::log_stderr
= atoi(optarg
);
432 * Load the file given instead of the default squid.conf. */
434 ConfigFile
= xstrdup(optarg
);
439 * Run the administrative action given following the option */
441 /** \li When its an unknown option display the usage help. */
442 if ((int) strlen(optarg
) < 1)
445 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
446 /** \li On reconfigure send SIGHUP. */
447 opt_send_signal
= SIGHUP
;
448 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
449 /** \li On rotate send SIGQUIT or SIGUSR1. */
450 #if defined(_SQUID_LINUX_THREADS_)
451 opt_send_signal
= SIGQUIT
;
453 opt_send_signal
= SIGUSR1
;
456 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
457 /** \li On debug send SIGTRAP or SIGUSR2. */
458 #if defined(_SQUID_LINUX_THREADS_)
459 opt_send_signal
= SIGTRAP
;
461 opt_send_signal
= SIGUSR2
;
464 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
465 /** \li On shutdown send SIGTERM. */
466 opt_send_signal
= SIGTERM
;
467 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
468 /** \li On interrupt send SIGINT. */
469 opt_send_signal
= SIGINT
;
470 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
471 /** \li On kill send SIGKILL. */
472 opt_send_signal
= SIGKILL
;
476 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
477 /** \li On restart send SIGTTIN. (exit and restart by parent) */
478 opt_send_signal
= SIGTTIN
;
482 else if (!strncmp(optarg
, "check", strlen(optarg
)))
483 /** \li On check send 0 / SIGNULL. */
484 opt_send_signal
= 0; /* SIGNULL */
485 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
486 /** \li On parse set global flag to re-parse the config file only. */
487 opt_parse_cfg_only
= 1;
495 * Set global malloc_debug_level to the value given following the option.
496 * if none is given it toggles the xmalloc_trace option on/off */
499 malloc_debug_level
= atoi(optarg
);
501 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
506 xmalloc_trace
= !xmalloc_trace
;
508 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
515 * Set global option opt_signal_service (to true).
516 * Stores the additional parameter given in global service_name */
517 // XXX: verify that the new name has ONLY alphanumeric characters
519 service_name
= xstrdup(optarg
);
520 opt_signal_service
= true;
523 #if USE_WIN32_SERVICE
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 printf("Service Name: %s\n", service_name
);
573 if (strlen(SQUID_BUILD_INFO
))
574 printf("%s\n",SQUID_BUILD_INFO
);
575 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
577 #if USE_WIN32_SERVICE
579 printf("Compiled as Windows System Service.\n");
589 * Set global option Debug::log_stderr and opt_create_swap_dirs */
590 Debug::log_stderr
= 1;
591 opt_create_swap_dirs
= 1;
599 /** \par h,?, or unknown
600 * \copydoc usage() */
618 signal(sig
, rotate_logs
);
628 ReconfigureSignal
= sig
;
632 signal(sig
, reconfigure
);
640 do_shutdown
= sig
== SIGINT
? -1 : 1;
641 ShutdownSignal
= sig
;
649 const pid_t ppid
= getppid();
651 if (!IamMasterProcess() && ppid
> 1) {
652 // notify master that we are shutting down
653 if (kill(ppid
, SIGUSR1
) < 0)
654 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
655 " pid " << ppid
<< ": " << xstrerror());
661 if (!IamMasterProcess() && ppid
> 1) {
662 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
664 if (kill(ppid
, sig
) < 0)
665 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
668 #endif /* KILL_PARENT_OPT */
669 #if SA_RESETHAND == 0
670 signal(SIGTERM
, SIG_DFL
);
672 signal(SIGINT
, SIG_DFL
);
679 serverConnectionsOpen(void)
681 if (IamPrimaryProcess()) {
683 wccpConnectionOpen();
688 wccp2ConnectionOpen();
691 // start various proxying services if we are responsible for them
692 if (IamWorkerProcess()) {
693 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 RunRegisteredHere(RegisteredRunner::syncConfig
);
811 if (IamPrimaryProcess())
813 CpuAffinityReconfigure();
815 setUmask(Config
.umask
);
818 _db_init(Debug::cache_log
, Debug::debugOptions
);
819 ipcache_restart(); /* clear stuck entries */
820 fqdncache_restart(); /* sigh, fqdncache too */
822 errorInitialize(); /* reload error pages */
825 #if USE_LOADABLE_MODULES
826 LoadableModulesConfigure(Config
.loadable_module_names
);
830 bool enableAdaptation
= false;
832 Adaptation::Icap::TheConfig
.finalize();
833 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
836 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
837 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
839 Adaptation::Config::Finalize(enableAdaptation
);
848 Ssl::Helper::GetInstance()->Init();
851 if (Ssl::CertValidationHelper::GetInstance())
852 Ssl::CertValidationHelper::GetInstance()->Init();
857 authenticateInit(&Auth::TheConfig
);
861 if (IamPrimaryProcess()) {
872 serverConnectionsOpen();
876 storeDirOpenSwapLogs();
878 mimeInit(Config
.mimeTablePathname
);
884 Config
.ClientDelay
.finalize();
887 if (Config
.onoff
.announce
) {
888 if (!eventFind(start_announce
, NULL
))
889 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
891 if (eventFind(start_announce
, NULL
))
892 eventDelete(start_announce
, NULL
);
895 writePidFile(); /* write PID file */
906 authenticateRotate();
908 externalAclShutdown();
910 _db_rotate_log(); /* cache.log */
911 storeDirWriteCleanLogs(1);
912 storeLogRotate(); /* store.log */
913 accessLogRotate(); /* access.log */
915 icapLogRotate(); /*icap.log*/
920 authenticateInit(&Auth::TheConfig
);
926 setEffectiveUser(void)
929 leave_suid(); /* Run as non privilegied user */
935 if (geteuid() == 0) {
936 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
937 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
938 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
939 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
940 fatal("Don't run Squid as root, set 'cache_effective_user'!");
944 /// changes working directory, providing error reporting
946 mainChangeDir(const char *dir
)
951 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
952 ": " << xstrerror());
956 /// set the working directory.
960 static bool chrooted
= false;
961 if (Config
.chroot_dir
&& !chrooted
) {
964 if (chroot(Config
.chroot_dir
) != 0)
965 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
967 if (!mainChangeDir("/"))
968 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
971 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
972 if (mainChangeDir(Config
.coredump_dir
)) {
973 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
978 /* If we don't have coredump_dir or couldn't cd there, report current dir */
979 char pathbuf
[MAXPATHLEN
];
980 if (getcwd(pathbuf
, MAXPATHLEN
)) {
981 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
983 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
990 /* chroot if configured to run inside chroot */
993 if (opt_catch_signals
) {
994 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
995 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
998 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
999 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
1003 if (icpPortNumOverride
!= 1)
1004 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
1006 _db_init(Debug::cache_log
, Debug::debugOptions
);
1008 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1012 log_trace_init("/tmp/squid.alloc");
1016 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1017 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1020 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1021 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1023 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1026 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1028 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1031 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1035 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1037 if (WIN32_Socks_initialized
)
1038 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1040 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1041 WIN32_IpAddrChangeMonitorInit();
1046 if (!configured_once
)
1047 disk_init(); /* disk_init must go before ipcache_init() */
1058 Ssl::Helper::GetInstance()->Init();
1062 if (!configured_once
)
1063 Ssl::initialize_session_cache();
1065 if (Ssl::CertValidationHelper::GetInstance())
1066 Ssl::CertValidationHelper::GetInstance()->Init();
1071 authenticateInit(&Auth::TheConfig
);
1075 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1077 httpReplyInitModule(); /* must go before accepting replies */
1098 malloc_debug(0, malloc_debug_level
);
1102 if (!configured_once
) {
1103 if (unlinkdNeeded())
1110 /* after this point we want to see the mallinfo() output */
1112 mimeInit(Config
.mimeTablePathname
);
1118 FwdState::initModule();
1119 /* register the modules in the cache manager menus */
1121 cbdataRegisterWithCacheManager();
1122 /* These use separate calls so that the comm loops can eventually
1128 // TODO: pconn is a good candidate for new-style registration
1129 // PconnModule::GetInstance()->registerWithCacheManager();
1130 // moved to PconnModule::PconnModule()
1133 if (IamPrimaryProcess()) {
1145 serverConnectionsOpen();
1149 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1151 if (Config
.chroot_dir
)
1154 if (!configured_once
)
1155 writePidFile(); /* write PID file */
1157 #if defined(_SQUID_LINUX_THREADS_)
1159 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1161 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1165 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1167 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1171 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1173 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1175 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1179 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1185 #if USE_LOADABLE_MODULES
1186 LoadableModulesConfigure(Config
.loadable_module_names
);
1190 bool enableAdaptation
= false;
1192 // We can remove this dependency on specific adaptation mechanisms
1193 // if we create a generic Registry of such mechanisms. Should we?
1195 Adaptation::Icap::TheConfig
.finalize();
1196 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1199 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1200 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1202 // must be the last adaptation-related finalize
1203 Adaptation::Config::Finalize(enableAdaptation
);
1211 Config
.ClientDelay
.finalize();
1214 if (!configured_once
) {
1215 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1217 if (Config
.onoff
.announce
)
1218 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1220 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1222 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1226 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1230 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1233 configured_once
= 1;
1236 /// unsafe main routine -- may throw
1237 int SquidMain(int argc
, char **argv
);
1238 /// unsafe main routine wrapper to catch exceptions
1239 static int SquidMainSafe(int argc
, char **argv
);
1241 #if USE_WIN32_SERVICE
1242 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1243 extern "C" void WINAPI
1244 SquidWinSvcMain(int argc
, char **argv
)
1246 SquidMainSafe(argc
, argv
);
1250 main(int argc
, char **argv
)
1252 return SquidMainSafe(argc
, argv
);
1257 SquidMainSafe(int argc
, char **argv
)
1260 return SquidMain(argc
, argv
);
1261 } catch (const std::exception
&e
) {
1262 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1266 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1269 return -1; // not reached
1272 /// computes name and ID for the current kid process
1274 ConfigureCurrentKid(const char *processName
)
1276 // kids are marked with parenthesis around their process names
1277 if (processName
&& processName
[0] == '(') {
1278 if (const char *idStart
= strrchr(processName
, '-')) {
1279 KidIdentifier
= atoi(idStart
+ 1);
1280 const size_t nameLen
= idStart
- (processName
+ 1);
1281 assert(nameLen
< sizeof(TheKidName
));
1282 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1283 if (!strcmp(TheKidName
, "squid-coord"))
1284 TheProcessKind
= pkCoordinator
;
1285 else if (!strcmp(TheKidName
, "squid"))
1286 TheProcessKind
= pkWorker
;
1287 else if (!strcmp(TheKidName
, "squid-disk"))
1288 TheProcessKind
= pkDisker
;
1290 TheProcessKind
= pkOther
; // including coordinator
1293 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1299 SquidMain(int argc
, char **argv
)
1301 ConfigureCurrentKid(argv
[0]);
1304 sbrk_start
= sbrk(0);
1307 Debug::parseOptions(NULL
);
1310 #if defined(SQUID_MAXFD_LIMIT)
1312 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1313 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1317 /* NOP under non-windows */
1318 int WIN32_init_err
=0;
1319 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1320 return WIN32_init_err
;
1322 /* call mallopt() before anything else */
1325 /* Round up all sizes to a multiple of this */
1326 mallopt(M_GRAIN
, 16);
1330 /* biggest size that is considered a small block */
1331 mallopt(M_MXFAST
, 256);
1335 /* allocate this many small blocks at once */
1336 mallopt(M_NLBLKS
, 32);
1339 #endif /* HAVE_MALLOPT */
1341 squid_srandom(time(NULL
));
1345 squid_start
= current_time
;
1347 failure_notify
= fatal_dump
;
1349 #if USE_WIN32_SERVICE
1351 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1355 mainParseOptions(argc
, argv
);
1357 if (opt_parse_cfg_only
) {
1358 Debug::parseOptions("ALL,1");
1361 #if USE_WIN32_SERVICE
1363 if (opt_install_service
) {
1364 WIN32_InstallService();
1368 if (opt_remove_service
) {
1369 WIN32_RemoveService();
1373 if (opt_command_line
) {
1374 WIN32_SetServiceCommandLine();
1380 /* parse configuration file
1381 * note: in "normal" case this used to be called from mainInitialize() */
1386 ConfigFile
= xstrdup(DefaultConfigFile
);
1388 assert(!configured_once
);
1392 storeFsInit(); /* required for config parsing */
1394 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1397 /* May not be needed for parsing, have not audited for such */
1398 DiskIOModule::SetupAllModules();
1400 /* Shouldn't be needed for config parsing, but have not audited for such */
1401 StoreFileSystem::SetupAllFs();
1403 /* we may want the parsing process to set this up in the future */
1404 Store::Root(new StoreController
);
1405 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1406 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1408 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1410 parse_err
= parseConfigFile(ConfigFile
);
1414 if (opt_parse_cfg_only
|| parse_err
> 0)
1417 setUmask(Config
.umask
);
1418 if (-1 == opt_send_signal
)
1419 if (checkRunningPid())
1434 /* send signal to running copy and exit */
1435 if (opt_send_signal
!= -1) {
1436 /* chroot if configured to run inside chroot */
1438 if (Config
.chroot_dir
) {
1448 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1450 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1451 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1452 RunRegisteredHere(RegisteredRunner::useConfig
);
1455 if (!opt_no_daemon
&& Config
.workers
> 0)
1458 if (opt_create_swap_dirs
) {
1459 /* chroot if configured to run inside chroot */
1463 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1464 Store::Root().create();
1469 if (IamPrimaryProcess())
1475 /* init comm module */
1478 if (opt_no_daemon
) {
1479 /* we have to init fdstat here. */
1480 fd_open(0, FD_LOG
, "stdin");
1481 fd_open(1, FD_LOG
, "stdout");
1482 fd_open(2, FD_LOG
, "stderr");
1485 #if USE_WIN32_SERVICE
1487 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1493 #if USE_WIN32_SERVICE
1495 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1502 SignalEngine signalEngine
;
1504 mainLoop
.registerEngine(&signalEngine
);
1506 /* TODO: stop requiring the singleton here */
1507 mainLoop
.registerEngine(EventScheduler::GetInstance());
1509 StoreRootEngine store_engine
;
1511 mainLoop
.registerEngine(&store_engine
);
1513 CommSelectEngine comm_engine
;
1515 mainLoop
.registerEngine(&comm_engine
);
1517 mainLoop
.setPrimaryEngine(&comm_engine
);
1519 /* use the standard time service */
1520 TimeEngine time_engine
;
1522 mainLoop
.setTimeService(&time_engine
);
1524 if (IamCoordinatorProcess())
1525 AsyncJob::Start(Ipc::Coordinator::Instance());
1526 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1527 AsyncJob::Start(new Ipc::Strand
);
1529 /* at this point we are finished the synchronous startup. */
1534 if (mainLoop
.errcount
== 10)
1535 fatal_dump("Event loop exited with failure.");
1537 /* shutdown squid now */
1550 if (strcmp(Config
.pidFilename
, "none") == 0) {
1551 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1554 pid
= readPidFile();
1557 #if USE_WIN32_SERVICE
1558 if (opt_signal_service
) {
1559 WIN32_sendSignal(opt_send_signal
);
1562 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1563 fprintf(stderr
, "signal to Squid Service:\n");
1564 fprintf(stderr
, "missing -n command line switch.\n");
1570 if (kill(pid
, opt_send_signal
) &&
1571 /* ignore permissions if just running check */
1572 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1573 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1574 fprintf(stderr
, "signal %d to process %d: %s\n",
1575 opt_send_signal
, (int) pid
, xstrerror());
1579 if (opt_send_signal
!= SIGTERM
) {
1580 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1583 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1588 /* signal successfully sent */
1592 #if !_SQUID_WINDOWS_
1594 * This function is run when Squid is in daemon mode, just
1595 * before the parent forks and starts up the child process.
1596 * It can be used for admin-specific tasks, such as notifying
1597 * someone that Squid is (re)started.
1600 mainStartScript(const char *prog
)
1602 char script
[MAXPATHLEN
];
1607 xstrncpy(script
, prog
, MAXPATHLEN
);
1609 if ((t
= strrchr(script
, '/'))) {
1611 sl
= strlen(script
);
1614 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1616 if ((cpid
= fork()) == 0) {
1618 execl(script
, squid_start_script
, (char *)NULL
);
1624 rpid
= wait4(cpid
, &status
, 0, NULL
);
1628 rpid
= waitpid(cpid
, &status
, 0);
1631 } while (rpid
!= cpid
);
1635 #endif /* _SQUID_WINDOWS_ */
1638 checkRunningPid(void)
1640 // master process must start alone, but its kids processes may co-exist
1641 if (!IamMasterProcess())
1649 pid
= readPidFile();
1654 if (kill(pid
, 0) < 0)
1657 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1663 watch_child(char *argv
[])
1665 #if !_SQUID_WINDOWS_
1683 if (!IamMasterProcess())
1686 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1688 if ((pid
= fork()) < 0)
1689 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1694 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1700 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1701 ioctl(i
, TIOCNOTTY
, NULL
);
1708 * RBCOLLINS - if cygwin stackdumps when squid is run without
1709 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1710 * 1.1.3. execvp had a bit overflow error in a loop..
1712 /* Connect stdio to /dev/null in daemon mode */
1713 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1716 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1720 if (Debug::log_stderr
< 0) {
1725 // handle shutdown notifications from kids
1726 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1728 if (Config
.workers
> 128) {
1729 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1731 // but we keep going in hope that user knows best
1735 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1737 // keep [re]starting kids until it is time to quit
1739 mainStartScript(argv
[0]);
1741 // start each kid that needs to be [re]started; once
1742 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1743 Kid
& kid
= TheKids
.get(i
);
1744 if (!kid
.shouldRestart())
1747 if ((pid
= fork()) == 0) {
1749 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1751 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1753 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1757 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1758 kid
.name().termedBuf(), pid
);
1762 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1764 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1768 pid
= wait3(&status
, 0, NULL
);
1772 pid
= waitpid(-1, &status
, 0);
1775 // Loop to collect all stopped kids before we go to sleep below.
1777 Kid
* kid
= TheKids
.find(pid
);
1780 if (kid
->calledExit()) {
1782 "Squid Parent: %s process %d exited with status %d",
1783 kid
->name().termedBuf(),
1784 kid
->getPid(), kid
->exitStatus());
1785 } else if (kid
->signaled()) {
1787 "Squid Parent: %s process %d exited due to signal %d with status %d",
1788 kid
->name().termedBuf(),
1789 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1791 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1792 kid
->name().termedBuf(), kid
->getPid());
1794 if (kid
->hopeless()) {
1795 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1796 " be restarted due to repeated, frequent failures",
1797 kid
->name().termedBuf(), kid
->getPid());
1800 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1803 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1806 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1809 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1811 // XXX: Master process has no main loop and, hence, should not call
1812 // RegisteredRunner::startShutdown which promises a loop iteration.
1813 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1816 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1817 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1821 if (TheKids
.allHopeless()) {
1822 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1829 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1834 #endif /* _SQUID_WINDOWS_ */
1841 /* XXX: This function is called after the main loop has quit, which
1842 * means that no AsyncCalls would be called, including close handlers.
1843 * TODO: We need to close/shut/free everything that needs calls before
1847 #if USE_WIN32_SERVICE
1848 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1851 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1854 Ssl::Helper::GetInstance()->Shutdown();
1857 if (Ssl::CertValidationHelper::GetInstance())
1858 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1861 externalAclShutdown();
1871 wccpConnectionClose();
1875 wccp2ConnectionClose();
1878 releaseServerSockets();
1879 commCloseAllSockets();
1886 DelayPools::FreePools();
1889 authenticateReset();
1891 #if USE_WIN32_SERVICE
1893 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1896 Store::Root().sync(); /* Flush pending object writes/unlinks */
1898 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1900 storeDirWriteCleanLogs(0);
1903 Store::Root().sync(); /* Flush log writes */
1906 Store::Root().sync(); /* Flush log close */
1907 StoreFileSystem::FreeAllFs();
1908 DiskIOModule::FreeAllModules();
1909 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1913 /*stmemFreeMemory(); */
1915 ipcacheFreeMemory();
1916 fqdncacheFreeMemory();
1918 clientdbFreeMemory();
1919 httpHeaderCleanModule();
1927 if (opt_no_daemon
) {
1934 // clear StoreController
1943 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1947 xmalloc_find_leaks();
1949 debugs(1, DBG_CRITICAL
, "Memory used after shutdown: " << xmalloc_total
);
1958 if (IamPrimaryProcess()) {
1959 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1961 safeunlink(Config
.pidFilename
, 0);
1966 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1970 * We used to fclose(debug_log) here if it was set, but then
1971 * we forgot to set it to NULL. That caused some coredumps
1972 * because exit() ends up calling a bunch of destructors and
1973 * such. So rather than forcing the debug_log to close, we'll
1974 * leave it open so that those destructors can write some
1975 * debugging if necessary. The file will be closed anyway when
1976 * the process truly exits.
1979 exit(shutdown_status
);