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"
40 #include "adaptation/Config.h"
43 #include "adaptation/ecap/Config.h"
46 #include "adaptation/icap/Config.h"
47 #include "adaptation/icap/icap_log.h"
49 #include "auth/Gadgets.h"
50 #include "base/Subscription.h"
51 #include "base/TextException.h"
54 #include "comm_epoll.h"
57 #include "comm_kqueue.h"
60 #include "comm_poll.h"
62 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
63 #include "comm_select.h"
65 #include "ConfigParser.h"
66 #include "DiskIO/DiskIOModule.h"
67 #include "errorpage.h"
69 #include "esi/Module.h"
72 #include "EventLoop.h"
73 #include "ExternalACL.h"
75 #include "fs/Module.h"
77 #include "HttpReply.h"
78 #include "icmp/IcmpSquid.h"
79 #include "icmp/net_db.h"
81 #include "ident/Ident.h"
83 #include "ipc/Coordinator.h"
85 #include "ipc/Strand.h"
86 #if USE_LOADABLE_MODULES
87 #include "LoadableModules.h"
92 #include "PeerSelectState.h"
93 #include "SquidTime.h"
95 #include "StoreFileSystem.h"
101 #include "squid_windows.h"
104 static int opt_install_service
= FALSE
;
105 static int opt_remove_service
= FALSE
;
106 static int opt_signal_service
= FALSE
;
107 static int opt_command_line
= FALSE
;
108 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
109 void WINAPI
WIN32_svcHandler(DWORD
);
113 #ifndef SQUID_BUILD_INFO
114 #define SQUID_BUILD_INFO ""
117 /** for error reporting from xmalloc and friends */
118 SQUIDCEXTERN
void (*failure_notify
) (const char *);
120 static int opt_parse_cfg_only
= 0;
121 static char *opt_syslog_facility
= NULL
;
122 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
123 static int configured_once
= 0;
125 static int malloc_debug_level
= 0;
127 static volatile int do_reconfigure
= 0;
128 static volatile int do_rotate
= 0;
129 static volatile int do_shutdown
= 0;
130 static volatile int shutdown_status
= 0;
132 static int RotateSignal
= -1;
133 static int ReconfigureSignal
= -1;
134 static int ShutdownSignal
= -1;
136 static void mainRotate(void);
137 static void mainReconfigureStart(void);
138 static void mainReconfigureFinish(void*);
139 static void mainInitialize(void);
140 static void usage(void);
141 static void mainParseOptions(int argc
, char *argv
[]);
142 static void sendSignal(void);
143 static void serverConnectionsOpen(void);
144 static void serverConnectionsClose(void);
145 static void watch_child(char **);
146 static void setEffectiveUser(void);
148 extern void log_trace_done();
149 extern void log_trace_init(char *);
151 static void SquidShutdown(void);
152 static void mainSetCwd(void);
153 static int checkRunningPid(void);
155 #ifndef _SQUID_MSWIN_
156 static const char *squid_start_script
= "squid_start";
160 #include "test_access.c"
163 /** temporary thunk across to the unrefactored store interface */
165 class StoreRootEngine
: public AsyncEngine
169 int checkEvents(int timeout
) {
170 Store::Root().callback();
175 class SignalEngine
: public AsyncEngine
179 SignalEngine(EventLoop
&evtLoop
) : loop(evtLoop
) {}
180 virtual int checkEvents(int timeout
);
183 static void StopEventLoop(void * data
) {
184 static_cast<SignalEngine
*>(data
)->loop
.stop();
187 void doShutdown(time_t wait
);
193 SignalEngine::checkEvents(int timeout
)
195 PROF_start(SignalEngine_checkEvents
);
197 if (do_reconfigure
) {
198 mainReconfigureStart();
200 } else if (do_rotate
) {
203 } else if (do_shutdown
) {
204 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
207 BroadcastSignalIfAny(DebugSignal
);
208 BroadcastSignalIfAny(RotateSignal
);
209 BroadcastSignalIfAny(ReconfigureSignal
);
210 BroadcastSignalIfAny(ShutdownSignal
);
212 PROF_stop(SignalEngine_checkEvents
);
217 SignalEngine::doShutdown(time_t wait
)
219 debugs(1, 1, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
220 debugs(1, 1, "Waiting " << wait
<< " seconds for active connections to finish");
224 #if USE_WIN32_SERVICE
225 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
228 /* run the closure code which can be shared with reconfigure */
229 serverConnectionsClose();
231 /* detach the auth components (only do this on full shutdown) */
232 AuthScheme::FreeAll();
234 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
241 #if USE_WIN32_SERVICE
242 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
244 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
246 " -a port Specify HTTP port number (default: %d).\n"
247 " -d level Write debugging to stderr also.\n"
248 " -f file Use given config-file instead of\n"
250 " -h Print help message.\n"
251 #if USE_WIN32_SERVICE
252 " -i Installs as a Windows Service (see -n option).\n"
254 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
255 " Parse configuration file, then send signal to \n"
256 " running copy (except -k parse) and exit.\n"
257 #if USE_WIN32_SERVICE
258 " -n name Specify Windows Service name to use for service operations\n"
259 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
260 " -r Removes a Windows Service (see -n option).\n"
262 " -s | -l facility\n"
263 " Enable logging to syslog.\n"
264 " -u port Specify ICP port number (default: %d), disable with 0.\n"
265 " -v Print version.\n"
266 " -z Create swap directories\n"
267 " -C Do not catch fatal signals.\n"
268 " -D OBSOLETE. Scheduled for removal.\n"
269 " -F Don't serve any requests until store is rebuilt.\n"
270 " -N No daemon mode.\n"
271 #if USE_WIN32_SERVICE
273 " Set Windows Service Command line options in Registry.\n"
275 " -R Do not set REUSEADDR on port.\n"
276 " -S Double-check swap during rebuild.\n"
277 " -X Force full debugging.\n"
278 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
279 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
284 * Parse the parameters received via command line interface.
286 \param argc Number of options received on command line
287 \param argv List of parameters received on command line
290 mainParseOptions(int argc
, char *argv
[])
295 #if USE_WIN32_SERVICE
296 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
298 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
306 * Unset/disabel global option for catchign signals. opt_catch_signals */
307 opt_catch_signals
= 0;
312 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
313 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
318 * Set global option for foreground rebuild. opt_foreground_rebuild */
319 opt_foreground_rebuild
= 1;
324 * Set global option for 'no_daemon' mode. opt_no_daemon */
328 #if USE_WIN32_SERVICE
332 * Set global option. opt_command_lin and WIN32_Command_Line */
333 opt_command_line
= 1;
334 WIN32_Command_Line
= xstrdup(optarg
);
340 * Unset/disable global option opt_reuseaddr */
346 * Set global option opt_store_doublecheck */
347 opt_store_doublecheck
= 1;
352 * Force full debugging */
353 Debug::parseOptions("rotate=0 ALL,9");
354 Debug::override_X
= 1;
355 sigusr2_handle(SIGUSR2
);
360 * Set global option opt_reload_hit_only */
361 opt_reload_hit_only
= 1;
364 #if USE_WIN32_SERVICE
368 * Set global option opt_install_service (to TRUE) */
369 opt_install_service
= TRUE
;
375 * Add optional HTTP port as given following the option */
376 add_http_port(optarg
);
381 * Set global option Debug::log_stderr to the number given follwoign the option */
382 Debug::log_stderr
= atoi(optarg
);
387 * Load the file given instead of the default squid.conf. */
389 ConfigFile
= xstrdup(optarg
);
394 * Run the administrative action given following the option */
396 /** \li When its an unknown option display the usage help. */
397 if ((int) strlen(optarg
) < 1)
400 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
401 /** \li On reconfigure send SIGHUP. */
402 opt_send_signal
= SIGHUP
;
403 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
404 /** \li On rotate send SIGQUIT or SIGUSR1. */
405 #ifdef _SQUID_LINUX_THREADS_
407 opt_send_signal
= SIGQUIT
;
411 opt_send_signal
= SIGUSR1
;
415 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
416 /** \li On debug send SIGTRAP or SIGUSR2. */
417 #ifdef _SQUID_LINUX_THREADS_
419 opt_send_signal
= SIGTRAP
;
423 opt_send_signal
= SIGUSR2
;
427 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
428 /** \li On shutdown send SIGTERM. */
429 opt_send_signal
= SIGTERM
;
430 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
431 /** \li On interrupt send SIGINT. */
432 opt_send_signal
= SIGINT
;
433 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
434 /** \li On kill send SIGKILL. */
435 opt_send_signal
= SIGKILL
;
439 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
440 /** \li On restart send SIGTTIN. (exit and restart by parent) */
441 opt_send_signal
= SIGTTIN
;
445 else if (!strncmp(optarg
, "check", strlen(optarg
)))
446 /** \li On check send 0 / SIGNULL. */
447 opt_send_signal
= 0; /* SIGNULL */
448 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
449 /** \li On parse set global flag to re-parse the config file only. */
450 opt_parse_cfg_only
= 1;
458 * Set global malloc_debug_level to the value given following the option.
459 * if none is given it toggles the xmalloc_trace option on/off */
462 malloc_debug_level
= atoi(optarg
);
464 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
469 xmalloc_trace
= !xmalloc_trace
;
471 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
476 #if USE_WIN32_SERVICE
480 * Set global option opt_signal_service (to TRUE).
481 * Stores the additional parameter given in global WIN32_Service_name */
482 xfree(WIN32_Service_name
);
484 WIN32_Service_name
= xstrdup(optarg
);
486 opt_signal_service
= TRUE
;
492 * Set global option opt_remove_service (to TRUE) */
493 opt_remove_service
= TRUE
;
501 * Stores the syslog facility name in global opt_syslog_facility
502 * then performs actions for -s option. */
503 opt_syslog_facility
= xstrdup(optarg
);
507 * Initialize the syslog for output */
510 _db_set_syslog(opt_syslog_facility
);
516 fatal("Logging to syslog not available on this platform");
523 * Store the ICP port number given in global option icpPortNumOverride
524 * ensuring its a positive number. */
525 icpPortNumOverride
= atoi(optarg
);
527 if (icpPortNumOverride
< 0)
528 icpPortNumOverride
= 0;
534 * Display squid version and build information. Then exit. */
535 printf("Squid Cache: Version %s\n" ,version_string
);
536 if (strlen(SQUID_BUILD_INFO
))
537 printf("%s\n",SQUID_BUILD_INFO
);
538 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
540 #if USE_WIN32_SERVICE
542 printf("Compiled as Windows System Service.\n");
552 * Set global option Debug::log_stderr and opt_create_swap_dirs */
553 Debug::log_stderr
= 1;
554 opt_create_swap_dirs
= 1;
562 /** \par h,?, or unknown
563 * \copydoc usage() */
578 #ifndef _SQUID_MSWIN_
581 signal(sig
, rotate_logs
);
591 ReconfigureSignal
= sig
;
592 #ifndef _SQUID_MSWIN_
595 signal(sig
, reconfigure
);
603 do_shutdown
= sig
== SIGINT
? -1 : 1;
604 ShutdownSignal
= sig
;
611 #ifndef _SQUID_MSWIN_
615 debugs(1, 1, "Killing master process, pid " << getppid());
617 if (kill(getppid(), sig
) < 0)
618 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
621 #endif /* KILL_PARENT_OPT */
622 #if SA_RESETHAND == 0
623 signal(SIGTERM
, SIG_DFL
);
625 signal(SIGINT
, SIG_DFL
);
632 serverConnectionsOpen(void)
634 if (IamPrimaryProcess()) {
637 wccpConnectionOpen();
642 wccp2ConnectionOpen();
645 // Coordinator does not start proxying services
646 if (!IamCoordinatorProcess()) {
647 clientOpenListenSockets();
648 icpConnectionsOpen();
655 snmpConnectionOpen();
667 peerSourceHashInit();
672 serverConnectionsClose(void)
674 assert(shutting_down
|| reconfiguring
);
676 if (IamPrimaryProcess()) {
679 wccpConnectionClose();
683 wccp2ConnectionClose();
686 if (!IamCoordinatorProcess()) {
687 clientHttpConnectionsClose();
688 icpConnectionShutdown();
691 htcpSocketShutdown();
697 snmpConnectionShutdown();
705 mainReconfigureStart(void)
707 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
710 // Initiate asynchronous closing sequence
711 serverConnectionsClose();
712 icpConnectionClose();
719 snmpConnectionClose();
731 externalAclShutdown();
732 storeDirCloseSwapLogs();
741 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
746 mainReconfigureFinish(void *)
748 debugs(1, 3, "finishing reconfiguring");
751 enter_suid(); /* root to read config file */
753 // we may have disabled the need for PURGE
754 if (Config2
.onoff
.enable_purge
)
755 Config2
.onoff
.enable_purge
= 2;
757 // parse the config returns a count of errors encountered.
758 const int oldWorkers
= Config
.workers
;
759 if ( parseConfigFile(ConfigFile
) != 0) {
760 // for now any errors are a fatal condition...
763 if (oldWorkers
!= Config
.workers
) {
764 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
765 oldWorkers
<< " to " << Config
.workers
<<
766 ") is not supported and ignored");
767 Config
.workers
= oldWorkers
;
770 setUmask(Config
.umask
);
773 _db_init(Debug::cache_log
, Debug::debugOptions
);
774 ipcache_restart(); /* clear stuck entries */
775 fqdncache_restart(); /* sigh, fqdncache too */
777 errorInitialize(); /* reload error pages */
780 #if USE_LOADABLE_MODULES
781 LoadableModulesConfigure(Config
.loadable_module_names
);
785 bool enableAdaptation
= false;
787 Adaptation::Icap::TheConfig
.finalize();
788 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
791 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
792 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
794 Adaptation::Config::Finalize(enableAdaptation
);
812 authenticateInit(&Auth::TheConfig
);
815 if (IamPrimaryProcess()) {
826 serverConnectionsOpen();
830 storeDirOpenSwapLogs();
832 mimeInit(Config
.mimeTablePathname
);
834 if (Config
.onoff
.announce
) {
835 if (!eventFind(start_announce
, NULL
))
836 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
838 if (eventFind(start_announce
, NULL
))
839 eventDelete(start_announce
, NULL
);
842 writePidFile(); /* write PID file */
844 debugs(1, 1, "Ready to serve requests.");
857 authenticateRotate();
858 externalAclShutdown();
860 _db_rotate_log(); /* cache.log */
861 storeDirWriteCleanLogs(1);
862 storeLogRotate(); /* store.log */
863 accessLogRotate(); /* access.log */
864 useragentRotateLog(); /* useragent.log */
865 refererRotateLog(); /* referer.log */
867 icapLogRotate(); /*icap.log*/
878 authenticateInit(&Auth::TheConfig
);
883 setEffectiveUser(void)
886 leave_suid(); /* Run as non privilegied user */
892 if (geteuid() == 0) {
893 debugs(0, 0, "Squid is not safe to run as root! If you must");
894 debugs(0, 0, "start Squid as root, then you must configure");
895 debugs(0, 0, "it to run as a non-priveledged user with the");
896 debugs(0, 0, "'cache_effective_user' option in the config file.");
897 fatal("Don't run Squid as root, set 'cache_effective_user'!");
904 char pathbuf
[MAXPATHLEN
];
906 if (Config
.coredump_dir
) {
907 if (0 == strcmp("none", Config
.coredump_dir
)) {
909 } else if (chdir(Config
.coredump_dir
) == 0) {
910 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
913 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
917 /* If we don't have coredump_dir or couldn't cd there, report current dir */
918 if (getcwd(pathbuf
, MAXPATHLEN
)) {
919 debugs(0, 1, "Current Directory is " << pathbuf
);
921 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
926 #include "DelayPools.h"
932 /* chroot if configured to run inside chroot */
934 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
935 fatal("failed to chroot");
938 if (opt_catch_signals
) {
939 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
940 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
943 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
944 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
948 if (icpPortNumOverride
!= 1)
949 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
951 _db_init(Debug::cache_log
, Debug::debugOptions
);
953 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
957 log_trace_init("/tmp/squid.alloc");
961 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
965 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
966 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
967 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
969 debugs(1, 0, "Running on " << WIN32_OS_string
);
973 debugs(1, 1, "Process ID " << getpid());
975 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
979 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
981 if (WIN32_Socks_initialized
)
982 debugs(1, 1, "Windows sockets initialized");
984 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
985 WIN32_IpAddrChangeMonitorInit();
990 if (!configured_once
)
991 disk_init(); /* disk_init must go before ipcache_init() */
1011 authenticateInit(&Auth::TheConfig
);
1019 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1021 httpReplyInitModule(); /* must go before accepting replies */
1042 malloc_debug(0, malloc_debug_level
);
1046 if (!configured_once
) {
1055 /* after this point we want to see the mallinfo() output */
1057 mimeInit(Config
.mimeTablePathname
);
1064 FwdState::initModule();
1065 /* register the modules in the cache manager menus */
1067 cbdataRegisterWithCacheManager();
1068 /* These use separate calls so that the comm loops can eventually
1074 // TODO: pconn is a good candidate for new-style registration
1075 // PconnModule::GetInstance()->registerWithCacheManager();
1076 // moved to PconnModule::PconnModule()
1079 if (IamPrimaryProcess()) {
1091 serverConnectionsOpen();
1095 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1097 if (Config
.chroot_dir
)
1100 if (!configured_once
)
1101 writePidFile(); /* write PID file */
1103 #ifdef _SQUID_LINUX_THREADS_
1105 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1107 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1111 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1113 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1117 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1119 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1121 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1125 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1131 #if USE_LOADABLE_MODULES
1132 LoadableModulesConfigure(Config
.loadable_module_names
);
1136 bool enableAdaptation
= false;
1138 // We can remove this dependency on specific adaptation mechanisms
1139 // if we create a generic Registry of such mechanisms. Should we?
1141 Adaptation::Icap::TheConfig
.finalize();
1142 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1145 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1146 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1148 // must be the last adaptation-related finalize
1149 Adaptation::Config::Finalize(enableAdaptation
);
1156 debugs(1, 1, "Ready to serve requests.");
1158 if (!configured_once
) {
1159 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1161 if (Config
.onoff
.announce
)
1162 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1164 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1166 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1170 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1174 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1177 configured_once
= 1;
1180 /// unsafe main routine -- may throw
1181 int SquidMain(int argc
, char **argv
);
1182 /// unsafe main routine wrapper to catch exceptions
1183 static int SquidMainSafe(int argc
, char **argv
);
1185 #if USE_WIN32_SERVICE
1186 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1187 extern "C" void WINAPI
1188 SquidWinSvcMain(int argc
, char **argv
)
1190 SquidMainSafe(argc
, argv
);
1194 main(int argc
, char **argv
)
1196 return SquidMainSafe(argc
, argv
);
1201 SquidMainSafe(int argc
, char **argv
)
1204 return SquidMain(argc
, argv
);
1205 } catch (const std::exception
&e
) {
1206 std::cerr
<< "dying from an unhandled exception: " << e
.what() << std::endl
;
1209 std::cerr
<< "dying from an unhandled exception." << std::endl
;
1212 return -1; // not reached
1215 /// computes name and ID for the current kid process
1217 ConfigureCurrentKid(const char *processName
)
1219 // kids are marked with parenthesis around their process names
1220 if (processName
&& processName
[0] == '(') {
1221 if (const char *idStart
= strrchr(processName
, '-')) {
1222 KidIdentifier
= atoi(idStart
+ 1);
1223 const size_t nameLen
= idStart
- (processName
+ 1);
1224 assert(nameLen
< sizeof(TheKidName
));
1225 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1228 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1234 SquidMain(int argc
, char **argv
)
1236 ConfigureCurrentKid(argv
[0]);
1238 #ifdef _SQUID_WIN32_
1245 sbrk_start
= sbrk(0);
1248 Debug::parseOptions(NULL
);
1251 #if defined(SQUID_MAXFD_LIMIT)
1253 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1254 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1258 #ifdef _SQUID_WIN32_
1260 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1261 return WIN32_init_err
;
1265 /* call mallopt() before anything else */
1268 /* Round up all sizes to a multiple of this */
1269 mallopt(M_GRAIN
, 16);
1273 /* biggest size that is considered a small block */
1274 mallopt(M_MXFAST
, 256);
1278 /* allocate this many small blocks at once */
1279 mallopt(M_NLBLKS
, 32);
1282 #endif /* HAVE_MALLOPT */
1284 squid_srandom(time(NULL
));
1288 squid_start
= current_time
;
1290 failure_notify
= fatal_dump
;
1292 #if USE_WIN32_SERVICE
1294 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1298 mainParseOptions(argc
, argv
);
1300 if (opt_parse_cfg_only
) {
1301 Debug::parseOptions("ALL,1");
1304 #if USE_WIN32_SERVICE
1306 if (opt_install_service
) {
1307 WIN32_InstallService();
1311 if (opt_remove_service
) {
1312 WIN32_RemoveService();
1316 if (opt_command_line
) {
1317 WIN32_SetServiceCommandLine();
1323 /* parse configuration file
1324 * note: in "normal" case this used to be called from mainInitialize() */
1329 ConfigFile
= xstrdup(DefaultConfigFile
);
1331 assert(!configured_once
);
1335 storeFsInit(); /* required for config parsing */
1337 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1340 /* May not be needed for parsing, have not audited for such */
1341 DiskIOModule::SetupAllModules();
1343 /* Shouldn't be needed for config parsing, but have not audited for such */
1344 StoreFileSystem::SetupAllFs();
1346 /* we may want the parsing process to set this up in the future */
1347 Store::Root(new StoreController
);
1349 InitAuthSchemes(); /* required for config parsing */
1351 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1353 parse_err
= parseConfigFile(ConfigFile
);
1357 if (opt_parse_cfg_only
|| parse_err
> 0)
1360 setUmask(Config
.umask
);
1361 if (-1 == opt_send_signal
)
1362 if (checkRunningPid())
1379 /* send signal to running copy and exit */
1380 if (opt_send_signal
!= -1) {
1381 /* chroot if configured to run inside chroot */
1383 if (Config
.chroot_dir
) {
1384 if (chroot(Config
.chroot_dir
))
1385 fatal("failed to chroot");
1396 if (opt_create_swap_dirs
) {
1397 /* chroot if configured to run inside chroot */
1399 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1400 fatal("failed to chroot");
1404 debugs(0, 0, "Creating Swap Directories");
1405 Store::Root().create();
1410 if (!opt_no_daemon
&& Config
.workers
> 0)
1415 /* init comm module */
1420 if (opt_no_daemon
) {
1421 /* we have to init fdstat here. */
1422 fd_open(0, FD_LOG
, "stdin");
1423 fd_open(1, FD_LOG
, "stdout");
1424 fd_open(2, FD_LOG
, "stderr");
1427 #if USE_WIN32_SERVICE
1429 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1435 #if USE_WIN32_SERVICE
1437 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1444 SignalEngine
signalEngine(mainLoop
);
1446 mainLoop
.registerEngine(&signalEngine
);
1448 /* TODO: stop requiring the singleton here */
1449 mainLoop
.registerEngine(EventScheduler::GetInstance());
1451 StoreRootEngine store_engine
;
1453 mainLoop
.registerEngine(&store_engine
);
1455 CommSelectEngine comm_engine
;
1457 mainLoop
.registerEngine(&comm_engine
);
1459 mainLoop
.setPrimaryEngine(&comm_engine
);
1461 /* use the standard time service */
1462 TimeEngine time_engine
;
1464 mainLoop
.setTimeService(&time_engine
);
1466 if (IamCoordinatorProcess())
1467 AsyncJob::Start(Ipc::Coordinator::Instance());
1468 else if (UsingSmp() && IamWorkerProcess())
1469 AsyncJob::Start(new Ipc::Strand
);
1471 /* at this point we are finished the synchronous startup. */
1476 if (mainLoop
.errcount
== 10)
1477 fatal_dump("Event loop exited with failure.");
1479 /* shutdown squid now */
1492 if (strcmp(Config
.pidFilename
, "none") == 0) {
1493 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1496 pid
= readPidFile();
1499 #if USE_WIN32_SERVICE
1501 if (opt_signal_service
) {
1502 WIN32_sendSignal(opt_send_signal
);
1505 #ifdef _SQUID_MSWIN_
1507 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1508 fprintf(stderr
, "signal to Squid Service:\n");
1509 fprintf(stderr
, "missing -n command line switch.\n");
1518 if (kill(pid
, opt_send_signal
) &&
1519 /* ignore permissions if just running check */
1520 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1521 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1522 fprintf(stderr
, "signal %d to process %d: %s\n",
1523 opt_send_signal
, (int) pid
, xstrerror());
1527 if (opt_send_signal
!= SIGTERM
) {
1528 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1531 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1536 /* signal successfully sent */
1540 #ifndef _SQUID_MSWIN_
1542 * This function is run when Squid is in daemon mode, just
1543 * before the parent forks and starts up the child process.
1544 * It can be used for admin-specific tasks, such as notifying
1545 * someone that Squid is (re)started.
1548 mainStartScript(const char *prog
)
1550 char script
[MAXPATHLEN
];
1555 xstrncpy(script
, prog
, MAXPATHLEN
);
1557 if ((t
= strrchr(script
, '/'))) {
1559 sl
= strlen(script
);
1562 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1564 if ((cpid
= fork()) == 0) {
1566 execl(script
, squid_start_script
, (char *)NULL
);
1572 rpid
= wait4(cpid
, &status
, 0, NULL
);
1576 rpid
= waitpid(cpid
, &status
, 0);
1579 } while (rpid
!= cpid
);
1583 #endif /* _SQUID_MSWIN_ */
1586 checkRunningPid(void)
1588 // master process must start alone, but its kids processes may co-exist
1589 if (!IamMasterProcess())
1597 pid
= readPidFile();
1602 if (kill(pid
, 0) < 0)
1605 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1611 watch_child(char *argv
[])
1613 #ifndef _SQUID_MSWIN_
1631 if (!IamMasterProcess())
1634 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1636 if ((pid
= fork()) < 0)
1637 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1642 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1648 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1649 ioctl(i
, TIOCNOTTY
, NULL
);
1656 * RBCOLLINS - if cygwin stackdumps when squid is run without
1657 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1658 * 1.1.3. execvp had a bit overflow error in a loop..
1660 /* Connect stdio to /dev/null in daemon mode */
1661 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1664 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1668 if (Debug::log_stderr
< 0) {
1673 if (Config
.workers
> 128) {
1674 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1676 // but we keep going in hope that user knows best
1678 TheKids
.init(Config
.workers
);
1680 // keep [re]starting kids until it is time to quit
1682 mainStartScript(argv
[0]);
1684 // start each kid that needs to be [re]started; once
1685 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1686 Kid
& kid
= TheKids
.get(i
);
1687 if (kid
.hopeless() || kid
.exitedHappy() || kid
.running())
1690 if ((pid
= fork()) == 0) {
1692 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1694 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1696 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1700 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1704 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1706 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1710 pid
= wait3(&status
, 0, NULL
);
1714 pid
= waitpid(-1, &status
, 0);
1717 // Loop to collect all stopped kids before we go to sleep below.
1719 Kid
* kid
= TheKids
.find(pid
);
1722 if (kid
->calledExit()) {
1724 "Squid Parent: child process %d exited with status %d",
1725 kid
->getPid(), kid
->exitStatus());
1726 } else if (kid
->signaled()) {
1728 "Squid Parent: child process %d exited due to signal %d with status %d",
1729 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1731 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", kid
->getPid());
1734 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1737 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1740 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1743 if (TheKids
.allExitedHappy()) {
1747 if (TheKids
.allHopeless()) {
1748 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1752 if (TheKids
.allSignaled(SIGKILL
)) {
1756 if (TheKids
.allSignaled(SIGINT
) || TheKids
.allSignaled(SIGTERM
)) {
1757 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1761 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1766 #endif /* _SQUID_MSWIN_ */
1773 /* XXX: This function is called after the main loop has quit, which
1774 * means that no AsyncCalls would be called, including close handlers.
1775 * TODO: We need to close/shut/free everything that needs calls before
1779 #if USE_WIN32_SERVICE
1780 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1783 debugs(1, 1, "Shutting down...");
1793 externalAclShutdown();
1794 icpConnectionClose();
1801 snmpConnectionClose();
1805 wccpConnectionClose();
1809 wccp2ConnectionClose();
1812 releaseServerSockets();
1813 commCloseAllSockets();
1821 DelayPools::FreePools();
1824 authenticateReset();
1825 #if USE_WIN32_SERVICE
1827 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1830 Store::Root().sync(); /* Flush pending object writes/unlinks */
1833 unlinkdClose(); /* after sync/flush */
1836 storeDirWriteCleanLogs(0);
1839 Store::Root().sync(); /* Flush log writes */
1842 useragentLogClose();
1849 Store::Root().sync(); /* Flush log close */
1850 StoreFileSystem::FreeAllFs();
1851 DiskIOModule::FreeAllModules();
1852 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1856 /*stmemFreeMemory(); */
1858 ipcacheFreeMemory();
1859 fqdncacheFreeMemory();
1861 clientdbFreeMemory();
1862 httpHeaderCleanModule();
1870 if (opt_no_daemon
) {
1885 xmalloc_find_leaks();
1887 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1896 if (IamPrimaryProcess()) {
1897 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1899 safeunlink(Config
.pidFilename
, 0);
1904 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1908 * We used to fclose(debug_log) here if it was set, but then
1909 * we forgot to set it to NULL. That caused some coredumps
1910 * because exit() ends up calling a bunch of destructors and
1911 * such. So rather than forcing the debug_log to close, we'll
1912 * leave it open so that those destructors can write some
1913 * debugging if necessary. The file will be closed anyway when
1914 * the process truly exits.
1917 exit(shutdown_status
);