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"
57 #include "fs/Module.h"
58 #include "fqdncache.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 "PeerSelectState.h"
78 #include "peer_sourcehash.h"
79 #include "peer_userhash.h"
80 #include "profiler/Profiler.h"
83 #include "send-announce.h"
84 #include "store_log.h"
86 #include "SquidConfig.h"
88 #include "SquidTime.h"
90 #include "StatCounters.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/helper.h"
124 #include "ssl/certificate_db.h"
127 #include "ssl/context_storage.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
156 #include "squid_windows.h"
159 static int opt_install_service
= FALSE
;
160 static int opt_remove_service
= FALSE
;
161 static int opt_signal_service
= FALSE
;
162 static int opt_command_line
= FALSE
;
163 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
164 void WINAPI
WIN32_svcHandler(DWORD
);
168 #if !defined(SQUID_BUILD_INFO)
169 #define SQUID_BUILD_INFO ""
172 static char *opt_syslog_facility
= NULL
;
173 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
174 static int configured_once
= 0;
176 static int malloc_debug_level
= 0;
178 static volatile int do_reconfigure
= 0;
179 static volatile int do_rotate
= 0;
180 static volatile int do_shutdown
= 0;
181 static volatile int shutdown_status
= 0;
183 static int RotateSignal
= -1;
184 static int ReconfigureSignal
= -1;
185 static int ShutdownSignal
= -1;
187 static void mainRotate(void);
188 static void mainReconfigureStart(void);
189 static void mainReconfigureFinish(void*);
190 static void mainInitialize(void);
191 static void usage(void);
192 static void mainParseOptions(int argc
, char *argv
[]);
193 static void sendSignal(void);
194 static void serverConnectionsOpen(void);
195 static void serverConnectionsClose(void);
196 static void watch_child(char **);
197 static void setEffectiveUser(void);
199 extern void log_trace_done();
200 extern void log_trace_init(char *);
202 static void SquidShutdown(void);
203 static void mainSetCwd(void);
204 static int checkRunningPid(void);
207 static const char *squid_start_script
= "squid_start";
211 #include "test_access.c"
214 /** temporary thunk across to the unrefactored store interface */
216 class StoreRootEngine
: public AsyncEngine
220 int checkEvents(int timeout
) {
221 Store::Root().callback();
226 class SignalEngine
: public AsyncEngine
230 SignalEngine(EventLoop
&evtLoop
) : loop(evtLoop
) {}
231 virtual int checkEvents(int timeout
);
234 static void StopEventLoop(void * data
) {
235 static_cast<SignalEngine
*>(data
)->loop
.stop();
238 void doShutdown(time_t wait
);
244 SignalEngine::checkEvents(int timeout
)
246 PROF_start(SignalEngine_checkEvents
);
248 if (do_reconfigure
) {
249 mainReconfigureStart();
251 } else if (do_rotate
) {
254 } else if (do_shutdown
) {
255 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
258 BroadcastSignalIfAny(DebugSignal
);
259 BroadcastSignalIfAny(RotateSignal
);
260 BroadcastSignalIfAny(ReconfigureSignal
);
261 BroadcastSignalIfAny(ShutdownSignal
);
263 PROF_stop(SignalEngine_checkEvents
);
268 SignalEngine::doShutdown(time_t wait
)
270 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
271 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
275 #if USE_WIN32_SERVICE
276 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
279 /* run the closure code which can be shared with reconfigure */
280 serverConnectionsClose();
282 /* detach the auth components (only do this on full shutdown) */
283 Auth::Scheme::FreeAll();
285 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
292 #if USE_WIN32_SERVICE
293 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
295 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
297 " -a port Specify HTTP port number (default: %d).\n"
298 " -d level Write debugging to stderr also.\n"
299 " -f file Use given config-file instead of\n"
301 " -h Print help message.\n"
302 #if USE_WIN32_SERVICE
303 " -i Installs as a Windows Service (see -n option).\n"
305 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
306 " Parse configuration file, then send signal to \n"
307 " running copy (except -k parse) and exit.\n"
308 #if USE_WIN32_SERVICE
309 " -n name Specify Windows Service name to use for service operations\n"
310 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
311 " -r Removes a Windows Service (see -n option).\n"
313 " -s | -l facility\n"
314 " Enable logging to syslog.\n"
315 " -u port Specify ICP port number (default: %d), disable with 0.\n"
316 " -v Print version.\n"
317 " -z Create swap directories\n"
318 " -C Do not catch fatal signals.\n"
319 " -D OBSOLETE. Scheduled for removal.\n"
320 " -F Don't serve any requests until store is rebuilt.\n"
321 " -N No daemon mode.\n"
322 #if USE_WIN32_SERVICE
324 " Set Windows Service Command line options in Registry.\n"
326 " -R Do not set REUSEADDR on port.\n"
327 " -S Double-check swap during rebuild.\n"
328 " -X Force full debugging.\n"
329 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
330 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
335 * Parse the parameters received via command line interface.
337 \param argc Number of options received on command line
338 \param argv List of parameters received on command line
341 mainParseOptions(int argc
, char *argv
[])
346 #if USE_WIN32_SERVICE
347 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
349 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
357 * Unset/disabel global option for catchign signals. opt_catch_signals */
358 opt_catch_signals
= 0;
363 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
364 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
369 * Set global option for foreground rebuild. opt_foreground_rebuild */
370 opt_foreground_rebuild
= 1;
375 * Set global option for 'no_daemon' mode. opt_no_daemon */
379 #if USE_WIN32_SERVICE
383 * Set global option. opt_command_lin and WIN32_Command_Line */
384 opt_command_line
= 1;
385 WIN32_Command_Line
= xstrdup(optarg
);
391 * Unset/disable global option opt_reuseaddr */
397 * Set global option opt_store_doublecheck */
398 opt_store_doublecheck
= 1;
403 * Force full debugging */
404 Debug::parseOptions("rotate=0 ALL,9");
405 Debug::override_X
= 1;
406 sigusr2_handle(SIGUSR2
);
411 * Set global option opt_reload_hit_only */
412 opt_reload_hit_only
= 1;
415 #if USE_WIN32_SERVICE
419 * Set global option opt_install_service (to TRUE) */
420 opt_install_service
= TRUE
;
426 * Add optional HTTP port as given following the option */
427 add_http_port(optarg
);
432 * Set global option Debug::log_stderr to the number given follwoign the option */
433 Debug::log_stderr
= atoi(optarg
);
438 * Load the file given instead of the default squid.conf. */
440 ConfigFile
= xstrdup(optarg
);
445 * Run the administrative action given following the option */
447 /** \li When its an unknown option display the usage help. */
448 if ((int) strlen(optarg
) < 1)
451 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
452 /** \li On reconfigure send SIGHUP. */
453 opt_send_signal
= SIGHUP
;
454 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
455 /** \li On rotate send SIGQUIT or SIGUSR1. */
456 #if defined(_SQUID_LINUX_THREADS_)
457 opt_send_signal
= SIGQUIT
;
459 opt_send_signal
= SIGUSR1
;
462 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
463 /** \li On debug send SIGTRAP or SIGUSR2. */
464 #if defined(_SQUID_LINUX_THREADS_)
465 opt_send_signal
= SIGTRAP
;
467 opt_send_signal
= SIGUSR2
;
470 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
471 /** \li On shutdown send SIGTERM. */
472 opt_send_signal
= SIGTERM
;
473 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
474 /** \li On interrupt send SIGINT. */
475 opt_send_signal
= SIGINT
;
476 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
477 /** \li On kill send SIGKILL. */
478 opt_send_signal
= SIGKILL
;
482 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
483 /** \li On restart send SIGTTIN. (exit and restart by parent) */
484 opt_send_signal
= SIGTTIN
;
488 else if (!strncmp(optarg
, "check", strlen(optarg
)))
489 /** \li On check send 0 / SIGNULL. */
490 opt_send_signal
= 0; /* SIGNULL */
491 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
492 /** \li On parse set global flag to re-parse the config file only. */
493 opt_parse_cfg_only
= 1;
501 * Set global malloc_debug_level to the value given following the option.
502 * if none is given it toggles the xmalloc_trace option on/off */
505 malloc_debug_level
= atoi(optarg
);
507 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
512 xmalloc_trace
= !xmalloc_trace
;
514 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
519 #if USE_WIN32_SERVICE
523 * Set global option opt_signal_service (to TRUE).
524 * Stores the additional parameter given in global WIN32_Service_name */
525 xfree(WIN32_Service_name
);
527 WIN32_Service_name
= xstrdup(optarg
);
529 opt_signal_service
= TRUE
;
535 * Set global option opt_remove_service (to TRUE) */
536 opt_remove_service
= TRUE
;
544 * Stores the syslog facility name in global opt_syslog_facility
545 * then performs actions for -s option. */
546 opt_syslog_facility
= xstrdup(optarg
);
550 * Initialize the syslog for output */
553 _db_set_syslog(opt_syslog_facility
);
559 fatal("Logging to syslog not available on this platform");
566 * Store the ICP port number given in global option icpPortNumOverride
567 * ensuring its a positive number. */
568 icpPortNumOverride
= atoi(optarg
);
570 if (icpPortNumOverride
< 0)
571 icpPortNumOverride
= 0;
577 * Display squid version and build information. Then exit. */
578 printf("Squid Cache: Version %s\n" ,version_string
);
579 if (strlen(SQUID_BUILD_INFO
))
580 printf("%s\n",SQUID_BUILD_INFO
);
581 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
583 #if USE_WIN32_SERVICE
585 printf("Compiled as Windows System Service.\n");
595 * Set global option Debug::log_stderr and opt_create_swap_dirs */
596 Debug::log_stderr
= 1;
597 opt_create_swap_dirs
= 1;
605 /** \par h,?, or unknown
606 * \copydoc usage() */
624 signal(sig
, rotate_logs
);
634 ReconfigureSignal
= sig
;
638 signal(sig
, reconfigure
);
646 do_shutdown
= sig
== SIGINT
? -1 : 1;
647 ShutdownSignal
= sig
;
655 const pid_t ppid
= getppid();
657 if (!IamMasterProcess() && ppid
> 1) {
658 // notify master that we are shutting down
659 if (kill(ppid
, SIGUSR1
) < 0)
660 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
661 " pid " << ppid
<< ": " << xstrerror());
667 if (!IamMasterProcess() && ppid
> 1) {
668 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
670 if (kill(ppid
, sig
) < 0)
671 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
674 #endif /* KILL_PARENT_OPT */
675 #if SA_RESETHAND == 0
676 signal(SIGTERM
, SIG_DFL
);
678 signal(SIGINT
, SIG_DFL
);
685 serverConnectionsOpen(void)
687 if (IamPrimaryProcess()) {
689 wccpConnectionOpen();
694 wccp2ConnectionOpen();
697 // start various proxying services if we are responsible for them
698 if (IamWorkerProcess()) {
699 clientOpenListenSockets();
719 peerSourceHashInit();
724 serverConnectionsClose(void)
726 assert(shutting_down
|| reconfiguring
);
728 if (IamPrimaryProcess()) {
731 wccpConnectionClose();
735 wccp2ConnectionClose();
738 if (IamWorkerProcess()) {
739 clientHttpConnectionsClose();
740 icpConnectionShutdown();
742 htcpSocketShutdown();
755 mainReconfigureStart(void)
757 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
760 // Initiate asynchronous closing sequence
761 serverConnectionsClose();
768 Ssl::Helper::GetInstance()->Shutdown();
771 Ssl::TheGlobalContextStorage
.reconfigureStart();
777 externalAclShutdown();
778 storeDirCloseSwapLogs();
785 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
790 mainReconfigureFinish(void *)
792 debugs(1, 3, "finishing reconfiguring");
795 enter_suid(); /* root to read config file */
797 // we may have disabled the need for PURGE
798 if (Config2
.onoff
.enable_purge
)
799 Config2
.onoff
.enable_purge
= 2;
801 // parse the config returns a count of errors encountered.
802 const int oldWorkers
= Config
.workers
;
803 if ( parseConfigFile(ConfigFile
) != 0) {
804 // for now any errors are a fatal condition...
807 if (oldWorkers
!= Config
.workers
) {
808 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
809 oldWorkers
<< " to " << Config
.workers
<<
810 ") is not supported and ignored");
811 Config
.workers
= oldWorkers
;
814 if (IamPrimaryProcess())
816 CpuAffinityReconfigure();
818 setUmask(Config
.umask
);
821 _db_init(Debug::cache_log
, Debug::debugOptions
);
822 ipcache_restart(); /* clear stuck entries */
823 fqdncache_restart(); /* sigh, fqdncache too */
825 errorInitialize(); /* reload error pages */
828 #if USE_LOADABLE_MODULES
829 LoadableModulesConfigure(Config
.loadable_module_names
);
833 bool enableAdaptation
= false;
835 Adaptation::Icap::TheConfig
.finalize();
836 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
839 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
840 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
842 Adaptation::Config::Finalize(enableAdaptation
);
851 Ssl::Helper::GetInstance()->Init();
856 authenticateInit(&Auth::TheConfig
);
860 if (IamPrimaryProcess()) {
871 serverConnectionsOpen();
875 storeDirOpenSwapLogs();
877 mimeInit(Config
.mimeTablePathname
);
883 Config
.ClientDelay
.finalize();
886 if (Config
.onoff
.announce
) {
887 if (!eventFind(start_announce
, NULL
))
888 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
890 if (eventFind(start_announce
, NULL
))
891 eventDelete(start_announce
, NULL
);
894 writePidFile(); /* write PID file */
908 authenticateRotate();
910 externalAclShutdown();
912 _db_rotate_log(); /* cache.log */
913 storeDirWriteCleanLogs(1);
914 storeLogRotate(); /* store.log */
915 accessLogRotate(); /* access.log */
917 icapLogRotate(); /*icap.log*/
925 authenticateInit(&Auth::TheConfig
);
931 setEffectiveUser(void)
934 leave_suid(); /* Run as non privilegied user */
940 if (geteuid() == 0) {
941 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
942 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
943 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
944 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
945 fatal("Don't run Squid as root, set 'cache_effective_user'!");
952 char pathbuf
[MAXPATHLEN
];
954 if (Config
.coredump_dir
) {
955 if (0 == strcmp("none", Config
.coredump_dir
)) {
957 } else if (chdir(Config
.coredump_dir
) == 0) {
958 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
961 debugs(50, DBG_CRITICAL
, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
965 /* If we don't have coredump_dir or couldn't cd there, report current dir */
966 if (getcwd(pathbuf
, MAXPATHLEN
)) {
967 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
969 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
976 /* chroot if configured to run inside chroot */
978 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
979 fatal("failed to chroot");
982 if (opt_catch_signals
) {
983 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
984 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
987 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
988 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
992 if (icpPortNumOverride
!= 1)
993 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
995 _db_init(Debug::cache_log
, Debug::debugOptions
);
997 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1001 log_trace_init("/tmp/squid.alloc");
1005 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1008 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1009 debugs(1, DBG_CRITICAL
, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
1010 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1012 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1015 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1017 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1020 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1024 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1026 if (WIN32_Socks_initialized
)
1027 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1029 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1030 WIN32_IpAddrChangeMonitorInit();
1035 if (!configured_once
)
1036 disk_init(); /* disk_init must go before ipcache_init() */
1047 Ssl::Helper::GetInstance()->Init();
1052 authenticateInit(&Auth::TheConfig
);
1056 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1058 httpReplyInitModule(); /* must go before accepting replies */
1079 malloc_debug(0, malloc_debug_level
);
1083 if (!configured_once
) {
1084 if (unlinkdNeeded())
1091 /* after this point we want to see the mallinfo() output */
1093 mimeInit(Config
.mimeTablePathname
);
1099 FwdState::initModule();
1100 /* register the modules in the cache manager menus */
1102 cbdataRegisterWithCacheManager();
1103 /* These use separate calls so that the comm loops can eventually
1109 // TODO: pconn is a good candidate for new-style registration
1110 // PconnModule::GetInstance()->registerWithCacheManager();
1111 // moved to PconnModule::PconnModule()
1114 if (IamPrimaryProcess()) {
1126 serverConnectionsOpen();
1130 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1132 if (Config
.chroot_dir
)
1135 if (!configured_once
)
1136 writePidFile(); /* write PID file */
1138 #if defined(_SQUID_LINUX_THREADS_)
1140 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1142 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1146 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1148 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1152 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1154 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1156 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1160 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1166 #if USE_LOADABLE_MODULES
1167 LoadableModulesConfigure(Config
.loadable_module_names
);
1171 bool enableAdaptation
= false;
1173 // We can remove this dependency on specific adaptation mechanisms
1174 // if we create a generic Registry of such mechanisms. Should we?
1176 Adaptation::Icap::TheConfig
.finalize();
1177 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1180 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1181 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1183 // must be the last adaptation-related finalize
1184 Adaptation::Config::Finalize(enableAdaptation
);
1192 Config
.ClientDelay
.finalize();
1195 if (!configured_once
) {
1196 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1198 if (Config
.onoff
.announce
)
1199 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1201 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1203 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1207 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1211 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1214 configured_once
= 1;
1217 /// unsafe main routine -- may throw
1218 int SquidMain(int argc
, char **argv
);
1219 /// unsafe main routine wrapper to catch exceptions
1220 static int SquidMainSafe(int argc
, char **argv
);
1222 #if USE_WIN32_SERVICE
1223 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1224 extern "C" void WINAPI
1225 SquidWinSvcMain(int argc
, char **argv
)
1227 SquidMainSafe(argc
, argv
);
1231 main(int argc
, char **argv
)
1233 return SquidMainSafe(argc
, argv
);
1238 SquidMainSafe(int argc
, char **argv
)
1241 return SquidMain(argc
, argv
);
1242 } catch (const std::exception
&e
) {
1243 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1247 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1250 return -1; // not reached
1253 /// computes name and ID for the current kid process
1255 ConfigureCurrentKid(const char *processName
)
1257 // kids are marked with parenthesis around their process names
1258 if (processName
&& processName
[0] == '(') {
1259 if (const char *idStart
= strrchr(processName
, '-')) {
1260 KidIdentifier
= atoi(idStart
+ 1);
1261 const size_t nameLen
= idStart
- (processName
+ 1);
1262 assert(nameLen
< sizeof(TheKidName
));
1263 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1264 if (!strcmp(TheKidName
, "squid-coord"))
1265 TheProcessKind
= pkCoordinator
;
1266 else if (!strcmp(TheKidName
, "squid"))
1267 TheProcessKind
= pkWorker
;
1268 else if (!strcmp(TheKidName
, "squid-disk"))
1269 TheProcessKind
= pkDisker
;
1271 TheProcessKind
= pkOther
; // including coordinator
1274 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1280 SquidMain(int argc
, char **argv
)
1282 ConfigureCurrentKid(argv
[0]);
1285 sbrk_start
= sbrk(0);
1288 Debug::parseOptions(NULL
);
1291 #if defined(SQUID_MAXFD_LIMIT)
1293 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1294 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1298 /* NOP under non-windows */
1299 int WIN32_init_err
=0;
1300 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1301 return WIN32_init_err
;
1303 /* call mallopt() before anything else */
1306 /* Round up all sizes to a multiple of this */
1307 mallopt(M_GRAIN
, 16);
1311 /* biggest size that is considered a small block */
1312 mallopt(M_MXFAST
, 256);
1316 /* allocate this many small blocks at once */
1317 mallopt(M_NLBLKS
, 32);
1320 #endif /* HAVE_MALLOPT */
1322 squid_srandom(time(NULL
));
1326 squid_start
= current_time
;
1328 failure_notify
= fatal_dump
;
1330 #if USE_WIN32_SERVICE
1332 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1336 mainParseOptions(argc
, argv
);
1338 if (opt_parse_cfg_only
) {
1339 Debug::parseOptions("ALL,1");
1342 #if USE_WIN32_SERVICE
1344 if (opt_install_service
) {
1345 WIN32_InstallService();
1349 if (opt_remove_service
) {
1350 WIN32_RemoveService();
1354 if (opt_command_line
) {
1355 WIN32_SetServiceCommandLine();
1361 /* parse configuration file
1362 * note: in "normal" case this used to be called from mainInitialize() */
1367 ConfigFile
= xstrdup(DefaultConfigFile
);
1369 assert(!configured_once
);
1373 storeFsInit(); /* required for config parsing */
1375 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1378 /* May not be needed for parsing, have not audited for such */
1379 DiskIOModule::SetupAllModules();
1381 /* Shouldn't be needed for config parsing, but have not audited for such */
1382 StoreFileSystem::SetupAllFs();
1384 /* we may want the parsing process to set this up in the future */
1385 Store::Root(new StoreController
);
1386 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1387 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1389 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1391 parse_err
= parseConfigFile(ConfigFile
);
1395 if (opt_parse_cfg_only
|| parse_err
> 0)
1398 setUmask(Config
.umask
);
1399 if (-1 == opt_send_signal
)
1400 if (checkRunningPid())
1415 /* send signal to running copy and exit */
1416 if (opt_send_signal
!= -1) {
1417 /* chroot if configured to run inside chroot */
1419 if (Config
.chroot_dir
) {
1420 if (chroot(Config
.chroot_dir
))
1421 fatal("failed to chroot");
1432 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1434 ActivateRegistered(rrFinalizeConfig
);
1435 ActivateRegistered(rrClaimMemoryNeeds
);
1436 ActivateRegistered(rrAfterConfig
);
1439 if (!opt_no_daemon
&& Config
.workers
> 0)
1442 if (opt_create_swap_dirs
) {
1443 /* chroot if configured to run inside chroot */
1445 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1446 fatal("failed to chroot");
1450 debugs(0, DBG_CRITICAL
, "Creating Swap Directories");
1451 Store::Root().create();
1456 if (IamPrimaryProcess())
1462 /* init comm module */
1465 if (opt_no_daemon
) {
1466 /* we have to init fdstat here. */
1467 fd_open(0, FD_LOG
, "stdin");
1468 fd_open(1, FD_LOG
, "stdout");
1469 fd_open(2, FD_LOG
, "stderr");
1472 #if USE_WIN32_SERVICE
1474 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1480 #if USE_WIN32_SERVICE
1482 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1489 SignalEngine
signalEngine(mainLoop
);
1491 mainLoop
.registerEngine(&signalEngine
);
1493 /* TODO: stop requiring the singleton here */
1494 mainLoop
.registerEngine(EventScheduler::GetInstance());
1496 StoreRootEngine store_engine
;
1498 mainLoop
.registerEngine(&store_engine
);
1500 CommSelectEngine comm_engine
;
1502 mainLoop
.registerEngine(&comm_engine
);
1504 mainLoop
.setPrimaryEngine(&comm_engine
);
1506 /* use the standard time service */
1507 TimeEngine time_engine
;
1509 mainLoop
.setTimeService(&time_engine
);
1511 if (IamCoordinatorProcess())
1512 AsyncJob::Start(Ipc::Coordinator::Instance());
1513 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1514 AsyncJob::Start(new Ipc::Strand
);
1516 /* at this point we are finished the synchronous startup. */
1521 if (mainLoop
.errcount
== 10)
1522 fatal_dump("Event loop exited with failure.");
1524 /* shutdown squid now */
1537 if (strcmp(Config
.pidFilename
, "none") == 0) {
1538 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1541 pid
= readPidFile();
1544 #if USE_WIN32_SERVICE
1545 if (opt_signal_service
) {
1546 WIN32_sendSignal(opt_send_signal
);
1549 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1550 fprintf(stderr
, "signal to Squid Service:\n");
1551 fprintf(stderr
, "missing -n command line switch.\n");
1557 if (kill(pid
, opt_send_signal
) &&
1558 /* ignore permissions if just running check */
1559 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1560 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1561 fprintf(stderr
, "signal %d to process %d: %s\n",
1562 opt_send_signal
, (int) pid
, xstrerror());
1566 if (opt_send_signal
!= SIGTERM
) {
1567 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1570 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1575 /* signal successfully sent */
1581 * This function is run when Squid is in daemon mode, just
1582 * before the parent forks and starts up the child process.
1583 * It can be used for admin-specific tasks, such as notifying
1584 * someone that Squid is (re)started.
1587 mainStartScript(const char *prog
)
1589 char script
[MAXPATHLEN
];
1594 xstrncpy(script
, prog
, MAXPATHLEN
);
1596 if ((t
= strrchr(script
, '/'))) {
1598 sl
= strlen(script
);
1601 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1603 if ((cpid
= fork()) == 0) {
1605 execl(script
, squid_start_script
, (char *)NULL
);
1611 rpid
= wait4(cpid
, &status
, 0, NULL
);
1615 rpid
= waitpid(cpid
, &status
, 0);
1618 } while (rpid
!= cpid
);
1622 #endif /* _SQUID_MSWIN_ */
1625 checkRunningPid(void)
1627 // master process must start alone, but its kids processes may co-exist
1628 if (!IamMasterProcess())
1636 pid
= readPidFile();
1641 if (kill(pid
, 0) < 0)
1644 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1650 watch_child(char *argv
[])
1670 if (!IamMasterProcess())
1673 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1675 if ((pid
= fork()) < 0)
1676 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1681 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1687 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1688 ioctl(i
, TIOCNOTTY
, NULL
);
1695 * RBCOLLINS - if cygwin stackdumps when squid is run without
1696 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1697 * 1.1.3. execvp had a bit overflow error in a loop..
1699 /* Connect stdio to /dev/null in daemon mode */
1700 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1703 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1707 if (Debug::log_stderr
< 0) {
1712 // handle shutdown notifications from kids
1713 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1715 if (Config
.workers
> 128) {
1716 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1718 // but we keep going in hope that user knows best
1722 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1724 // keep [re]starting kids until it is time to quit
1726 mainStartScript(argv
[0]);
1728 // start each kid that needs to be [re]started; once
1729 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1730 Kid
& kid
= TheKids
.get(i
);
1731 if (!kid
.shouldRestart())
1734 if ((pid
= fork()) == 0) {
1736 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1738 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1740 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1744 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1745 kid
.name().termedBuf(), pid
);
1749 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1751 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1755 pid
= wait3(&status
, 0, NULL
);
1759 pid
= waitpid(-1, &status
, 0);
1762 // Loop to collect all stopped kids before we go to sleep below.
1764 Kid
* kid
= TheKids
.find(pid
);
1767 if (kid
->calledExit()) {
1769 "Squid Parent: %s process %d exited with status %d",
1770 kid
->name().termedBuf(),
1771 kid
->getPid(), kid
->exitStatus());
1772 } else if (kid
->signaled()) {
1774 "Squid Parent: %s process %d exited due to signal %d with status %d",
1775 kid
->name().termedBuf(),
1776 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1778 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1779 kid
->name().termedBuf(), kid
->getPid());
1781 if (kid
->hopeless()) {
1782 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1783 " be restarted due to repeated, frequent failures",
1784 kid
->name().termedBuf(), kid
->getPid());
1787 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1790 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1793 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1796 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1798 DeactivateRegistered(rrAfterConfig
);
1799 DeactivateRegistered(rrClaimMemoryNeeds
);
1800 DeactivateRegistered(rrFinalizeConfig
);
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, DBG_IMPORTANT
, "Shutting down...");
1841 Ssl::Helper::GetInstance()->Shutdown();
1844 externalAclShutdown();
1854 wccpConnectionClose();
1858 wccp2ConnectionClose();
1861 releaseServerSockets();
1862 commCloseAllSockets();
1869 DelayPools::FreePools();
1872 authenticateReset();
1874 #if USE_WIN32_SERVICE
1876 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1879 Store::Root().sync(); /* Flush pending object writes/unlinks */
1881 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1883 storeDirWriteCleanLogs(0);
1886 Store::Root().sync(); /* Flush log writes */
1889 Store::Root().sync(); /* Flush log close */
1890 StoreFileSystem::FreeAllFs();
1891 DiskIOModule::FreeAllModules();
1892 DeactivateRegistered(rrAfterConfig
);
1893 DeactivateRegistered(rrClaimMemoryNeeds
);
1894 DeactivateRegistered(rrFinalizeConfig
);
1895 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1899 /*stmemFreeMemory(); */
1901 ipcacheFreeMemory();
1902 fqdncacheFreeMemory();
1904 clientdbFreeMemory();
1905 httpHeaderCleanModule();
1913 if (opt_no_daemon
) {
1920 // clear StoreController
1931 xmalloc_find_leaks();
1933 debugs(1, DBG_CRITICAL
, "Memory used after shutdown: " << xmalloc_total
);
1942 if (IamPrimaryProcess()) {
1943 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1945 safeunlink(Config
.pidFilename
, 0);
1950 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1954 * We used to fclose(debug_log) here if it was set, but then
1955 * we forgot to set it to NULL. That caused some coredumps
1956 * because exit() ends up calling a bunch of destructors and
1957 * such. So rather than forcing the debug_log to close, we'll
1958 * leave it open so that those destructors can write some
1959 * debugging if necessary. The file will be closed anyway when
1960 * the process truly exits.
1963 exit(shutdown_status
);