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"
40 #include "auth/Gadgets.h"
41 #include "base/TextException.h"
42 #include "ConfigParser.h"
43 #include "CpuAffinity.h"
44 #include "errorpage.h"
46 #include "EventLoop.h"
47 #include "ExternalACL.h"
50 #include "ident/Ident.h"
51 #include "HttpReply.h"
57 #include "StoreFileSystem.h"
58 #include "DiskIO/DiskIOModule.h"
61 #include "ipc/Coordinator.h"
62 #include "ipc/Strand.h"
65 #include "comm_epoll.h"
68 #include "comm_kqueue.h"
71 #include "comm_poll.h"
73 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
74 #include "comm_select.h"
76 #include "SquidTime.h"
80 #include "icmp/IcmpSquid.h"
81 #include "icmp/net_db.h"
83 #if USE_LOADABLE_MODULES
84 #include "LoadableModules.h"
88 #include "adaptation/icap/Config.h"
91 #include "adaptation/ecap/Config.h"
94 #include "adaptation/Config.h"
98 #include "esi/Module.h"
101 #include "fs/Module.h"
103 #if USE_WIN32_SERVICE
105 #include "squid_windows.h"
108 static int opt_install_service
= FALSE
;
109 static int opt_remove_service
= FALSE
;
110 static int opt_signal_service
= FALSE
;
111 static int opt_command_line
= FALSE
;
112 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
113 void WINAPI
WIN32_svcHandler(DWORD
);
117 #ifndef SQUID_BUILD_INFO
118 #define SQUID_BUILD_INFO ""
121 /** for error reporting from xmalloc and friends */
122 SQUIDCEXTERN
void (*failure_notify
) (const char *);
124 static int opt_parse_cfg_only
= 0;
125 static char *opt_syslog_facility
= NULL
;
126 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
127 static int configured_once
= 0;
129 static int malloc_debug_level
= 0;
131 static volatile int do_reconfigure
= 0;
132 static volatile int do_rotate
= 0;
133 static volatile int do_shutdown
= 0;
134 static volatile int shutdown_status
= 0;
136 static int RotateSignal
= -1;
137 static int ReconfigureSignal
= -1;
138 static int ShutdownSignal
= -1;
140 static void mainRotate(void);
141 static void mainReconfigureStart(void);
142 static void mainReconfigureFinish(void*);
143 static void mainInitialize(void);
144 static void usage(void);
145 static void mainParseOptions(int argc
, char *argv
[]);
146 static void sendSignal(void);
147 static void serverConnectionsOpen(void);
148 static void serverConnectionsClose(void);
149 static void watch_child(char **);
150 static void setEffectiveUser(void);
152 extern void log_trace_done();
153 extern void log_trace_init(char *);
155 static void SquidShutdown(void);
156 static void mainSetCwd(void);
157 static int checkRunningPid(void);
159 #ifndef _SQUID_MSWIN_
160 static const char *squid_start_script
= "squid_start";
164 #include "test_access.c"
167 /** temporary thunk across to the unrefactored store interface */
169 class StoreRootEngine
: public AsyncEngine
173 int checkEvents(int timeout
) {
174 Store::Root().callback();
179 class SignalEngine
: public AsyncEngine
183 SignalEngine(EventLoop
&evtLoop
) : loop(evtLoop
) {}
184 virtual int checkEvents(int timeout
);
187 static void StopEventLoop(void * data
) {
188 static_cast<SignalEngine
*>(data
)->loop
.stop();
191 void doShutdown(time_t wait
);
197 SignalEngine::checkEvents(int timeout
)
199 PROF_start(SignalEngine_checkEvents
);
201 if (do_reconfigure
) {
202 mainReconfigureStart();
204 } else if (do_rotate
) {
207 } else if (do_shutdown
) {
208 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
211 BroadcastSignalIfAny(DebugSignal
);
212 BroadcastSignalIfAny(RotateSignal
);
213 BroadcastSignalIfAny(ReconfigureSignal
);
214 BroadcastSignalIfAny(ShutdownSignal
);
216 PROF_stop(SignalEngine_checkEvents
);
221 SignalEngine::doShutdown(time_t wait
)
223 debugs(1, 1, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
224 debugs(1, 1, "Waiting " << wait
<< " seconds for active connections to finish");
228 #if USE_WIN32_SERVICE
229 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
232 /* run the closure code which can be shared with reconfigure */
233 serverConnectionsClose();
235 /* detach the auth components (only do this on full shutdown) */
236 AuthScheme::FreeAll();
238 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
245 #if USE_WIN32_SERVICE
246 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
248 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
250 " -a port Specify HTTP port number (default: %d).\n"
251 " -d level Write debugging to stderr also.\n"
252 " -f file Use given config-file instead of\n"
254 " -h Print help message.\n"
255 #if USE_WIN32_SERVICE
256 " -i Installs as a Windows Service (see -n option).\n"
258 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
259 " Parse configuration file, then send signal to \n"
260 " running copy (except -k parse) and exit.\n"
261 #if USE_WIN32_SERVICE
262 " -n name Specify Windows Service name to use for service operations\n"
263 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
264 " -r Removes a Windows Service (see -n option).\n"
266 " -s | -l facility\n"
267 " Enable logging to syslog.\n"
268 " -u port Specify ICP port number (default: %d), disable with 0.\n"
269 " -v Print version.\n"
270 " -z Create swap directories\n"
271 " -C Do not catch fatal signals.\n"
272 " -D OBSOLETE. Scheduled for removal.\n"
273 " -F Don't serve any requests until store is rebuilt.\n"
274 " -N No daemon mode.\n"
275 #if USE_WIN32_SERVICE
277 " Set Windows Service Command line options in Registry.\n"
279 " -R Do not set REUSEADDR on port.\n"
280 " -S Double-check swap during rebuild.\n"
281 " -X Force full debugging.\n"
282 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
283 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
288 * Parse the parameters received via command line interface.
290 \param argc Number of options received on command line
291 \param argv List of parameters received on command line
294 mainParseOptions(int argc
, char *argv
[])
299 #if USE_WIN32_SERVICE
300 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
302 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
310 * Unset/disabel global option for catchign signals. opt_catch_signals */
311 opt_catch_signals
= 0;
316 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
317 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
322 * Set global option for foreground rebuild. opt_foreground_rebuild */
323 opt_foreground_rebuild
= 1;
328 * Set global option for 'no_daemon' mode. opt_no_daemon */
332 #if USE_WIN32_SERVICE
336 * Set global option. opt_command_lin and WIN32_Command_Line */
337 opt_command_line
= 1;
338 WIN32_Command_Line
= xstrdup(optarg
);
344 * Unset/disable global option opt_reuseaddr */
350 * Set global option opt_store_doublecheck */
351 opt_store_doublecheck
= 1;
356 * Force full debugging */
357 Debug::parseOptions("rotate=0 ALL,9");
358 Debug::override_X
= 1;
359 sigusr2_handle(SIGUSR2
);
364 * Set global option opt_reload_hit_only */
365 opt_reload_hit_only
= 1;
368 #if USE_WIN32_SERVICE
372 * Set global option opt_install_service (to TRUE) */
373 opt_install_service
= TRUE
;
379 * Add optional HTTP port as given following the option */
380 add_http_port(optarg
);
385 * Set global option Debug::log_stderr to the number given follwoign the option */
386 Debug::log_stderr
= atoi(optarg
);
391 * Load the file given instead of the default squid.conf. */
393 ConfigFile
= xstrdup(optarg
);
398 * Run the administrative action given following the option */
400 /** \li When its an unknown option display the usage help. */
401 if ((int) strlen(optarg
) < 1)
404 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
405 /** \li On reconfigure send SIGHUP. */
406 opt_send_signal
= SIGHUP
;
407 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
408 /** \li On rotate send SIGQUIT or SIGUSR1. */
409 #ifdef _SQUID_LINUX_THREADS_
411 opt_send_signal
= SIGQUIT
;
415 opt_send_signal
= SIGUSR1
;
419 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
420 /** \li On debug send SIGTRAP or SIGUSR2. */
421 #ifdef _SQUID_LINUX_THREADS_
423 opt_send_signal
= SIGTRAP
;
427 opt_send_signal
= SIGUSR2
;
431 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
432 /** \li On shutdown send SIGTERM. */
433 opt_send_signal
= SIGTERM
;
434 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
435 /** \li On interrupt send SIGINT. */
436 opt_send_signal
= SIGINT
;
437 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
438 /** \li On kill send SIGKILL. */
439 opt_send_signal
= SIGKILL
;
443 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
444 /** \li On restart send SIGTTIN. (exit and restart by parent) */
445 opt_send_signal
= SIGTTIN
;
449 else if (!strncmp(optarg
, "check", strlen(optarg
)))
450 /** \li On check send 0 / SIGNULL. */
451 opt_send_signal
= 0; /* SIGNULL */
452 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
453 /** \li On parse set global flag to re-parse the config file only. */
454 opt_parse_cfg_only
= 1;
462 * Set global malloc_debug_level to the value given following the option.
463 * if none is given it toggles the xmalloc_trace option on/off */
466 malloc_debug_level
= atoi(optarg
);
468 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
473 xmalloc_trace
= !xmalloc_trace
;
475 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
480 #if USE_WIN32_SERVICE
484 * Set global option opt_signal_service (to TRUE).
485 * Stores the additional parameter given in global WIN32_Service_name */
486 xfree(WIN32_Service_name
);
488 WIN32_Service_name
= xstrdup(optarg
);
490 opt_signal_service
= TRUE
;
496 * Set global option opt_remove_service (to TRUE) */
497 opt_remove_service
= TRUE
;
505 * Stores the syslog facility name in global opt_syslog_facility
506 * then performs actions for -s option. */
507 opt_syslog_facility
= xstrdup(optarg
);
511 * Initialize the syslog for output */
514 _db_set_syslog(opt_syslog_facility
);
520 fatal("Logging to syslog not available on this platform");
527 * Store the ICP port number given in global option icpPortNumOverride
528 * ensuring its a positive number. */
529 icpPortNumOverride
= atoi(optarg
);
531 if (icpPortNumOverride
< 0)
532 icpPortNumOverride
= 0;
538 * Display squid version and build information. Then exit. */
539 printf("Squid Cache: Version %s\n" ,version_string
);
540 if (strlen(SQUID_BUILD_INFO
))
541 printf("%s\n",SQUID_BUILD_INFO
);
542 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
544 #if USE_WIN32_SERVICE
546 printf("Compiled as Windows System Service.\n");
556 * Set global option Debug::log_stderr and opt_create_swap_dirs */
557 Debug::log_stderr
= 1;
558 opt_create_swap_dirs
= 1;
566 /** \par h,?, or unknown
567 * \copydoc usage() */
582 #ifndef _SQUID_MSWIN_
585 signal(sig
, rotate_logs
);
595 ReconfigureSignal
= sig
;
596 #ifndef _SQUID_MSWIN_
599 signal(sig
, reconfigure
);
607 do_shutdown
= sig
== SIGINT
? -1 : 1;
608 ShutdownSignal
= sig
;
615 #ifndef _SQUID_MSWIN_
619 debugs(1, 1, "Killing master process, pid " << getppid());
621 if (kill(getppid(), sig
) < 0)
622 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
625 #endif /* KILL_PARENT_OPT */
626 #if SA_RESETHAND == 0
627 signal(SIGTERM
, SIG_DFL
);
629 signal(SIGINT
, SIG_DFL
);
636 serverConnectionsOpen(void)
638 if (IamPrimaryProcess()) {
641 wccpConnectionOpen();
646 wccp2ConnectionOpen();
649 // Coordinator does not start proxying services
650 if (!IamCoordinatorProcess()) {
651 clientOpenListenSockets();
652 icpConnectionsOpen();
659 snmpConnectionOpen();
671 peerSourceHashInit();
676 serverConnectionsClose(void)
678 assert(shutting_down
|| reconfiguring
);
680 if (IamPrimaryProcess()) {
683 wccpConnectionClose();
687 wccp2ConnectionClose();
690 if (!IamCoordinatorProcess()) {
691 clientHttpConnectionsClose();
692 icpConnectionShutdown();
695 htcpSocketShutdown();
701 snmpConnectionShutdown();
709 mainReconfigureStart(void)
711 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
714 // Initiate asynchronous closing sequence
715 serverConnectionsClose();
716 icpConnectionClose();
723 snmpConnectionClose();
735 externalAclShutdown();
736 storeDirCloseSwapLogs();
745 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
750 mainReconfigureFinish(void *)
752 debugs(1, 3, "finishing reconfiguring");
755 enter_suid(); /* root to read config file */
757 // we may have disabled the need for PURGE
758 if (Config2
.onoff
.enable_purge
)
759 Config2
.onoff
.enable_purge
= 2;
761 // parse the config returns a count of errors encountered.
762 const int oldWorkers
= Config
.workers
;
763 if ( parseConfigFile(ConfigFile
) != 0) {
764 // for now any errors are a fatal condition...
767 if (oldWorkers
!= Config
.workers
) {
768 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
769 oldWorkers
<< " to " << Config
.workers
<<
770 ") is not supported and ignored");
771 Config
.workers
= oldWorkers
;
774 if (IamPrimaryProcess())
776 CpuAffinityReconfigure();
778 setUmask(Config
.umask
);
781 _db_init(Debug::cache_log
, Debug::debugOptions
);
782 ipcache_restart(); /* clear stuck entries */
783 fqdncache_restart(); /* sigh, fqdncache too */
785 errorInitialize(); /* reload error pages */
788 #if USE_LOADABLE_MODULES
789 LoadableModulesConfigure(Config
.loadable_module_names
);
793 bool enableAdaptation
= false;
795 Adaptation::Icap::TheConfig
.finalize();
796 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
799 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
800 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
802 Adaptation::Config::Finalize(enableAdaptation
);
820 authenticateInit(&Auth::TheConfig
);
823 if (IamPrimaryProcess()) {
834 serverConnectionsOpen();
838 storeDirOpenSwapLogs();
840 mimeInit(Config
.mimeTablePathname
);
842 if (Config
.onoff
.announce
) {
843 if (!eventFind(start_announce
, NULL
))
844 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
846 if (eventFind(start_announce
, NULL
))
847 eventDelete(start_announce
, NULL
);
850 writePidFile(); /* write PID file */
852 debugs(1, 1, "Ready to serve requests.");
865 authenticateRotate();
866 externalAclShutdown();
868 _db_rotate_log(); /* cache.log */
869 storeDirWriteCleanLogs(1);
870 storeLogRotate(); /* store.log */
871 accessLogRotate(); /* access.log */
872 useragentRotateLog(); /* useragent.log */
873 refererRotateLog(); /* referer.log */
875 icapLogRotate(); /*icap.log*/
886 authenticateInit(&Auth::TheConfig
);
891 setEffectiveUser(void)
894 leave_suid(); /* Run as non privilegied user */
900 if (geteuid() == 0) {
901 debugs(0, 0, "Squid is not safe to run as root! If you must");
902 debugs(0, 0, "start Squid as root, then you must configure");
903 debugs(0, 0, "it to run as a non-priveledged user with the");
904 debugs(0, 0, "'cache_effective_user' option in the config file.");
905 fatal("Don't run Squid as root, set 'cache_effective_user'!");
912 char pathbuf
[MAXPATHLEN
];
914 if (Config
.coredump_dir
) {
915 if (0 == strcmp("none", Config
.coredump_dir
)) {
917 } else if (chdir(Config
.coredump_dir
) == 0) {
918 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
921 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
925 /* If we don't have coredump_dir or couldn't cd there, report current dir */
926 if (getcwd(pathbuf
, MAXPATHLEN
)) {
927 debugs(0, 1, "Current Directory is " << pathbuf
);
929 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
934 #include "DelayPools.h"
940 /* chroot if configured to run inside chroot */
942 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
943 fatal("failed to chroot");
946 if (opt_catch_signals
) {
947 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
948 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
951 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
952 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
956 if (icpPortNumOverride
!= 1)
957 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
959 _db_init(Debug::cache_log
, Debug::debugOptions
);
961 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
965 log_trace_init("/tmp/squid.alloc");
969 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
973 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
974 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
975 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
977 debugs(1, 0, "Running on " << WIN32_OS_string
);
981 debugs(1, 1, "Process ID " << getpid());
983 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
987 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
989 if (WIN32_Socks_initialized
)
990 debugs(1, 1, "Windows sockets initialized");
992 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
993 WIN32_IpAddrChangeMonitorInit();
998 if (!configured_once
)
999 disk_init(); /* disk_init must go before ipcache_init() */
1019 authenticateInit(&Auth::TheConfig
);
1027 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1029 httpReplyInitModule(); /* must go before accepting replies */
1050 malloc_debug(0, malloc_debug_level
);
1054 if (!configured_once
) {
1063 /* after this point we want to see the mallinfo() output */
1065 mimeInit(Config
.mimeTablePathname
);
1072 FwdState::initModule();
1073 /* register the modules in the cache manager menus */
1075 cbdataRegisterWithCacheManager();
1076 /* These use separate calls so that the comm loops can eventually
1082 // TODO: pconn is a good candidate for new-style registration
1083 // PconnModule::GetInstance()->registerWithCacheManager();
1084 // moved to PconnModule::PconnModule()
1087 if (IamPrimaryProcess()) {
1099 serverConnectionsOpen();
1103 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1105 if (Config
.chroot_dir
)
1108 if (!configured_once
)
1109 writePidFile(); /* write PID file */
1111 #ifdef _SQUID_LINUX_THREADS_
1113 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1115 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1119 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1121 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1125 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1127 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1129 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1133 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1139 #if USE_LOADABLE_MODULES
1140 LoadableModulesConfigure(Config
.loadable_module_names
);
1144 bool enableAdaptation
= false;
1146 // We can remove this dependency on specific adaptation mechanisms
1147 // if we create a generic Registry of such mechanisms. Should we?
1149 Adaptation::Icap::TheConfig
.finalize();
1150 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1153 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1154 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1156 // must be the last adaptation-related finalize
1157 Adaptation::Config::Finalize(enableAdaptation
);
1164 debugs(1, 1, "Ready to serve requests.");
1166 if (!configured_once
) {
1167 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1169 if (Config
.onoff
.announce
)
1170 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1172 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1174 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1178 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1182 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1185 configured_once
= 1;
1188 /// unsafe main routine -- may throw
1189 int SquidMain(int argc
, char **argv
);
1190 /// unsafe main routine wrapper to catch exceptions
1191 static int SquidMainSafe(int argc
, char **argv
);
1193 #if USE_WIN32_SERVICE
1194 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1195 extern "C" void WINAPI
1196 SquidWinSvcMain(int argc
, char **argv
)
1198 SquidMainSafe(argc
, argv
);
1202 main(int argc
, char **argv
)
1204 return SquidMainSafe(argc
, argv
);
1209 SquidMainSafe(int argc
, char **argv
)
1212 return SquidMain(argc
, argv
);
1213 } catch (const std::exception
&e
) {
1214 std::cerr
<< "dying from an unhandled exception: " << e
.what() << std::endl
;
1217 std::cerr
<< "dying from an unhandled exception." << std::endl
;
1220 return -1; // not reached
1223 /// computes name and ID for the current kid process
1225 ConfigureCurrentKid(const char *processName
)
1227 // kids are marked with parenthesis around their process names
1228 if (processName
&& processName
[0] == '(') {
1229 if (const char *idStart
= strrchr(processName
, '-')) {
1230 KidIdentifier
= atoi(idStart
+ 1);
1231 const size_t nameLen
= idStart
- (processName
+ 1);
1232 assert(nameLen
< sizeof(TheKidName
));
1233 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1236 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1242 SquidMain(int argc
, char **argv
)
1244 ConfigureCurrentKid(argv
[0]);
1246 #ifdef _SQUID_WIN32_
1253 sbrk_start
= sbrk(0);
1256 Debug::parseOptions(NULL
);
1259 #if defined(SQUID_MAXFD_LIMIT)
1261 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1262 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1266 #ifdef _SQUID_WIN32_
1268 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1269 return WIN32_init_err
;
1273 /* call mallopt() before anything else */
1276 /* Round up all sizes to a multiple of this */
1277 mallopt(M_GRAIN
, 16);
1281 /* biggest size that is considered a small block */
1282 mallopt(M_MXFAST
, 256);
1286 /* allocate this many small blocks at once */
1287 mallopt(M_NLBLKS
, 32);
1290 #endif /* HAVE_MALLOPT */
1292 squid_srandom(time(NULL
));
1296 squid_start
= current_time
;
1298 failure_notify
= fatal_dump
;
1300 #if USE_WIN32_SERVICE
1302 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1306 mainParseOptions(argc
, argv
);
1308 if (opt_parse_cfg_only
) {
1309 Debug::parseOptions("ALL,1");
1312 #if USE_WIN32_SERVICE
1314 if (opt_install_service
) {
1315 WIN32_InstallService();
1319 if (opt_remove_service
) {
1320 WIN32_RemoveService();
1324 if (opt_command_line
) {
1325 WIN32_SetServiceCommandLine();
1331 /* parse configuration file
1332 * note: in "normal" case this used to be called from mainInitialize() */
1337 ConfigFile
= xstrdup(DefaultConfigFile
);
1339 assert(!configured_once
);
1343 storeFsInit(); /* required for config parsing */
1345 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1348 /* May not be needed for parsing, have not audited for such */
1349 DiskIOModule::SetupAllModules();
1351 /* Shouldn't be needed for config parsing, but have not audited for such */
1352 StoreFileSystem::SetupAllFs();
1354 /* we may want the parsing process to set this up in the future */
1355 Store::Root(new StoreController
);
1357 InitAuthSchemes(); /* required for config parsing */
1359 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1361 parse_err
= parseConfigFile(ConfigFile
);
1365 if (opt_parse_cfg_only
|| parse_err
> 0)
1368 setUmask(Config
.umask
);
1369 if (-1 == opt_send_signal
)
1370 if (checkRunningPid())
1387 /* send signal to running copy and exit */
1388 if (opt_send_signal
!= -1) {
1389 /* chroot if configured to run inside chroot */
1391 if (Config
.chroot_dir
) {
1392 if (chroot(Config
.chroot_dir
))
1393 fatal("failed to chroot");
1404 if (!opt_no_daemon
&& Config
.workers
> 0)
1407 if (opt_create_swap_dirs
) {
1408 /* chroot if configured to run inside chroot */
1410 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1411 fatal("failed to chroot");
1415 debugs(0, 0, "Creating Swap Directories");
1416 Store::Root().create();
1421 if (IamPrimaryProcess())
1427 /* init comm module */
1432 if (opt_no_daemon
) {
1433 /* we have to init fdstat here. */
1434 fd_open(0, FD_LOG
, "stdin");
1435 fd_open(1, FD_LOG
, "stdout");
1436 fd_open(2, FD_LOG
, "stderr");
1439 #if USE_WIN32_SERVICE
1441 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1447 #if USE_WIN32_SERVICE
1449 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1456 SignalEngine
signalEngine(mainLoop
);
1458 mainLoop
.registerEngine(&signalEngine
);
1460 /* TODO: stop requiring the singleton here */
1461 mainLoop
.registerEngine(EventScheduler::GetInstance());
1463 StoreRootEngine store_engine
;
1465 mainLoop
.registerEngine(&store_engine
);
1467 CommSelectEngine comm_engine
;
1469 mainLoop
.registerEngine(&comm_engine
);
1471 mainLoop
.setPrimaryEngine(&comm_engine
);
1473 /* use the standard time service */
1474 TimeEngine time_engine
;
1476 mainLoop
.setTimeService(&time_engine
);
1478 if (IamCoordinatorProcess())
1479 AsyncJob::Start(Ipc::Coordinator::Instance());
1480 else if (UsingSmp() && IamWorkerProcess())
1481 AsyncJob::Start(new Ipc::Strand
);
1483 /* at this point we are finished the synchronous startup. */
1488 if (mainLoop
.errcount
== 10)
1489 fatal_dump("Event loop exited with failure.");
1491 /* shutdown squid now */
1504 if (strcmp(Config
.pidFilename
, "none") == 0) {
1505 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1508 pid
= readPidFile();
1511 #if USE_WIN32_SERVICE
1513 if (opt_signal_service
) {
1514 WIN32_sendSignal(opt_send_signal
);
1517 #ifdef _SQUID_MSWIN_
1519 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1520 fprintf(stderr
, "signal to Squid Service:\n");
1521 fprintf(stderr
, "missing -n command line switch.\n");
1530 if (kill(pid
, opt_send_signal
) &&
1531 /* ignore permissions if just running check */
1532 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1533 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1534 fprintf(stderr
, "signal %d to process %d: %s\n",
1535 opt_send_signal
, (int) pid
, xstrerror());
1539 if (opt_send_signal
!= SIGTERM
) {
1540 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1543 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1548 /* signal successfully sent */
1552 #ifndef _SQUID_MSWIN_
1554 * This function is run when Squid is in daemon mode, just
1555 * before the parent forks and starts up the child process.
1556 * It can be used for admin-specific tasks, such as notifying
1557 * someone that Squid is (re)started.
1560 mainStartScript(const char *prog
)
1562 char script
[MAXPATHLEN
];
1567 xstrncpy(script
, prog
, MAXPATHLEN
);
1569 if ((t
= strrchr(script
, '/'))) {
1571 sl
= strlen(script
);
1574 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1576 if ((cpid
= fork()) == 0) {
1578 execl(script
, squid_start_script
, (char *)NULL
);
1584 rpid
= wait4(cpid
, &status
, 0, NULL
);
1588 rpid
= waitpid(cpid
, &status
, 0);
1591 } while (rpid
!= cpid
);
1595 #endif /* _SQUID_MSWIN_ */
1598 checkRunningPid(void)
1600 // master process must start alone, but its kids processes may co-exist
1601 if (!IamMasterProcess())
1609 pid
= readPidFile();
1614 if (kill(pid
, 0) < 0)
1617 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1623 watch_child(char *argv
[])
1625 #ifndef _SQUID_MSWIN_
1643 if (!IamMasterProcess())
1646 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1648 if ((pid
= fork()) < 0)
1649 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1654 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1660 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1661 ioctl(i
, TIOCNOTTY
, NULL
);
1668 * RBCOLLINS - if cygwin stackdumps when squid is run without
1669 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1670 * 1.1.3. execvp had a bit overflow error in a loop..
1672 /* Connect stdio to /dev/null in daemon mode */
1673 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1676 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1680 if (Debug::log_stderr
< 0) {
1685 if (Config
.workers
> 128) {
1686 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1688 // but we keep going in hope that user knows best
1690 TheKids
.init(Config
.workers
);
1692 // keep [re]starting kids until it is time to quit
1694 mainStartScript(argv
[0]);
1696 // start each kid that needs to be [re]started; once
1697 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1698 Kid
& kid
= TheKids
.get(i
);
1699 if (kid
.hopeless() || kid
.exitedHappy() || kid
.running())
1702 if ((pid
= fork()) == 0) {
1704 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1706 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1708 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1712 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1716 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1718 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1722 pid
= wait3(&status
, 0, NULL
);
1726 pid
= waitpid(-1, &status
, 0);
1729 // Loop to collect all stopped kids before we go to sleep below.
1731 Kid
* kid
= TheKids
.find(pid
);
1734 if (kid
->calledExit()) {
1736 "Squid Parent: child process %d exited with status %d",
1737 kid
->getPid(), kid
->exitStatus());
1738 } else if (kid
->signaled()) {
1740 "Squid Parent: child process %d exited due to signal %d with status %d",
1741 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1743 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", kid
->getPid());
1746 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1749 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1752 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1755 if (TheKids
.allExitedHappy()) {
1759 if (TheKids
.allHopeless()) {
1760 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1764 if (TheKids
.allSignaled(SIGKILL
)) {
1768 if (TheKids
.allSignaled(SIGINT
) || TheKids
.allSignaled(SIGTERM
)) {
1769 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1773 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1778 #endif /* _SQUID_MSWIN_ */
1785 /* XXX: This function is called after the main loop has quit, which
1786 * means that no AsyncCalls would be called, including close handlers.
1787 * TODO: We need to close/shut/free everything that needs calls before
1791 #if USE_WIN32_SERVICE
1792 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1795 debugs(1, 1, "Shutting down...");
1805 externalAclShutdown();
1806 icpConnectionClose();
1813 snmpConnectionClose();
1817 wccpConnectionClose();
1821 wccp2ConnectionClose();
1824 releaseServerSockets();
1825 commCloseAllSockets();
1833 DelayPools::FreePools();
1836 authenticateReset();
1837 #if USE_WIN32_SERVICE
1839 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1842 Store::Root().sync(); /* Flush pending object writes/unlinks */
1845 unlinkdClose(); /* after sync/flush */
1848 storeDirWriteCleanLogs(0);
1851 Store::Root().sync(); /* Flush log writes */
1854 useragentLogClose();
1861 Store::Root().sync(); /* Flush log close */
1862 StoreFileSystem::FreeAllFs();
1863 DiskIOModule::FreeAllModules();
1864 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1868 /*stmemFreeMemory(); */
1870 ipcacheFreeMemory();
1871 fqdncacheFreeMemory();
1873 clientdbFreeMemory();
1874 httpHeaderCleanModule();
1882 if (opt_no_daemon
) {
1897 xmalloc_find_leaks();
1899 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1908 if (IamPrimaryProcess()) {
1909 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1911 safeunlink(Config
.pidFilename
, 0);
1916 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1920 * We used to fclose(debug_log) here if it was set, but then
1921 * we forgot to set it to NULL. That caused some coredumps
1922 * because exit() ends up calling a bunch of destructors and
1923 * such. So rather than forcing the debug_log to close, we'll
1924 * leave it open so that those destructors can write some
1925 * debugging if necessary. The file will be closed anyway when
1926 * the process truly exits.
1929 exit(shutdown_status
);