4 * DEBUG: section 1 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 "ConfigParser.h"
42 #include "errorpage.h"
44 #include "EventLoop.h"
45 #include "ExternalACL.h"
48 #include "ident/Ident.h"
49 #include "HttpReply.h"
55 #include "StoreFileSystem.h"
56 #include "DiskIO/DiskIOModule.h"
59 #include "ipc/Coordinator.h"
60 #include "ipc/Strand.h"
62 #include "comm_epoll.h"
65 #include "comm_kqueue.h"
68 #include "comm_poll.h"
70 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
71 #include "comm_select.h"
73 #include "SquidTime.h"
77 #include "icmp/IcmpSquid.h"
78 #include "icmp/net_db.h"
79 #include "TextException.h"
81 #if USE_LOADABLE_MODULES
82 #include "LoadableModules.h"
86 #include "adaptation/icap/Config.h"
89 #include "adaptation/ecap/Config.h"
92 #include "adaptation/Config.h"
96 #include "esi/Module.h"
99 #include "fs/Module.h"
101 #if USE_WIN32_SERVICE
103 #include "squid_windows.h"
106 static int opt_install_service
= FALSE
;
107 static int opt_remove_service
= FALSE
;
108 static int opt_signal_service
= FALSE
;
109 static int opt_command_line
= FALSE
;
110 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
111 void WINAPI
WIN32_svcHandler(DWORD
);
115 /** for error reporting from xmalloc and friends */
116 SQUIDCEXTERN
void (*failure_notify
) (const char *);
118 static int opt_parse_cfg_only
= 0;
119 static char *opt_syslog_facility
= NULL
;
120 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
121 static int configured_once
= 0;
123 static int malloc_debug_level
= 0;
125 static volatile int do_reconfigure
= 0;
126 static volatile int do_rotate
= 0;
127 static volatile int do_shutdown
= 0;
128 static volatile int shutdown_status
= 0;
130 static int RotateSignal
= -1;
131 static int ReconfigureSignal
= -1;
132 static int ShutdownSignal
= -1;
134 static void mainRotate(void);
135 static void mainReconfigureStart(void);
136 static void mainReconfigureFinish(void*);
137 static void mainInitialize(void);
138 static void usage(void);
139 static void mainParseOptions(int argc
, char *argv
[]);
140 static void sendSignal(void);
141 static void serverConnectionsOpen(void);
142 static void serverConnectionsClose(void);
143 static void watch_child(char **);
144 static void setEffectiveUser(void);
146 extern void log_trace_done();
147 extern void log_trace_init(char *);
149 static void SquidShutdown(void);
150 static void mainSetCwd(void);
151 static int checkRunningPid(void);
153 #ifndef _SQUID_MSWIN_
154 static const char *squid_start_script
= "squid_start";
158 #include "test_access.c"
161 /** temporary thunk across to the unrefactored store interface */
163 class StoreRootEngine
: public AsyncEngine
167 int checkEvents(int timeout
) {
168 Store::Root().callback();
173 class SignalEngine
: public AsyncEngine
177 SignalEngine(EventLoop
&evtLoop
) : loop(evtLoop
) {}
178 virtual int checkEvents(int timeout
);
181 static void StopEventLoop(void * data
) {
182 static_cast<SignalEngine
*>(data
)->loop
.stop();
185 void doShutdown(time_t wait
);
191 SignalEngine::checkEvents(int timeout
)
193 PROF_start(SignalEngine_checkEvents
);
195 if (do_reconfigure
) {
196 mainReconfigureStart();
198 } else if (do_rotate
) {
201 } else if (do_shutdown
) {
202 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
205 BroadcastSignalIfAny(DebugSignal
);
206 BroadcastSignalIfAny(RotateSignal
);
207 BroadcastSignalIfAny(ReconfigureSignal
);
208 BroadcastSignalIfAny(ShutdownSignal
);
210 PROF_stop(SignalEngine_checkEvents
);
215 SignalEngine::doShutdown(time_t wait
)
217 debugs(1, 1, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
218 debugs(1, 1, "Waiting " << wait
<< " seconds for active connections to finish");
222 #if USE_WIN32_SERVICE
223 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
226 serverConnectionsClose();
227 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
234 #if USE_WIN32_SERVICE
235 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
237 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
239 " -a port Specify HTTP port number (default: %d).\n"
240 " -d level Write debugging to stderr also.\n"
241 " -f file Use given config-file instead of\n"
243 " -h Print help message.\n"
244 #if USE_WIN32_SERVICE
245 " -i Installs as a Windows Service (see -n option).\n"
247 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
248 " Parse configuration file, then send signal to \n"
249 " running copy (except -k parse) and exit.\n"
250 #if USE_WIN32_SERVICE
251 " -n name Specify Windows Service name to use for service operations\n"
252 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
253 " -r Removes a Windows Service (see -n option).\n"
255 " -s | -l facility\n"
256 " Enable logging to syslog.\n"
257 " -u port Specify ICP port number (default: %d), disable with 0.\n"
258 " -v Print version.\n"
259 " -z Create swap directories\n"
260 " -C Do not catch fatal signals.\n"
261 " -D OBSOLETE. Scheduled for removal.\n"
262 " -F Don't serve any requests until store is rebuilt.\n"
263 " -N No daemon mode.\n"
264 #if USE_WIN32_SERVICE
266 " Set Windows Service Command line options in Registry.\n"
268 " -R Do not set REUSEADDR on port.\n"
269 " -S Double-check swap during rebuild.\n"
270 " -X Force full debugging.\n"
271 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
272 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
277 * Parse the parameters received via command line interface.
279 \param argc Number of options received on command line
280 \param argv List of parameters received on command line
283 mainParseOptions(int argc
, char *argv
[])
288 #if USE_WIN32_SERVICE
289 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
291 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
299 * Unset/disabel global option for catchign signals. opt_catch_signals */
300 opt_catch_signals
= 0;
305 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
306 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
311 * Set global option for foreground rebuild. opt_foreground_rebuild */
312 opt_foreground_rebuild
= 1;
317 * Set global option for 'no_daemon' mode. opt_no_daemon */
321 #if USE_WIN32_SERVICE
325 * Set global option. opt_command_lin and WIN32_Command_Line */
326 opt_command_line
= 1;
327 WIN32_Command_Line
= xstrdup(optarg
);
333 * Unset/disable global option opt_reuseaddr */
339 * Set global option opt_store_doublecheck */
340 opt_store_doublecheck
= 1;
345 * Force full debugging */
346 Debug::parseOptions("rotate=0 ALL,9");
347 Debug::override_X
= 1;
348 sigusr2_handle(SIGUSR2
);
353 * Set global option opt_reload_hit_only */
354 opt_reload_hit_only
= 1;
357 #if USE_WIN32_SERVICE
361 * Set global option opt_install_service (to TRUE) */
362 opt_install_service
= TRUE
;
368 * Add optional HTTP port as given following the option */
369 add_http_port(optarg
);
374 * Set global option Debug::log_stderr to the number given follwoign the option */
375 Debug::log_stderr
= atoi(optarg
);
380 * Load the file given instead of the default squid.conf. */
382 ConfigFile
= xstrdup(optarg
);
387 * Run the administrative action given following the option */
389 /** \li When its an unknown option display the usage help. */
390 if ((int) strlen(optarg
) < 1)
393 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
394 /** \li On reconfigure send SIGHUP. */
395 opt_send_signal
= SIGHUP
;
396 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
397 /** \li On rotate send SIGQUIT or SIGUSR1. */
398 #ifdef _SQUID_LINUX_THREADS_
400 opt_send_signal
= SIGQUIT
;
404 opt_send_signal
= SIGUSR1
;
408 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
409 /** \li On debug send SIGTRAP or SIGUSR2. */
410 #ifdef _SQUID_LINUX_THREADS_
412 opt_send_signal
= SIGTRAP
;
416 opt_send_signal
= SIGUSR2
;
420 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
421 /** \li On shutdown send SIGTERM. */
422 opt_send_signal
= SIGTERM
;
423 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
424 /** \li On interrupt send SIGINT. */
425 opt_send_signal
= SIGINT
;
426 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
427 /** \li On kill send SIGKILL. */
428 opt_send_signal
= SIGKILL
;
432 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
433 /** \li On restart send SIGTTIN. (exit and restart by parent) */
434 opt_send_signal
= SIGTTIN
;
438 else if (!strncmp(optarg
, "check", strlen(optarg
)))
439 /** \li On check send 0 / SIGNULL. */
440 opt_send_signal
= 0; /* SIGNULL */
441 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
442 /** \li On parse set global flag to re-parse the config file only. */
443 opt_parse_cfg_only
= 1;
451 * Set global malloc_debug_level to the value given following the option.
452 * if none is given it toggles the xmalloc_trace option on/off */
455 malloc_debug_level
= atoi(optarg
);
457 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
462 xmalloc_trace
= !xmalloc_trace
;
464 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
469 #if USE_WIN32_SERVICE
473 * Set global option opt_signal_service (to TRUE).
474 * Stores the additional parameter given in global WIN32_Service_name */
475 xfree(WIN32_Service_name
);
477 WIN32_Service_name
= xstrdup(optarg
);
479 opt_signal_service
= TRUE
;
485 * Set global option opt_remove_service (to TRUE) */
486 opt_remove_service
= TRUE
;
494 * Stores the syslog facility name in global opt_syslog_facility
495 * then performs actions for -s option. */
496 opt_syslog_facility
= xstrdup(optarg
);
500 * Initialize the syslog for output */
503 _db_set_syslog(opt_syslog_facility
);
509 fatal("Logging to syslog not available on this platform");
516 * Store the ICP port number given in global option icpPortNumOverride
517 * ensuring its a positive number. */
518 icpPortNumOverride
= atoi(optarg
);
520 if (icpPortNumOverride
< 0)
521 icpPortNumOverride
= 0;
527 * Display squid version and build information. Then exit. */
528 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string
, SQUID_CONFIGURE_OPTIONS
);
530 #if USE_WIN32_SERVICE
532 printf("Compiled as Windows System Service.\n");
542 * Set global option Debug::log_stderr and opt_create_swap_dirs */
543 Debug::log_stderr
= 1;
544 opt_create_swap_dirs
= 1;
552 /** \par h,?, or unknown
553 * \copydoc usage() */
568 #ifndef _SQUID_MSWIN_
571 signal(sig
, rotate_logs
);
581 ReconfigureSignal
= sig
;
582 #ifndef _SQUID_MSWIN_
585 signal(sig
, reconfigure
);
593 do_shutdown
= sig
== SIGINT
? -1 : 1;
594 ShutdownSignal
= sig
;
601 #ifndef _SQUID_MSWIN_
602 #ifdef KILL_PARENT_OPT
605 debugs(1, 1, "Killing master process, pid " << getppid());
607 if (kill(getppid(), sig
) < 0)
608 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
612 #if SA_RESETHAND == 0
613 signal(SIGTERM
, SIG_DFL
);
615 signal(SIGINT
, SIG_DFL
);
622 serverConnectionsOpen(void)
624 if (IamPrimaryProcess()) {
627 wccpConnectionOpen();
632 wccp2ConnectionOpen();
635 // Coordinator does not start proxying services
636 if (!IamCoordinatorProcess()) {
637 clientOpenListenSockets();
638 icpConnectionsOpen();
645 snmpConnectionOpen();
657 peerSourceHashInit();
662 serverConnectionsClose(void)
664 assert(shutting_down
|| reconfiguring
);
666 if (IamPrimaryProcess()) {
669 wccpConnectionClose();
673 wccp2ConnectionClose();
676 if (!IamCoordinatorProcess()) {
677 clientHttpConnectionsClose();
678 icpConnectionShutdown();
681 htcpSocketShutdown();
687 snmpConnectionShutdown();
695 mainReconfigureStart(void)
697 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
700 // Initiate asynchronous closing sequence
701 serverConnectionsClose();
702 icpConnectionClose();
709 snmpConnectionClose();
720 authenticateShutdown();
721 externalAclShutdown();
722 storeDirCloseSwapLogs();
731 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
736 mainReconfigureFinish(void *)
738 debugs(1, 3, "finishing reconfiguring");
741 enter_suid(); /* root to read config file */
743 // we may have disabled the need for PURGE
744 if (Config2
.onoff
.enable_purge
)
745 Config2
.onoff
.enable_purge
= 2;
747 // parse the config returns a count of errors encountered.
748 const int oldWorkers
= Config
.workers
;
749 if ( parseConfigFile(ConfigFile
) != 0) {
750 // for now any errors are a fatal condition...
753 if (oldWorkers
!= Config
.workers
) {
754 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
755 oldWorkers
<< " to " << Config
.workers
<<
756 ") is not supported and ignored");
757 Config
.workers
= oldWorkers
;
760 setUmask(Config
.umask
);
763 _db_init(Debug::cache_log
, Debug::debugOptions
);
764 ipcache_restart(); /* clear stuck entries */
765 authenticateUserCacheRestart(); /* clear stuck ACL entries */
766 fqdncache_restart(); /* sigh, fqdncache too */
768 errorInitialize(); /* reload error pages */
785 authenticateInit(&Config
.authConfiguration
);
788 if (IamPrimaryProcess()) {
799 serverConnectionsOpen();
803 storeDirOpenSwapLogs();
805 mimeInit(Config
.mimeTablePathname
);
807 if (Config
.onoff
.announce
) {
808 if (!eventFind(start_announce
, NULL
))
809 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
811 if (eventFind(start_announce
, NULL
))
812 eventDelete(start_announce
, NULL
);
815 writePidFile(); /* write PID file */
817 debugs(1, 1, "Ready to serve requests.");
830 authenticateShutdown();
831 externalAclShutdown();
833 _db_rotate_log(); /* cache.log */
834 storeDirWriteCleanLogs(1);
835 storeLogRotate(); /* store.log */
836 accessLogRotate(); /* access.log */
837 useragentRotateLog(); /* useragent.log */
838 refererRotateLog(); /* referer.log */
840 icapLogRotate(); /*icap.log*/
851 authenticateInit(&Config
.authConfiguration
);
856 setEffectiveUser(void)
859 leave_suid(); /* Run as non privilegied user */
865 if (geteuid() == 0) {
866 debugs(0, 0, "Squid is not safe to run as root! If you must");
867 debugs(0, 0, "start Squid as root, then you must configure");
868 debugs(0, 0, "it to run as a non-priveledged user with the");
869 debugs(0, 0, "'cache_effective_user' option in the config file.");
870 fatal("Don't run Squid as root, set 'cache_effective_user'!");
877 char pathbuf
[MAXPATHLEN
];
879 if (Config
.coredump_dir
) {
880 if (0 == strcmp("none", Config
.coredump_dir
)) {
882 } else if (chdir(Config
.coredump_dir
) == 0) {
883 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
886 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
890 /* If we don't have coredump_dir or couldn't cd there, report current dir */
891 if (getcwd(pathbuf
, MAXPATHLEN
)) {
892 debugs(0, 1, "Current Directory is " << pathbuf
);
894 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
899 #include "DelayPools.h"
905 /* chroot if configured to run inside chroot */
907 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
908 fatal("failed to chroot");
911 if (opt_catch_signals
) {
912 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
913 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
916 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
917 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
921 if (icpPortNumOverride
!= 1)
922 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
924 _db_init(Debug::cache_log
, Debug::debugOptions
);
926 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
930 log_trace_init("/tmp/squid.alloc");
934 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
938 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
939 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
940 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
942 debugs(1, 0, "Running on " << WIN32_OS_string
);
946 debugs(1, 1, "Process ID " << getpid());
948 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
952 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
954 if (WIN32_Socks_initialized
)
955 debugs(1, 1, "Windows sockets initialized");
957 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
958 WIN32_IpAddrChangeMonitorInit();
963 if (!configured_once
)
964 disk_init(); /* disk_init must go before ipcache_init() */
984 authenticateInit(&Config
.authConfiguration
);
992 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
994 httpReplyInitModule(); /* must go before accepting replies */
1015 malloc_debug(0, malloc_debug_level
);
1019 if (!configured_once
) {
1028 /* after this point we want to see the mallinfo() output */
1030 mimeInit(Config
.mimeTablePathname
);
1037 FwdState::initModule();
1038 /* register the modules in the cache manager menus */
1040 cbdataRegisterWithCacheManager();
1041 /* These use separate calls so that the comm loops can eventually
1047 // TODO: pconn is a good candidate for new-style registration
1048 // PconnModule::GetInstance()->registerWithCacheManager();
1049 // moved to PconnModule::PconnModule()
1052 if (IamPrimaryProcess()) {
1064 serverConnectionsOpen();
1068 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1070 if (Config
.chroot_dir
)
1073 if (!configured_once
)
1074 writePidFile(); /* write PID file */
1076 #ifdef _SQUID_LINUX_THREADS_
1078 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1080 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1084 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1086 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1090 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1092 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1094 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1098 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1104 #if USE_LOADABLE_MODULES
1105 LoadableModulesConfigure(Config
.loadable_module_names
);
1109 bool enableAdaptation
= false;
1111 // We can remove this dependency on specific adaptation mechanisms
1112 // if we create a generic Registry of such mechanisms. Should we?
1114 Adaptation::Icap::TheConfig
.finalize();
1115 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1118 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1119 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1121 // must be the last adaptation-related finalize
1122 Adaptation::Config::Finalize(enableAdaptation
);
1129 debugs(1, 1, "Ready to serve requests.");
1131 if (!configured_once
) {
1132 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1134 if (Config
.onoff
.announce
)
1135 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1137 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1139 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1143 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1147 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1150 configured_once
= 1;
1153 /// unsafe main routine -- may throw
1154 int SquidMain(int argc
, char **argv
);
1155 /// unsafe main routine wrapper to catch exceptions
1156 static int SquidMainSafe(int argc
, char **argv
);
1158 #if USE_WIN32_SERVICE
1159 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1160 extern "C" void WINAPI
1161 SquidWinSvcMain(int argc
, char **argv
)
1163 SquidMainSafe(argc
, argv
);
1167 main(int argc
, char **argv
)
1169 return SquidMainSafe(argc
, argv
);
1174 SquidMainSafe(int argc
, char **argv
)
1177 return SquidMain(argc
, argv
);
1178 } catch (const std::exception
&e
) {
1179 std::cerr
<< "dying from an unhandled exception: " << e
.what() << std::endl
;
1182 std::cerr
<< "dying from an unhandled exception." << std::endl
;
1185 return -1; // not reached
1188 /// computes name and ID for the current kid process
1190 ConfigureCurrentKid(const char *processName
)
1192 // kids are marked with parenthesis around their process names
1193 if (processName
&& processName
[0] == '(') {
1194 if (const char *idStart
= strrchr(processName
, '-')) {
1195 KidIdentifier
= atoi(idStart
+ 1);
1196 const int nameLen
= idStart
- (processName
+ 1);
1197 xstrncpy(KidName
, processName
+ 1, nameLen
+ 1);
1200 xstrncpy(KidName
, APP_SHORTNAME
, sizeof(KidName
));
1206 SquidMain(int argc
, char **argv
)
1208 ConfigureCurrentKid(argv
[0]);
1210 #ifdef _SQUID_WIN32_
1217 sbrk_start
= sbrk(0);
1220 Debug::parseOptions(NULL
);
1223 #if defined(SQUID_MAXFD_LIMIT)
1225 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1226 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1230 #ifdef _SQUID_WIN32_
1232 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1233 return WIN32_init_err
;
1237 /* call mallopt() before anything else */
1240 /* Round up all sizes to a multiple of this */
1241 mallopt(M_GRAIN
, 16);
1245 /* biggest size that is considered a small block */
1246 mallopt(M_MXFAST
, 256);
1250 /* allocate this many small blocks at once */
1251 mallopt(M_NLBLKS
, 32);
1254 #endif /* HAVE_MALLOPT */
1256 squid_srandom(time(NULL
));
1260 squid_start
= current_time
;
1262 failure_notify
= fatal_dump
;
1264 #if USE_WIN32_SERVICE
1266 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1270 mainParseOptions(argc
, argv
);
1272 if (opt_parse_cfg_only
) {
1273 Debug::parseOptions("ALL,1");
1276 #if USE_WIN32_SERVICE
1278 if (opt_install_service
) {
1279 WIN32_InstallService();
1283 if (opt_remove_service
) {
1284 WIN32_RemoveService();
1288 if (opt_command_line
) {
1289 WIN32_SetServiceCommandLine();
1295 /* parse configuration file
1296 * note: in "normal" case this used to be called from mainInitialize() */
1301 ConfigFile
= xstrdup(DefaultConfigFile
);
1303 assert(!configured_once
);
1307 storeFsInit(); /* required for config parsing */
1309 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1312 /* May not be needed for parsing, have not audited for such */
1313 DiskIOModule::SetupAllModules();
1315 /* Shouldn't be needed for config parsing, but have not audited for such */
1316 StoreFileSystem::SetupAllFs();
1318 /* we may want the parsing process to set this up in the future */
1319 Store::Root(new StoreController
);
1321 parse_err
= parseConfigFile(ConfigFile
);
1325 if (opt_parse_cfg_only
|| parse_err
> 0)
1328 setUmask(Config
.umask
);
1329 if (-1 == opt_send_signal
)
1330 if (checkRunningPid())
1347 /* send signal to running copy and exit */
1348 if (opt_send_signal
!= -1) {
1349 /* chroot if configured to run inside chroot */
1351 if (Config
.chroot_dir
) {
1352 if (chroot(Config
.chroot_dir
))
1353 fatal("failed to chroot");
1364 if (opt_create_swap_dirs
) {
1365 /* chroot if configured to run inside chroot */
1367 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1368 fatal("failed to chroot");
1372 debugs(0, 0, "Creating Swap Directories");
1373 Store::Root().create();
1378 if (!opt_no_daemon
&& Config
.workers
> 0)
1383 /* init comm module */
1388 if (opt_no_daemon
) {
1389 /* we have to init fdstat here. */
1390 fd_open(0, FD_LOG
, "stdin");
1391 fd_open(1, FD_LOG
, "stdout");
1392 fd_open(2, FD_LOG
, "stderr");
1395 #if USE_WIN32_SERVICE
1397 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1403 #if USE_WIN32_SERVICE
1405 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1412 SignalEngine
signalEngine(mainLoop
);
1414 mainLoop
.registerEngine(&signalEngine
);
1416 /* TODO: stop requiring the singleton here */
1417 mainLoop
.registerEngine(EventScheduler::GetInstance());
1419 StoreRootEngine store_engine
;
1421 mainLoop
.registerEngine(&store_engine
);
1423 CommSelectEngine comm_engine
;
1425 mainLoop
.registerEngine(&comm_engine
);
1427 mainLoop
.setPrimaryEngine(&comm_engine
);
1429 /* use the standard time service */
1430 TimeEngine time_engine
;
1432 mainLoop
.setTimeService(&time_engine
);
1434 if (IamCoordinatorProcess())
1435 AsyncJob::AsyncStart(Ipc::Coordinator::Instance());
1436 else if (UsingSmp() && IamWorkerProcess())
1437 AsyncJob::AsyncStart(new Ipc::Strand
);
1439 /* at this point we are finished the synchronous startup. */
1444 if (mainLoop
.errcount
== 10)
1445 fatal_dump("Event loop exited with failure.");
1447 /* shutdown squid now */
1460 if (strcmp(Config
.pidFilename
, "none") == 0) {
1461 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1464 pid
= readPidFile();
1467 #if USE_WIN32_SERVICE
1469 if (opt_signal_service
) {
1470 WIN32_sendSignal(opt_send_signal
);
1473 #ifdef _SQUID_MSWIN_
1475 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1476 fprintf(stderr
, "signal to Squid Service:\n");
1477 fprintf(stderr
, "missing -n command line switch.\n");
1486 if (kill(pid
, opt_send_signal
) &&
1487 /* ignore permissions if just running check */
1488 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1489 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1490 fprintf(stderr
, "signal %d to process %d: %s\n",
1491 opt_send_signal
, (int) pid
, xstrerror());
1495 if (opt_send_signal
!= SIGTERM
) {
1496 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1499 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1504 /* signal successfully sent */
1508 #ifndef _SQUID_MSWIN_
1510 * This function is run when Squid is in daemon mode, just
1511 * before the parent forks and starts up the child process.
1512 * It can be used for admin-specific tasks, such as notifying
1513 * someone that Squid is (re)started.
1516 mainStartScript(const char *prog
)
1518 char script
[SQUID_MAXPATHLEN
];
1523 xstrncpy(script
, prog
, MAXPATHLEN
);
1525 if ((t
= strrchr(script
, '/'))) {
1527 sl
= strlen(script
);
1530 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1532 if ((cpid
= fork()) == 0) {
1534 execl(script
, squid_start_script
, (char *)NULL
);
1540 rpid
= wait4(cpid
, &status
, 0, NULL
);
1544 rpid
= waitpid(cpid
, &status
, 0);
1547 } while (rpid
!= cpid
);
1551 #endif /* _SQUID_MSWIN_ */
1554 checkRunningPid(void)
1556 // master process must start alone, but its kids processes may co-exist
1557 if (!IamMasterProcess())
1565 pid
= readPidFile();
1570 if (kill(pid
, 0) < 0)
1573 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1579 watch_child(char *argv
[])
1581 #ifndef _SQUID_MSWIN_
1599 if (!IamMasterProcess())
1602 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1604 if ((pid
= fork()) < 0)
1605 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1610 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1616 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1617 ioctl(i
, TIOCNOTTY
, NULL
);
1624 * RBCOLLINS - if cygwin stackdumps when squid is run without
1625 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1626 * 1.1.3. execvp had a bit overflow error in a loop..
1628 /* Connect stdio to /dev/null in daemon mode */
1629 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1632 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1636 if (Debug::log_stderr
< 0) {
1641 if (Config
.workers
> 128) {
1642 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1644 // but we keep going in hope that user knows best
1646 TheKids
.init(Config
.workers
);
1648 // keep [re]starting kids until it is time to quit
1650 mainStartScript(argv
[0]);
1652 // start each kid that needs to be [re]started; once
1653 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1654 Kid
& kid
= TheKids
.get(i
);
1655 if (kid
.hopeless() || kid
.exitedHappy() || kid
.running())
1658 if ((pid
= fork()) == 0) {
1660 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1662 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1664 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1668 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1672 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1674 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1678 pid
= wait3(&status
, 0, NULL
);
1682 pid
= waitpid(-1, &status
, 0);
1685 // Loop to collect all stopped kids before we go to sleep below.
1687 Kid
* kid
= TheKids
.find(pid
);
1690 if (kid
->calledExit()) {
1692 "Squid Parent: child process %d exited with status %d",
1693 kid
->getPid(), kid
->exitStatus());
1694 } else if (kid
->signaled()) {
1696 "Squid Parent: child process %d exited due to signal %d with status %d",
1697 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1699 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", kid
->getPid());
1702 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1705 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1708 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1711 if (TheKids
.allExitedHappy()) {
1715 if (TheKids
.allHopeless()) {
1716 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1720 if (TheKids
.allSignaled(SIGKILL
)) {
1724 if (TheKids
.allSignaled(SIGINT
) || TheKids
.allSignaled(SIGTERM
)) {
1725 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1729 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1734 #endif /* _SQUID_MSWIN_ */
1741 /* XXX: This function is called after the main loop has quit, which
1742 * means that no AsyncCalls would be called, including close handlers.
1743 * TODO: We need to close/shut/free everything that needs calls before
1747 #if USE_WIN32_SERVICE
1748 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1751 debugs(1, 1, "Shutting down...");
1761 externalAclShutdown();
1762 icpConnectionClose();
1769 snmpConnectionClose();
1773 wccpConnectionClose();
1777 wccp2ConnectionClose();
1780 releaseServerSockets();
1781 commCloseAllSockets();
1789 DelayPools::FreePools();
1792 authenticateShutdown();
1793 #if USE_WIN32_SERVICE
1795 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1798 Store::Root().sync(); /* Flush pending object writes/unlinks */
1801 unlinkdClose(); /* after sync/flush */
1804 storeDirWriteCleanLogs(0);
1807 Store::Root().sync(); /* Flush log writes */
1810 useragentLogClose();
1817 Store::Root().sync(); /* Flush log close */
1818 StoreFileSystem::FreeAllFs();
1819 DiskIOModule::FreeAllModules();
1820 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1824 /*stmemFreeMemory(); */
1826 ipcacheFreeMemory();
1827 fqdncacheFreeMemory();
1829 clientdbFreeMemory();
1830 httpHeaderCleanModule();
1838 if (opt_no_daemon
) {
1853 xmalloc_find_leaks();
1855 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1864 if (IamPrimaryProcess()) {
1865 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1867 safeunlink(Config
.pidFilename
, 0);
1872 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1876 * We used to fclose(debug_log) here if it was set, but then
1877 * we forgot to set it to NULL. That caused some coredumps
1878 * because exit() ends up calling a bunch of destructors and
1879 * such. So rather than forcing the debug_log to close, we'll
1880 * leave it open so that those destructors can write some
1881 * debugging if necessary. The file will be closed anyway when
1882 * the process truly exits.
1885 exit(shutdown_status
);