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"
37 #include "authenticate.h"
38 #include "ConfigParser.h"
39 #include "errorpage.h"
41 #include "EventLoop.h"
42 #include "ExternalACL.h"
46 #include "HttpReply.h"
52 #include "StoreFileSystem.h"
53 #include "DiskIO/DiskIOModule.h"
56 #include "comm_epoll.h"
59 #include "comm_kqueue.h"
62 #include "comm_poll.h"
64 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
65 #include "comm_select.h"
67 #include "SquidTime.h"
71 #include "icmp/IcmpSquid.h"
72 #include "icmp/net_db.h"
73 #include "TextException.h"
75 #if USE_LOADABLE_MODULES
76 #include "LoadableModules.h"
80 #include "ICAP/ICAPConfig.h"
83 #include "eCAP/Config.h"
86 #include "adaptation/Config.h"
91 #include "squid_windows.h"
94 static int opt_install_service
= FALSE
;
95 static int opt_remove_service
= FALSE
;
96 static int opt_signal_service
= FALSE
;
97 static int opt_command_line
= FALSE
;
98 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
99 void WINAPI
WIN32_svcHandler(DWORD
);
103 /** for error reporting from xmalloc and friends */
104 SQUIDCEXTERN
void (*failure_notify
) (const char *);
106 static int opt_parse_cfg_only
= 0;
107 static char *opt_syslog_facility
= NULL
;
108 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
109 static int configured_once
= 0;
111 static int malloc_debug_level
= 0;
113 static volatile int do_reconfigure
= 0;
114 static volatile int do_rotate
= 0;
115 static volatile int do_shutdown
= 0;
116 static volatile int shutdown_status
= 0;
118 static void mainRotate(void);
119 static void mainReconfigureStart(void);
120 static void mainReconfigureFinish(void*);
121 static void mainInitialize(void);
122 static void usage(void);
123 static void mainParseOptions(int argc
, char *argv
[]);
124 static void sendSignal(void);
125 static void serverConnectionsOpen(void);
126 static void serverConnectionsClose(void);
127 static void watch_child(char **);
128 static void setEffectiveUser(void);
130 extern void log_trace_done();
131 extern void log_trace_init(char *);
133 static void SquidShutdown(void);
134 static void mainSetCwd(void);
135 static int checkRunningPid(void);
137 #ifndef _SQUID_MSWIN_
138 static const char *squid_start_script
= "squid_start";
142 #include "test_access.c"
145 /** temporary thunk across to the unrefactored store interface */
147 class StoreRootEngine
: public AsyncEngine
151 int checkEvents(int timeout
) {
152 Store::Root().callback();
157 class SignalEngine
: public AsyncEngine
161 SignalEngine(EventLoop
&loop
) : loop(loop
) {}
162 virtual int checkEvents(int timeout
);
165 static void StopEventLoop(void * data
) {
166 static_cast<SignalEngine
*>(data
)->loop
.stop();
169 void doShutdown(time_t wait
);
175 SignalEngine::checkEvents(int timeout
)
177 PROF_start(SignalEngine_checkEvents
);
179 if (do_reconfigure
) {
180 mainReconfigureStart();
182 } else if (do_rotate
) {
185 } else if (do_shutdown
) {
186 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
190 PROF_stop(SignalEngine_checkEvents
);
195 SignalEngine::doShutdown(time_t wait
)
197 debugs(1, 1, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
198 debugs(1, 1, "Waiting " << wait
<< " seconds for active connections to finish");
202 #if USE_WIN32_SERVICE
203 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
206 serverConnectionsClose();
207 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
214 #if USE_WIN32_SERVICE
215 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
217 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
219 " -a port Specify HTTP port number (default: %d).\n"
220 " -d level Write debugging to stderr also.\n"
221 " -f file Use given config-file instead of\n"
223 " -h Print help message.\n"
224 #if USE_WIN32_SERVICE
225 " -i Installs as a Windows Service (see -n option).\n"
227 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
228 " Parse configuration file, then send signal to \n"
229 " running copy (except -k parse) and exit.\n"
230 #if USE_WIN32_SERVICE
231 " -n name Specify Windows Service name to use for service operations\n"
232 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
233 " -r Removes a Windows Service (see -n option).\n"
235 " -s | -l facility\n"
236 " Enable logging to syslog.\n"
237 " -u port Specify ICP port number (default: %d), disable with 0.\n"
238 " -v Print version.\n"
239 " -z Create swap directories\n"
240 " -C Do not catch fatal signals.\n"
241 " -D OBSOLETE. Scheduled for removal.\n"
242 " -F Don't serve any requests until store is rebuilt.\n"
243 " -N No daemon mode.\n"
244 #if USE_WIN32_SERVICE
246 " Set Windows Service Command line options in Registry.\n"
248 " -R Do not set REUSEADDR on port.\n"
249 " -S Double-check swap during rebuild.\n"
250 " -X Force full debugging.\n"
251 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
252 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
257 * Parse the parameters received via command line interface.
259 \param argc[in] Number of options received on command line
260 \param argv[in] List of parameters received on command line
263 mainParseOptions(int argc
, char *argv
[])
268 #if USE_WIN32_SERVICE
269 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
271 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
279 * Unset/disabel global option for catchign signals. opt_catch_signals */
280 opt_catch_signals
= 0;
285 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
286 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
291 * Set global option for foreground rebuild. opt_foreground_rebuild */
292 opt_foreground_rebuild
= 1;
297 * Set global option for 'no_daemon' mode. opt_no_daemon */
301 #if USE_WIN32_SERVICE
305 * Set global option. opt_command_lin and WIN32_Command_Line */
306 opt_command_line
= 1;
307 WIN32_Command_Line
= xstrdup(optarg
);
313 * Unset/disable global option opt_reuseaddr */
319 * Set global option opt_store_doublecheck */
320 opt_store_doublecheck
= 1;
325 * Force full debugging */
326 Debug::parseOptions("debug_options ALL,9");
327 Config
.onoff
.debug_override_X
= 1;
328 sigusr2_handle(SIGUSR2
);
333 * Set global option opt_reload_hit_only */
334 opt_reload_hit_only
= 1;
337 #if USE_WIN32_SERVICE
341 * Set global option opt_install_service (to TRUE) */
342 opt_install_service
= TRUE
;
348 * Add optional HTTP port as given following the option */
349 add_http_port(optarg
);
354 * Set global option opt_debug_stderr to the number given follwoign the option */
355 opt_debug_stderr
= atoi(optarg
);
360 * Load the file given instead of the default squid.conf. */
362 ConfigFile
= xstrdup(optarg
);
367 * Run the administrative action given following the option */
369 /** \li When its an unknown option display the usage help. */
370 if ((int) strlen(optarg
) < 1)
373 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
374 /** \li On reconfigure send SIGHUP. */
375 opt_send_signal
= SIGHUP
;
376 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
377 /** \li On rotate send SIGQUIT or SIGUSR1. */
378 #ifdef _SQUID_LINUX_THREADS_
380 opt_send_signal
= SIGQUIT
;
384 opt_send_signal
= SIGUSR1
;
388 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
389 /** \li On debug send SIGTRAP or SIGUSR2. */
390 #ifdef _SQUID_LINUX_THREADS_
392 opt_send_signal
= SIGTRAP
;
396 opt_send_signal
= SIGUSR2
;
400 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
401 /** \li On shutdown send SIGTERM. */
402 opt_send_signal
= SIGTERM
;
403 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
404 /** \li On interrupt send SIGINT. */
405 opt_send_signal
= SIGINT
;
406 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
407 /** \li On kill send SIGKILL. */
408 opt_send_signal
= SIGKILL
;
412 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
413 /** \li On restart send SIGTTIN. (exit and restart by parent) */
414 opt_send_signal
= SIGTTIN
;
418 else if (!strncmp(optarg
, "check", strlen(optarg
)))
419 /** \li On check send 0 / SIGNULL. */
420 opt_send_signal
= 0; /* SIGNULL */
421 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
422 /** \li On parse set global flag to re-parse the config file only. */
423 opt_parse_cfg_only
= 1;
431 * Set global malloc_debug_level to the value given following the option.
432 * if none is given it toggles the xmalloc_trace option on/off */
435 malloc_debug_level
= atoi(optarg
);
437 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
442 xmalloc_trace
= !xmalloc_trace
;
444 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
449 #if USE_WIN32_SERVICE
453 * Set global option opt_signal_service (to TRUE).
454 * Stores the additional parameter given in global WIN32_Service_name */
455 xfree(WIN32_Service_name
);
457 WIN32_Service_name
= xstrdup(optarg
);
459 opt_signal_service
= TRUE
;
465 * Set global option opt_remove_service (to TRUE) */
466 opt_remove_service
= TRUE
;
474 * Stores the syslog facility name in global opt_syslog_facility
475 * then performs actions for -s option. */
476 opt_syslog_facility
= xstrdup(optarg
);
480 * Initialize the syslog for output */
483 _db_set_syslog(opt_syslog_facility
);
489 fatal("Logging to syslog not available on this platform");
496 * Store the ICP port number given in global option icpPortNumOverride
497 * ensuring its a positive number. */
498 icpPortNumOverride
= atoi(optarg
);
500 if (icpPortNumOverride
< 0)
501 icpPortNumOverride
= 0;
507 * Display squid version and build information. Then exit. */
508 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string
, SQUID_CONFIGURE_OPTIONS
);
510 #if USE_WIN32_SERVICE
512 printf("Compiled as Windows System Service.\n");
522 * Set global option opt_debug_stderr and opt_create_swap_dirs */
523 opt_debug_stderr
= 1;
525 opt_create_swap_dirs
= 1;
534 /** \par h,?, or unknown
535 * \copydoc usage() */
549 #ifndef _SQUID_MSWIN_
552 signal(sig
, rotate_logs
);
562 #ifndef _SQUID_MSWIN_
565 signal(sig
, reconfigure
);
573 do_shutdown
= sig
== SIGINT
? -1 : 1;
580 #ifndef _SQUID_MSWIN_
581 #ifdef KILL_PARENT_OPT
584 debugs(1, 1, "Killing RunCache, pid " << getppid());
586 if (kill(getppid(), sig
) < 0)
587 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
591 #if SA_RESETHAND == 0
592 signal(SIGTERM
, SIG_DFL
);
594 signal(SIGINT
, SIG_DFL
);
601 serverConnectionsOpen(void)
603 clientOpenListenSockets();
604 icpConnectionsOpen();
611 snmpConnectionOpen();
615 wccpConnectionOpen();
620 wccp2ConnectionOpen();
632 peerSourceHashInit();
636 serverConnectionsClose(void)
638 assert(shutting_down
|| reconfiguring
);
639 clientHttpConnectionsClose();
640 icpConnectionShutdown();
643 htcpSocketShutdown();
649 snmpConnectionShutdown();
653 wccpConnectionClose();
657 wccp2ConnectionClose();
664 mainReconfigureStart(void)
666 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
669 // Initiate asynchronous closing sequence
670 serverConnectionsClose();
671 icpConnectionClose();
678 snmpConnectionClose();
689 authenticateShutdown();
690 externalAclShutdown();
691 storeDirCloseSwapLogs();
697 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
702 mainReconfigureFinish(void *)
704 debugs(1, 3, "finishing reconfiguring");
707 enter_suid(); /* root to read config file */
708 parseConfigFile(ConfigFile
);
709 setUmask(Config
.umask
);
712 _db_init(Config
.Log
.log
, Config
.debugOptions
);
713 ipcache_restart(); /* clear stuck entries */
714 authenticateUserCacheRestart(); /* clear stuck ACL entries */
715 fqdncache_restart(); /* sigh, fqdncache too */
717 errorInitialize(); /* reload error pages */
731 authenticateInit(&Config
.authConfiguration
);
742 serverConnectionsOpen();
746 storeDirOpenSwapLogs();
748 mimeInit(Config
.mimeTablePathname
);
750 if (Config
.onoff
.announce
) {
751 if (!eventFind(start_announce
, NULL
))
752 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
754 if (eventFind(start_announce
, NULL
))
755 eventDelete(start_announce
, NULL
);
758 writePidFile(); /* write PID file */
760 debugs(1, 1, "Ready to serve requests.");
775 authenticateShutdown();
776 externalAclShutdown();
777 _db_rotate_log(); /* cache.log */
778 storeDirWriteCleanLogs(1);
779 storeLogRotate(); /* store.log */
780 accessLogRotate(); /* access.log */
781 useragentRotateLog(); /* useragent.log */
782 refererRotateLog(); /* referer.log */
795 authenticateInit(&Config
.authConfiguration
);
800 setEffectiveUser(void)
803 leave_suid(); /* Run as non privilegied user */
809 if (geteuid() == 0) {
810 debugs(0, 0, "Squid is not safe to run as root! If you must");
811 debugs(0, 0, "start Squid as root, then you must configure");
812 debugs(0, 0, "it to run as a non-priveledged user with the");
813 debugs(0, 0, "'cache_effective_user' option in the config file.");
814 fatal("Don't run Squid as root, set 'cache_effective_user'!");
821 char pathbuf
[MAXPATHLEN
];
823 if (Config
.coredump_dir
) {
824 if (0 == strcmp("none", Config
.coredump_dir
)) {
826 } else if (chdir(Config
.coredump_dir
) == 0) {
827 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
830 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
834 /* If we don't have coredump_dir or couldn't cd there, report current dir */
835 if (getcwd(pathbuf
, MAXPATHLEN
)) {
836 debugs(0, 1, "Current Directory is " << pathbuf
);
838 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
843 #include "DelayPools.h"
849 /* chroot if configured to run inside chroot */
851 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
852 fatal("failed to chroot");
855 if (opt_catch_signals
) {
856 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
857 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
860 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
861 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
865 if (icpPortNumOverride
!= 1)
866 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
868 _db_init(Config
.Log
.log
, Config
.debugOptions
);
870 fd_open(fileno(debug_log
), FD_LOG
, Config
.Log
.log
);
874 log_trace_init("/tmp/squid.alloc");
878 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
882 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
883 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
884 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
886 debugs(1, 0, "Running on " << WIN32_OS_string
);
890 debugs(1, 1, "Process ID " << getpid());
892 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
896 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
898 if (WIN32_Socks_initialized
)
899 debugs(1, 1, "Windows sockets initialized");
901 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
902 WIN32_IpAddrChangeMonitorInit();
907 if (!configured_once
)
908 disk_init(); /* disk_init must go before ipcache_init() */
928 authenticateInit(&Config
.authConfiguration
);
936 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
938 httpReplyInitModule(); /* must go before accepting replies */
956 malloc_debug(0, malloc_debug_level
);
960 if (!configured_once
) {
969 /* after this point we want to see the mallinfo() output */
971 mimeInit(Config
.mimeTablePathname
);
978 FwdState::initModule();
979 /* register the modules in the cache manager menus */
981 cbdataRegisterWithCacheManager();
982 /* These use separate calls so that the comm loops can eventually
988 // TODO: pconn is a good candidate for new-style registration
989 // PconnModule::GetInstance()->registerWithCacheManager();
990 // moved to PconnModule::PconnModule()
1003 serverConnectionsOpen();
1007 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1009 if (Config
.chroot_dir
)
1012 if (!configured_once
)
1013 writePidFile(); /* write PID file */
1015 #ifdef _SQUID_LINUX_THREADS_
1017 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1019 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1023 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1025 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1029 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1031 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1033 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1037 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1043 #if USE_LOADABLE_MODULES
1044 LoadableModulesConfigure(Config
.loadable_module_names
);
1048 bool enableAdaptation
= false;
1050 // We can remove this dependency on specific adaptation mechanisms
1051 // if we create a generic Registry of such mechanisms. Should we?
1053 TheICAPConfig
.finalize();
1054 enableAdaptation
= TheICAPConfig
.onoff
|| enableAdaptation
;
1057 Ecap::TheConfig
.finalize(); // must be after we load modules
1058 enableAdaptation
= Ecap::TheConfig
.onoff
|| enableAdaptation
;
1060 // must be the last adaptation-related finalize
1061 Adaptation::Config::Finalize(enableAdaptation
);
1065 debugs(1, 1, "Ready to serve requests.");
1067 if (!configured_once
) {
1068 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1070 if (Config
.onoff
.announce
)
1071 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1073 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1075 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1079 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1083 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1086 configured_once
= 1;
1089 /// unsafe main routine -- may throw
1090 static int SquidMain(int argc
, char **argv
);
1091 /// unsafe main routine wrapper to catch exceptions
1092 static int SquidMainSafe(int argc
, char **argv
);
1094 #if USE_WIN32_SERVICE
1095 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1096 extern "C" void WINAPI
1097 SquidWinSvcMain(int argc
, char **argv
)
1100 main(int argc
, char **argv
)
1103 SquidMainSafe(argc
, argv
);
1107 SquidMainSafe(int argc
, char **argv
)
1110 return SquidMain(argc
, argv
);
1111 } catch (const std::exception
&e
) {
1112 std::cerr
<< "dying from an unhandled exception: " << e
.what() << std::endl
;
1115 std::cerr
<< "dying from an unhandled exception." << std::endl
;
1118 return -1; // not reached
1122 SquidMain(int argc
, char **argv
)
1124 #ifdef _SQUID_WIN32_
1131 sbrk_start
= sbrk(0);
1134 Debug::parseOptions(NULL
);
1137 #if defined(SQUID_MAXFD_LIMIT)
1139 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1140 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1144 #ifdef _SQUID_WIN32_
1146 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1147 return WIN32_init_err
;
1151 /* call mallopt() before anything else */
1154 /* Round up all sizes to a multiple of this */
1155 mallopt(M_GRAIN
, 16);
1159 /* biggest size that is considered a small block */
1160 mallopt(M_MXFAST
, 256);
1164 /* allocate this many small blocks at once */
1165 mallopt(M_NLBLKS
, 32);
1168 #endif /* HAVE_MALLOPT */
1170 squid_srandom(time(NULL
));
1174 squid_start
= current_time
;
1176 failure_notify
= fatal_dump
;
1178 #if USE_WIN32_SERVICE
1180 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1184 mainParseOptions(argc
, argv
);
1186 if (opt_parse_cfg_only
) {
1187 Debug::parseOptions("ALL,1");
1190 #if USE_WIN32_SERVICE
1192 if (opt_install_service
) {
1193 WIN32_InstallService();
1197 if (opt_remove_service
) {
1198 WIN32_RemoveService();
1202 if (opt_command_line
) {
1203 WIN32_SetServiceCommandLine();
1209 /* parse configuration file
1210 * note: in "normal" case this used to be called from mainInitialize() */
1215 ConfigFile
= xstrdup(DefaultConfigFile
);
1217 assert(!configured_once
);
1221 storeFsInit(); /* required for config parsing */
1223 /* May not be needed for parsing, have not audited for such */
1224 DiskIOModule::SetupAllModules();
1226 /* Shouldn't be needed for config parsing, but have not audited for such */
1227 StoreFileSystem::SetupAllFs();
1229 /* we may want the parsing process to set this up in the future */
1230 Store::Root(new StoreController
);
1232 parse_err
= parseConfigFile(ConfigFile
);
1236 if (opt_parse_cfg_only
)
1240 setUmask(Config
.umask
);
1241 if (-1 == opt_send_signal
)
1242 if (checkRunningPid())
1259 /* send signal to running copy and exit */
1260 if (opt_send_signal
!= -1) {
1261 /* chroot if configured to run inside chroot */
1263 if (Config
.chroot_dir
) {
1264 if (chroot(Config
.chroot_dir
))
1265 fatal("failed to chroot");
1276 if (opt_create_swap_dirs
) {
1277 /* chroot if configured to run inside chroot */
1279 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1280 fatal("failed to chroot");
1284 debugs(0, 0, "Creating Swap Directories");
1285 Store::Root().create();
1295 /* init comm module */
1300 if (opt_no_daemon
) {
1301 /* we have to init fdstat here. */
1302 fd_open(0, FD_LOG
, "stdin");
1303 fd_open(1, FD_LOG
, "stdout");
1304 fd_open(2, FD_LOG
, "stderr");
1307 #if USE_WIN32_SERVICE
1309 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1315 #if USE_WIN32_SERVICE
1317 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1324 SignalEngine
signalEngine(mainLoop
);
1326 mainLoop
.registerEngine(&signalEngine
);
1328 /* TODO: stop requiring the singleton here */
1329 mainLoop
.registerEngine(EventScheduler::GetInstance());
1331 StoreRootEngine store_engine
;
1333 mainLoop
.registerEngine(&store_engine
);
1335 CommSelectEngine comm_engine
;
1337 mainLoop
.registerEngine(&comm_engine
);
1339 mainLoop
.setPrimaryEngine(&comm_engine
);
1341 /* use the standard time service */
1342 TimeEngine time_engine
;
1344 mainLoop
.setTimeService(&time_engine
);
1348 if (mainLoop
.errcount
== 10)
1349 fatal_dump("Event loop exited with failure.");
1351 /* shutdown squid now */
1364 if (strcmp(Config
.pidFilename
, "none") == 0) {
1365 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1368 pid
= readPidFile();
1371 #if USE_WIN32_SERVICE
1373 if (opt_signal_service
) {
1374 WIN32_sendSignal(opt_send_signal
);
1377 #ifdef _SQUID_MSWIN_
1379 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1380 fprintf(stderr
, "signal to Squid Service:\n");
1381 fprintf(stderr
, "missing -n command line switch.\n");
1390 if (kill(pid
, opt_send_signal
) &&
1391 /* ignore permissions if just running check */
1392 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1393 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1394 fprintf(stderr
, "signal %d to process %d: %s\n",
1395 opt_send_signal
, (int) pid
, xstrerror());
1399 if (opt_send_signal
!= SIGTERM
) {
1400 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1403 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1408 /* signal successfully sent */
1412 #ifndef _SQUID_MSWIN_
1414 * This function is run when Squid is in daemon mode, just
1415 * before the parent forks and starts up the child process.
1416 * It can be used for admin-specific tasks, such as notifying
1417 * someone that Squid is (re)started.
1420 mainStartScript(const char *prog
)
1422 char script
[SQUID_MAXPATHLEN
];
1427 xstrncpy(script
, prog
, MAXPATHLEN
);
1429 if ((t
= strrchr(script
, '/'))) {
1431 sl
= strlen(script
);
1434 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1436 if ((cpid
= fork()) == 0) {
1438 execl(script
, squid_start_script
, (char *)NULL
);
1444 rpid
= wait3(&status
, 0, NULL
);
1448 rpid
= waitpid(-1, &status
, 0);
1451 } while (rpid
!= cpid
);
1455 #endif /* _SQUID_MSWIN_ */
1458 checkRunningPid(void)
1465 pid
= readPidFile();
1470 if (kill(pid
, 0) < 0)
1473 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1479 watch_child(char *argv
[])
1481 #ifndef _SQUID_MSWIN_
1502 if (*(argv
[0]) == '(')
1505 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1507 if ((pid
= fork()) < 0)
1508 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1513 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1519 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1520 ioctl(i
, TIOCNOTTY
, NULL
);
1527 * RBCOLLINS - if cygwin stackdumps when squid is run without
1528 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1529 * 1.1.3. execvp had a bit overflow error in a loop..
1531 /* Connect stdio to /dev/null in daemon mode */
1532 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1535 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1539 if (opt_debug_stderr
< 0) {
1545 mainStartScript(argv
[0]);
1547 if ((pid
= fork()) == 0) {
1549 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1550 prog
= xstrdup(argv
[0]);
1551 argv
[0] = xstrdup("(squid)");
1553 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1557 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1559 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1563 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1567 pid
= wait3(&status
, 0, NULL
);
1571 pid
= waitpid(-1, &status
, 0);
1577 if (WIFEXITED(status
)) {
1579 "Squid Parent: child process %d exited with status %d",
1580 pid
, WEXITSTATUS(status
));
1581 } else if (WIFSIGNALED(status
)) {
1583 "Squid Parent: child process %d exited due to signal %d with status %d",
1584 pid
, WTERMSIG(status
), WEXITSTATUS(status
));
1586 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", pid
);
1589 if (stop
- start
< 10)
1594 if (failcount
== 5) {
1595 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1599 if (WIFEXITED(status
))
1600 if (WEXITSTATUS(status
) == 0)
1603 if (WIFSIGNALED(status
)) {
1604 switch (WTERMSIG(status
)) {
1612 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1621 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1626 #endif /* _SQUID_MSWIN_ */
1633 /* XXX: This function is called after the main loop has quit, which
1634 * means that no AsyncCalls would be called, including close handlers.
1635 * TODO: We need to close/shut/free everything that needs calls before
1639 #if USE_WIN32_SERVICE
1640 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1643 debugs(1, 1, "Shutting down...");
1653 externalAclShutdown();
1654 icpConnectionClose();
1661 snmpConnectionClose();
1665 wccpConnectionClose();
1669 wccp2ConnectionClose();
1672 releaseServerSockets();
1673 commCloseAllSockets();
1676 DelayPools::FreePools();
1679 authenticateShutdown();
1680 #if USE_WIN32_SERVICE
1682 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1685 Store::Root().sync(); /* Flush pending object writes/unlinks */
1688 unlinkdClose(); /* after sync/flush */
1691 storeDirWriteCleanLogs(0);
1694 Store::Root().sync(); /* Flush log writes */
1697 useragentLogClose();
1704 Store::Root().sync(); /* Flush log close */
1705 StoreFileSystem::FreeAllFs();
1706 DiskIOModule::FreeAllModules();
1707 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1711 /*stmemFreeMemory(); */
1713 ipcacheFreeMemory();
1714 fqdncacheFreeMemory();
1716 clientdbFreeMemory();
1717 httpHeaderCleanModule();
1725 if (opt_no_daemon
) {
1740 xmalloc_find_leaks();
1742 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1751 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1753 safeunlink(Config
.pidFilename
, 0);
1757 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1761 * We used to fclose(debug_log) here if it was set, but then
1762 * we forgot to set it to NULL. That caused some coredumps
1763 * because exit() ends up calling a bunch of destructors and
1764 * such. So rather than forcing the debug_log to close, we'll
1765 * leave it open so that those destructors can write some
1766 * debugging if necessary. The file will be closed anyway when
1767 * the process truly exits.
1770 exit(shutdown_status
);