4 * DEBUG: section 01 Startup and Main Loop
5 * AUTHOR: Harvest Derived
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 #include "AccessLogEntry.h"
38 #include "adaptation/icap/icap_log.h"
41 #include "auth/Gadgets.h"
43 #include "base/RunnersRegistry.h"
44 #include "base/TextException.h"
46 #include "ClientDelayConfig.h"
49 #include "ConfigParser.h"
50 #include "CpuAffinity.h"
52 #include "DelayPools.h"
54 #include "errorpage.h"
56 #include "EventLoop.h"
57 #include "ExternalACL.h"
60 #include "ident/Ident.h"
61 #include "HttpReply.h"
67 #include "StoreFileSystem.h"
68 #include "DiskIO/DiskIOModule.h"
70 #include "ipc/Coordinator.h"
71 #include "ipc/Strand.h"
73 #include "SquidTime.h"
77 #include "icmp/IcmpSquid.h"
78 #include "icmp/net_db.h"
80 #if USE_LOADABLE_MODULES
81 #include "LoadableModules.h"
85 #include "ssl/helper.h"
86 #include "ssl/certificate_db.h"
90 #include "ssl/context_storage.h"
94 #include "adaptation/icap/Config.h"
97 #include "adaptation/ecap/Config.h"
100 #include "adaptation/Config.h"
103 #include "esi/Module.h"
105 #include "fs/Module.h"
111 #if USE_WIN32_SERVICE
112 #include "squid_windows.h"
115 static int opt_install_service
= FALSE
;
116 static int opt_remove_service
= FALSE
;
117 static int opt_signal_service
= FALSE
;
118 static int opt_command_line
= FALSE
;
119 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
120 void WINAPI
WIN32_svcHandler(DWORD
);
124 #ifndef SQUID_BUILD_INFO
125 #define SQUID_BUILD_INFO ""
128 static char *opt_syslog_facility
= NULL
;
129 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
130 static int configured_once
= 0;
132 static int malloc_debug_level
= 0;
134 static volatile int do_reconfigure
= 0;
135 static volatile int do_rotate
= 0;
136 static volatile int do_shutdown
= 0;
137 static volatile int shutdown_status
= 0;
139 static int RotateSignal
= -1;
140 static int ReconfigureSignal
= -1;
141 static int ShutdownSignal
= -1;
143 static void mainRotate(void);
144 static void mainReconfigureStart(void);
145 static void mainReconfigureFinish(void*);
146 static void mainInitialize(void);
147 static void usage(void);
148 static void mainParseOptions(int argc
, char *argv
[]);
149 static void sendSignal(void);
150 static void serverConnectionsOpen(void);
151 static void serverConnectionsClose(void);
152 static void watch_child(char **);
153 static void setEffectiveUser(void);
155 extern void log_trace_done();
156 extern void log_trace_init(char *);
158 static void SquidShutdown(void);
159 static void mainSetCwd(void);
160 static int checkRunningPid(void);
162 #ifndef _SQUID_MSWIN_
163 static const char *squid_start_script
= "squid_start";
167 #include "test_access.c"
170 /** temporary thunk across to the unrefactored store interface */
172 class StoreRootEngine
: public AsyncEngine
176 int checkEvents(int timeout
) {
177 Store::Root().callback();
182 class SignalEngine
: public AsyncEngine
186 SignalEngine(EventLoop
&evtLoop
) : loop(evtLoop
) {}
187 virtual int checkEvents(int timeout
);
190 static void StopEventLoop(void * data
) {
191 static_cast<SignalEngine
*>(data
)->loop
.stop();
194 void doShutdown(time_t wait
);
200 SignalEngine::checkEvents(int timeout
)
202 PROF_start(SignalEngine_checkEvents
);
204 if (do_reconfigure
) {
205 mainReconfigureStart();
207 } else if (do_rotate
) {
210 } else if (do_shutdown
) {
211 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
214 BroadcastSignalIfAny(DebugSignal
);
215 BroadcastSignalIfAny(RotateSignal
);
216 BroadcastSignalIfAny(ReconfigureSignal
);
217 BroadcastSignalIfAny(ShutdownSignal
);
219 PROF_stop(SignalEngine_checkEvents
);
224 SignalEngine::doShutdown(time_t wait
)
226 debugs(1, 1, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
227 debugs(1, 1, "Waiting " << wait
<< " seconds for active connections to finish");
231 #if USE_WIN32_SERVICE
232 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
235 /* run the closure code which can be shared with reconfigure */
236 serverConnectionsClose();
238 /* detach the auth components (only do this on full shutdown) */
239 Auth::Scheme::FreeAll();
241 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
248 #if USE_WIN32_SERVICE
249 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
251 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
253 " -a port Specify HTTP port number (default: %d).\n"
254 " -d level Write debugging to stderr also.\n"
255 " -f file Use given config-file instead of\n"
257 " -h Print help message.\n"
258 #if USE_WIN32_SERVICE
259 " -i Installs as a Windows Service (see -n option).\n"
261 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
262 " Parse configuration file, then send signal to \n"
263 " running copy (except -k parse) and exit.\n"
264 #if USE_WIN32_SERVICE
265 " -n name Specify Windows Service name to use for service operations\n"
266 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
267 " -r Removes a Windows Service (see -n option).\n"
269 " -s | -l facility\n"
270 " Enable logging to syslog.\n"
271 " -u port Specify ICP port number (default: %d), disable with 0.\n"
272 " -v Print version.\n"
273 " -z Create swap directories\n"
274 " -C Do not catch fatal signals.\n"
275 " -D OBSOLETE. Scheduled for removal.\n"
276 " -F Don't serve any requests until store is rebuilt.\n"
277 " -N No daemon mode.\n"
278 #if USE_WIN32_SERVICE
280 " Set Windows Service Command line options in Registry.\n"
282 " -R Do not set REUSEADDR on port.\n"
283 " -S Double-check swap during rebuild.\n"
284 " -X Force full debugging.\n"
285 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
286 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
291 * Parse the parameters received via command line interface.
293 \param argc Number of options received on command line
294 \param argv List of parameters received on command line
297 mainParseOptions(int argc
, char *argv
[])
302 #if USE_WIN32_SERVICE
303 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
305 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
313 * Unset/disabel global option for catchign signals. opt_catch_signals */
314 opt_catch_signals
= 0;
319 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
320 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
325 * Set global option for foreground rebuild. opt_foreground_rebuild */
326 opt_foreground_rebuild
= 1;
331 * Set global option for 'no_daemon' mode. opt_no_daemon */
335 #if USE_WIN32_SERVICE
339 * Set global option. opt_command_lin and WIN32_Command_Line */
340 opt_command_line
= 1;
341 WIN32_Command_Line
= xstrdup(optarg
);
347 * Unset/disable global option opt_reuseaddr */
353 * Set global option opt_store_doublecheck */
354 opt_store_doublecheck
= 1;
359 * Force full debugging */
360 Debug::parseOptions("rotate=0 ALL,9");
361 Debug::override_X
= 1;
362 sigusr2_handle(SIGUSR2
);
367 * Set global option opt_reload_hit_only */
368 opt_reload_hit_only
= 1;
371 #if USE_WIN32_SERVICE
375 * Set global option opt_install_service (to TRUE) */
376 opt_install_service
= TRUE
;
382 * Add optional HTTP port as given following the option */
383 add_http_port(optarg
);
388 * Set global option Debug::log_stderr to the number given follwoign the option */
389 Debug::log_stderr
= atoi(optarg
);
394 * Load the file given instead of the default squid.conf. */
396 ConfigFile
= xstrdup(optarg
);
401 * Run the administrative action given following the option */
403 /** \li When its an unknown option display the usage help. */
404 if ((int) strlen(optarg
) < 1)
407 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
408 /** \li On reconfigure send SIGHUP. */
409 opt_send_signal
= SIGHUP
;
410 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
411 /** \li On rotate send SIGQUIT or SIGUSR1. */
412 #ifdef _SQUID_LINUX_THREADS_
414 opt_send_signal
= SIGQUIT
;
418 opt_send_signal
= SIGUSR1
;
422 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
423 /** \li On debug send SIGTRAP or SIGUSR2. */
424 #ifdef _SQUID_LINUX_THREADS_
426 opt_send_signal
= SIGTRAP
;
430 opt_send_signal
= SIGUSR2
;
434 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
435 /** \li On shutdown send SIGTERM. */
436 opt_send_signal
= SIGTERM
;
437 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
438 /** \li On interrupt send SIGINT. */
439 opt_send_signal
= SIGINT
;
440 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
441 /** \li On kill send SIGKILL. */
442 opt_send_signal
= SIGKILL
;
446 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
447 /** \li On restart send SIGTTIN. (exit and restart by parent) */
448 opt_send_signal
= SIGTTIN
;
452 else if (!strncmp(optarg
, "check", strlen(optarg
)))
453 /** \li On check send 0 / SIGNULL. */
454 opt_send_signal
= 0; /* SIGNULL */
455 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
456 /** \li On parse set global flag to re-parse the config file only. */
457 opt_parse_cfg_only
= 1;
465 * Set global malloc_debug_level to the value given following the option.
466 * if none is given it toggles the xmalloc_trace option on/off */
469 malloc_debug_level
= atoi(optarg
);
471 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
476 xmalloc_trace
= !xmalloc_trace
;
478 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
483 #if USE_WIN32_SERVICE
487 * Set global option opt_signal_service (to TRUE).
488 * Stores the additional parameter given in global WIN32_Service_name */
489 xfree(WIN32_Service_name
);
491 WIN32_Service_name
= xstrdup(optarg
);
493 opt_signal_service
= TRUE
;
499 * Set global option opt_remove_service (to TRUE) */
500 opt_remove_service
= TRUE
;
508 * Stores the syslog facility name in global opt_syslog_facility
509 * then performs actions for -s option. */
510 opt_syslog_facility
= xstrdup(optarg
);
514 * Initialize the syslog for output */
517 _db_set_syslog(opt_syslog_facility
);
523 fatal("Logging to syslog not available on this platform");
530 * Store the ICP port number given in global option icpPortNumOverride
531 * ensuring its a positive number. */
532 icpPortNumOverride
= atoi(optarg
);
534 if (icpPortNumOverride
< 0)
535 icpPortNumOverride
= 0;
541 * Display squid version and build information. Then exit. */
542 printf("Squid Cache: Version %s\n" ,version_string
);
543 if (strlen(SQUID_BUILD_INFO
))
544 printf("%s\n",SQUID_BUILD_INFO
);
545 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
547 #if USE_WIN32_SERVICE
549 printf("Compiled as Windows System Service.\n");
559 * Set global option Debug::log_stderr and opt_create_swap_dirs */
560 Debug::log_stderr
= 1;
561 opt_create_swap_dirs
= 1;
569 /** \par h,?, or unknown
570 * \copydoc usage() */
585 #ifndef _SQUID_MSWIN_
588 signal(sig
, rotate_logs
);
598 ReconfigureSignal
= sig
;
599 #ifndef _SQUID_MSWIN_
602 signal(sig
, reconfigure
);
610 do_shutdown
= sig
== SIGINT
? -1 : 1;
611 ShutdownSignal
= sig
;
619 const pid_t ppid
= getppid();
621 if (!IamMasterProcess() && ppid
> 1) {
622 // notify master that we are shutting down
623 if (kill(ppid
, SIGUSR1
) < 0)
624 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
625 " pid " << ppid
<< ": " << xstrerror());
628 #ifndef _SQUID_MSWIN_
631 if (!IamMasterProcess() && ppid
> 1) {
632 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
634 if (kill(ppid
, sig
) < 0)
635 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
638 #endif /* KILL_PARENT_OPT */
639 #if SA_RESETHAND == 0
640 signal(SIGTERM
, SIG_DFL
);
642 signal(SIGINT
, SIG_DFL
);
649 serverConnectionsOpen(void)
651 if (IamPrimaryProcess()) {
654 wccpConnectionOpen();
659 wccp2ConnectionOpen();
662 // start various proxying services if we are responsible for them
663 if (IamWorkerProcess()) {
664 clientOpenListenSockets();
665 icpConnectionsOpen();
672 snmpConnectionOpen();
686 peerSourceHashInit();
691 serverConnectionsClose(void)
693 assert(shutting_down
|| reconfiguring
);
695 if (IamPrimaryProcess()) {
698 wccpConnectionClose();
702 wccp2ConnectionClose();
705 if (IamWorkerProcess()) {
706 clientHttpConnectionsClose();
707 icpConnectionShutdown();
710 htcpSocketShutdown();
716 snmpConnectionShutdown();
724 mainReconfigureStart(void)
726 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
729 // Initiate asynchronous closing sequence
730 serverConnectionsClose();
731 icpConnectionClose();
738 snmpConnectionClose();
748 Ssl::Helper::GetInstance()->Shutdown();
751 Ssl::TheGlobalContextStorage
.reconfigureStart();
757 externalAclShutdown();
758 storeDirCloseSwapLogs();
765 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
770 mainReconfigureFinish(void *)
772 debugs(1, 3, "finishing reconfiguring");
775 enter_suid(); /* root to read config file */
777 // we may have disabled the need for PURGE
778 if (Config2
.onoff
.enable_purge
)
779 Config2
.onoff
.enable_purge
= 2;
781 // parse the config returns a count of errors encountered.
782 const int oldWorkers
= Config
.workers
;
783 if ( parseConfigFile(ConfigFile
) != 0) {
784 // for now any errors are a fatal condition...
787 if (oldWorkers
!= Config
.workers
) {
788 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
789 oldWorkers
<< " to " << Config
.workers
<<
790 ") is not supported and ignored");
791 Config
.workers
= oldWorkers
;
794 if (IamPrimaryProcess())
796 CpuAffinityReconfigure();
798 setUmask(Config
.umask
);
801 _db_init(Debug::cache_log
, Debug::debugOptions
);
802 ipcache_restart(); /* clear stuck entries */
803 fqdncache_restart(); /* sigh, fqdncache too */
805 errorInitialize(); /* reload error pages */
808 #if USE_LOADABLE_MODULES
809 LoadableModulesConfigure(Config
.loadable_module_names
);
813 bool enableAdaptation
= false;
815 Adaptation::Icap::TheConfig
.finalize();
816 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
819 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
820 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
822 Adaptation::Config::Finalize(enableAdaptation
);
837 Ssl::Helper::GetInstance()->Init();
842 authenticateInit(&Auth::TheConfig
);
846 if (IamPrimaryProcess()) {
857 serverConnectionsOpen();
861 storeDirOpenSwapLogs();
863 mimeInit(Config
.mimeTablePathname
);
866 Config
.ClientDelay
.finalize();
869 if (Config
.onoff
.announce
) {
870 if (!eventFind(start_announce
, NULL
))
871 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
873 if (eventFind(start_announce
, NULL
))
874 eventDelete(start_announce
, NULL
);
877 writePidFile(); /* write PID file */
879 debugs(1, 1, "Ready to serve requests.");
893 authenticateRotate();
895 externalAclShutdown();
897 _db_rotate_log(); /* cache.log */
898 storeDirWriteCleanLogs(1);
899 storeLogRotate(); /* store.log */
900 accessLogRotate(); /* access.log */
902 icapLogRotate(); /*icap.log*/
910 authenticateInit(&Auth::TheConfig
);
916 setEffectiveUser(void)
919 leave_suid(); /* Run as non privilegied user */
925 if (geteuid() == 0) {
926 debugs(0, 0, "Squid is not safe to run as root! If you must");
927 debugs(0, 0, "start Squid as root, then you must configure");
928 debugs(0, 0, "it to run as a non-priveledged user with the");
929 debugs(0, 0, "'cache_effective_user' option in the config file.");
930 fatal("Don't run Squid as root, set 'cache_effective_user'!");
937 char pathbuf
[MAXPATHLEN
];
939 if (Config
.coredump_dir
) {
940 if (0 == strcmp("none", Config
.coredump_dir
)) {
942 } else if (chdir(Config
.coredump_dir
) == 0) {
943 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
946 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
950 /* If we don't have coredump_dir or couldn't cd there, report current dir */
951 if (getcwd(pathbuf
, MAXPATHLEN
)) {
952 debugs(0, 1, "Current Directory is " << pathbuf
);
954 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
961 /* chroot if configured to run inside chroot */
963 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
964 fatal("failed to chroot");
967 if (opt_catch_signals
) {
968 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
969 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
972 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
973 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
977 if (icpPortNumOverride
!= 1)
978 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
980 _db_init(Debug::cache_log
, Debug::debugOptions
);
982 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
986 log_trace_init("/tmp/squid.alloc");
990 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
993 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
994 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
995 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
997 debugs(1, 0, "Running on " << WIN32_OS_string
);
1000 debugs(1, 1, "Process ID " << getpid());
1002 debugs(1, 1, "Process Roles:" << ProcessRoles());
1005 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
1007 #ifdef _SQUID_MSWIN_
1009 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1011 if (WIN32_Socks_initialized
)
1012 debugs(1, 1, "Windows sockets initialized");
1014 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1015 WIN32_IpAddrChangeMonitorInit();
1020 if (!configured_once
)
1021 disk_init(); /* disk_init must go before ipcache_init() */
1041 authenticateInit(&Auth::TheConfig
);
1045 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1047 httpReplyInitModule(); /* must go before accepting replies */
1068 malloc_debug(0, malloc_debug_level
);
1072 if (!configured_once
) {
1081 /* after this point we want to see the mallinfo() output */
1083 mimeInit(Config
.mimeTablePathname
);
1089 FwdState::initModule();
1090 /* register the modules in the cache manager menus */
1092 cbdataRegisterWithCacheManager();
1093 /* These use separate calls so that the comm loops can eventually
1099 // TODO: pconn is a good candidate for new-style registration
1100 // PconnModule::GetInstance()->registerWithCacheManager();
1101 // moved to PconnModule::PconnModule()
1104 if (IamPrimaryProcess()) {
1116 serverConnectionsOpen();
1120 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1122 if (Config
.chroot_dir
)
1125 if (!configured_once
)
1126 writePidFile(); /* write PID file */
1128 #ifdef _SQUID_LINUX_THREADS_
1130 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1132 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1136 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1138 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1142 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1144 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1146 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1150 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1156 #if USE_LOADABLE_MODULES
1157 LoadableModulesConfigure(Config
.loadable_module_names
);
1161 bool enableAdaptation
= false;
1163 // We can remove this dependency on specific adaptation mechanisms
1164 // if we create a generic Registry of such mechanisms. Should we?
1166 Adaptation::Icap::TheConfig
.finalize();
1167 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1170 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1171 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1173 // must be the last adaptation-related finalize
1174 Adaptation::Config::Finalize(enableAdaptation
);
1182 Config
.ClientDelay
.finalize();
1185 debugs(1, 1, "Ready to serve requests.");
1187 if (!configured_once
) {
1188 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1190 if (Config
.onoff
.announce
)
1191 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1193 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1195 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1199 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1203 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1206 configured_once
= 1;
1209 /// unsafe main routine -- may throw
1210 int SquidMain(int argc
, char **argv
);
1211 /// unsafe main routine wrapper to catch exceptions
1212 static int SquidMainSafe(int argc
, char **argv
);
1214 #if USE_WIN32_SERVICE
1215 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1216 extern "C" void WINAPI
1217 SquidWinSvcMain(int argc
, char **argv
)
1219 SquidMainSafe(argc
, argv
);
1223 main(int argc
, char **argv
)
1225 return SquidMainSafe(argc
, argv
);
1230 SquidMainSafe(int argc
, char **argv
)
1233 return SquidMain(argc
, argv
);
1234 } catch (const std::exception
&e
) {
1235 debugs(0,0, "dying from an unhandled exception: " << e
.what());
1238 debugs(0,0, "dying from an unhandled exception.");
1241 return -1; // not reached
1244 /// computes name and ID for the current kid process
1246 ConfigureCurrentKid(const char *processName
)
1248 // kids are marked with parenthesis around their process names
1249 if (processName
&& processName
[0] == '(') {
1250 if (const char *idStart
= strrchr(processName
, '-')) {
1251 KidIdentifier
= atoi(idStart
+ 1);
1252 const size_t nameLen
= idStart
- (processName
+ 1);
1253 assert(nameLen
< sizeof(TheKidName
));
1254 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1255 if (!strcmp(TheKidName
, "squid-coord"))
1256 TheProcessKind
= pkCoordinator
;
1258 if (!strcmp(TheKidName
, "squid"))
1259 TheProcessKind
= pkWorker
;
1261 if (!strcmp(TheKidName
, "squid-disk"))
1262 TheProcessKind
= pkDisker
;
1264 TheProcessKind
= pkOther
; // including coordinator
1267 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1273 SquidMain(int argc
, char **argv
)
1275 ConfigureCurrentKid(argv
[0]);
1283 sbrk_start
= sbrk(0);
1286 Debug::parseOptions(NULL
);
1289 #if defined(SQUID_MAXFD_LIMIT)
1291 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1292 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1297 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1298 return WIN32_init_err
;
1301 /* call mallopt() before anything else */
1304 /* Round up all sizes to a multiple of this */
1305 mallopt(M_GRAIN
, 16);
1309 /* biggest size that is considered a small block */
1310 mallopt(M_MXFAST
, 256);
1314 /* allocate this many small blocks at once */
1315 mallopt(M_NLBLKS
, 32);
1318 #endif /* HAVE_MALLOPT */
1320 squid_srandom(time(NULL
));
1324 squid_start
= current_time
;
1326 failure_notify
= fatal_dump
;
1328 #if USE_WIN32_SERVICE
1330 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1334 mainParseOptions(argc
, argv
);
1336 if (opt_parse_cfg_only
) {
1337 Debug::parseOptions("ALL,1");
1340 #if USE_WIN32_SERVICE
1342 if (opt_install_service
) {
1343 WIN32_InstallService();
1347 if (opt_remove_service
) {
1348 WIN32_RemoveService();
1352 if (opt_command_line
) {
1353 WIN32_SetServiceCommandLine();
1359 /* parse configuration file
1360 * note: in "normal" case this used to be called from mainInitialize() */
1365 ConfigFile
= xstrdup(DefaultConfigFile
);
1367 assert(!configured_once
);
1371 storeFsInit(); /* required for config parsing */
1373 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1376 /* May not be needed for parsing, have not audited for such */
1377 DiskIOModule::SetupAllModules();
1379 /* Shouldn't be needed for config parsing, but have not audited for such */
1380 StoreFileSystem::SetupAllFs();
1382 /* we may want the parsing process to set this up in the future */
1383 Store::Root(new StoreController
);
1385 Auth::Init(); /* required for config parsing */
1387 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1389 parse_err
= parseConfigFile(ConfigFile
);
1393 if (opt_parse_cfg_only
|| parse_err
> 0)
1396 setUmask(Config
.umask
);
1397 if (-1 == opt_send_signal
)
1398 if (checkRunningPid())
1413 /* send signal to running copy and exit */
1414 if (opt_send_signal
!= -1) {
1415 /* chroot if configured to run inside chroot */
1417 if (Config
.chroot_dir
) {
1418 if (chroot(Config
.chroot_dir
))
1419 fatal("failed to chroot");
1430 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1432 ActivateRegistered(rrAfterConfig
);
1435 if (!opt_no_daemon
&& Config
.workers
> 0)
1438 if (opt_create_swap_dirs
) {
1439 /* chroot if configured to run inside chroot */
1441 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1442 fatal("failed to chroot");
1446 debugs(0, 0, "Creating Swap Directories");
1447 Store::Root().create();
1452 if (IamPrimaryProcess())
1458 /* init comm module */
1461 if (opt_no_daemon
) {
1462 /* we have to init fdstat here. */
1463 fd_open(0, FD_LOG
, "stdin");
1464 fd_open(1, FD_LOG
, "stdout");
1465 fd_open(2, FD_LOG
, "stderr");
1468 #if USE_WIN32_SERVICE
1470 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1476 #if USE_WIN32_SERVICE
1478 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1485 SignalEngine
signalEngine(mainLoop
);
1487 mainLoop
.registerEngine(&signalEngine
);
1489 /* TODO: stop requiring the singleton here */
1490 mainLoop
.registerEngine(EventScheduler::GetInstance());
1492 StoreRootEngine store_engine
;
1494 mainLoop
.registerEngine(&store_engine
);
1496 CommSelectEngine comm_engine
;
1498 mainLoop
.registerEngine(&comm_engine
);
1500 mainLoop
.setPrimaryEngine(&comm_engine
);
1502 /* use the standard time service */
1503 TimeEngine time_engine
;
1505 mainLoop
.setTimeService(&time_engine
);
1507 if (IamCoordinatorProcess())
1508 AsyncJob::Start(Ipc::Coordinator::Instance());
1509 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1510 AsyncJob::Start(new Ipc::Strand
);
1512 /* at this point we are finished the synchronous startup. */
1517 if (mainLoop
.errcount
== 10)
1518 fatal_dump("Event loop exited with failure.");
1520 /* shutdown squid now */
1533 if (strcmp(Config
.pidFilename
, "none") == 0) {
1534 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1537 pid
= readPidFile();
1540 #if USE_WIN32_SERVICE
1542 if (opt_signal_service
) {
1543 WIN32_sendSignal(opt_send_signal
);
1546 #ifdef _SQUID_MSWIN_
1548 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1549 fprintf(stderr
, "signal to Squid Service:\n");
1550 fprintf(stderr
, "missing -n command line switch.\n");
1559 if (kill(pid
, opt_send_signal
) &&
1560 /* ignore permissions if just running check */
1561 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1562 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1563 fprintf(stderr
, "signal %d to process %d: %s\n",
1564 opt_send_signal
, (int) pid
, xstrerror());
1568 if (opt_send_signal
!= SIGTERM
) {
1569 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1572 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1577 /* signal successfully sent */
1581 #ifndef _SQUID_MSWIN_
1583 * This function is run when Squid is in daemon mode, just
1584 * before the parent forks and starts up the child process.
1585 * It can be used for admin-specific tasks, such as notifying
1586 * someone that Squid is (re)started.
1589 mainStartScript(const char *prog
)
1591 char script
[MAXPATHLEN
];
1596 xstrncpy(script
, prog
, MAXPATHLEN
);
1598 if ((t
= strrchr(script
, '/'))) {
1600 sl
= strlen(script
);
1603 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1605 if ((cpid
= fork()) == 0) {
1607 execl(script
, squid_start_script
, (char *)NULL
);
1613 rpid
= wait4(cpid
, &status
, 0, NULL
);
1617 rpid
= waitpid(cpid
, &status
, 0);
1620 } while (rpid
!= cpid
);
1624 #endif /* _SQUID_MSWIN_ */
1627 checkRunningPid(void)
1629 // master process must start alone, but its kids processes may co-exist
1630 if (!IamMasterProcess())
1638 pid
= readPidFile();
1643 if (kill(pid
, 0) < 0)
1646 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1652 watch_child(char *argv
[])
1654 #ifndef _SQUID_MSWIN_
1672 if (!IamMasterProcess())
1675 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1677 if ((pid
= fork()) < 0)
1678 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1683 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1689 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1690 ioctl(i
, TIOCNOTTY
, NULL
);
1697 * RBCOLLINS - if cygwin stackdumps when squid is run without
1698 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1699 * 1.1.3. execvp had a bit overflow error in a loop..
1701 /* Connect stdio to /dev/null in daemon mode */
1702 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1705 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1709 if (Debug::log_stderr
< 0) {
1714 // handle shutdown notifications from kids
1715 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1717 if (Config
.workers
> 128) {
1718 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1720 // but we keep going in hope that user knows best
1724 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1726 // keep [re]starting kids until it is time to quit
1728 mainStartScript(argv
[0]);
1730 // start each kid that needs to be [re]started; once
1731 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1732 Kid
& kid
= TheKids
.get(i
);
1733 if (!kid
.shouldRestart())
1736 if ((pid
= fork()) == 0) {
1738 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1740 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1742 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1746 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1747 kid
.name().termedBuf(), pid
);
1751 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1753 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1757 pid
= wait3(&status
, 0, NULL
);
1761 pid
= waitpid(-1, &status
, 0);
1764 // Loop to collect all stopped kids before we go to sleep below.
1766 Kid
* kid
= TheKids
.find(pid
);
1769 if (kid
->calledExit()) {
1771 "Squid Parent: %s process %d exited with status %d",
1772 kid
->name().termedBuf(),
1773 kid
->getPid(), kid
->exitStatus());
1774 } else if (kid
->signaled()) {
1776 "Squid Parent: %s process %d exited due to signal %d with status %d",
1777 kid
->name().termedBuf(),
1778 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1780 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1781 kid
->name().termedBuf(), kid
->getPid());
1783 if (kid
->hopeless()) {
1784 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1785 " be restarted due to repeated, frequent failures",
1786 kid
->name().termedBuf(), kid
->getPid());
1789 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1792 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1795 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1798 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1800 DeactivateRegistered(rrAfterConfig
);
1803 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1804 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1808 if (TheKids
.allHopeless()) {
1809 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1816 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1821 #endif /* _SQUID_MSWIN_ */
1828 /* XXX: This function is called after the main loop has quit, which
1829 * means that no AsyncCalls would be called, including close handlers.
1830 * TODO: We need to close/shut/free everything that needs calls before
1834 #if USE_WIN32_SERVICE
1835 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1838 debugs(1, 1, "Shutting down...");
1847 Ssl::Helper::GetInstance()->Shutdown();
1850 externalAclShutdown();
1851 icpConnectionClose();
1858 snmpConnectionClose();
1862 wccpConnectionClose();
1866 wccp2ConnectionClose();
1869 releaseServerSockets();
1870 commCloseAllSockets();
1877 DelayPools::FreePools();
1880 authenticateReset();
1882 #if USE_WIN32_SERVICE
1884 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1887 Store::Root().sync(); /* Flush pending object writes/unlinks */
1890 unlinkdClose(); /* after sync/flush */
1893 storeDirWriteCleanLogs(0);
1896 Store::Root().sync(); /* Flush log writes */
1899 Store::Root().sync(); /* Flush log close */
1900 StoreFileSystem::FreeAllFs();
1901 DiskIOModule::FreeAllModules();
1902 DeactivateRegistered(rrAfterConfig
);
1903 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1907 /*stmemFreeMemory(); */
1909 ipcacheFreeMemory();
1910 fqdncacheFreeMemory();
1912 clientdbFreeMemory();
1913 httpHeaderCleanModule();
1921 if (opt_no_daemon
) {
1936 xmalloc_find_leaks();
1938 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1947 if (IamPrimaryProcess()) {
1948 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1950 safeunlink(Config
.pidFilename
, 0);
1955 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1959 * We used to fclose(debug_log) here if it was set, but then
1960 * we forgot to set it to NULL. That caused some coredumps
1961 * because exit() ends up calling a bunch of destructors and
1962 * such. So rather than forcing the debug_log to close, we'll
1963 * leave it open so that those destructors can write some
1964 * debugging if necessary. The file will be closed anyway when
1965 * the process truly exits.
1968 exit(shutdown_status
);