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 "comm_epoll.h"
62 #include "comm_kqueue.h"
65 #include "comm_poll.h"
67 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
68 #include "comm_select.h"
70 #include "SquidTime.h"
74 #include "icmp/IcmpSquid.h"
75 #include "icmp/net_db.h"
76 #include "TextException.h"
78 #if USE_LOADABLE_MODULES
79 #include "LoadableModules.h"
83 #include "adaptation/icap/Config.h"
86 #include "adaptation/ecap/Config.h"
89 #include "adaptation/Config.h"
93 #include "esi/Module.h"
96 #include "fs/Module.h"
100 #include "squid_windows.h"
103 static int opt_install_service
= FALSE
;
104 static int opt_remove_service
= FALSE
;
105 static int opt_signal_service
= FALSE
;
106 static int opt_command_line
= FALSE
;
107 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
108 void WINAPI
WIN32_svcHandler(DWORD
);
112 /** for error reporting from xmalloc and friends */
113 SQUIDCEXTERN
void (*failure_notify
) (const char *);
115 static int opt_parse_cfg_only
= 0;
116 static char *opt_syslog_facility
= NULL
;
117 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
118 static int configured_once
= 0;
120 static int malloc_debug_level
= 0;
122 static volatile int do_reconfigure
= 0;
123 static volatile int do_rotate
= 0;
124 static volatile int do_shutdown
= 0;
125 static volatile int shutdown_status
= 0;
127 static void mainRotate(void);
128 static void mainReconfigureStart(void);
129 static void mainReconfigureFinish(void*);
130 static void mainInitialize(void);
131 static void usage(void);
132 static void mainParseOptions(int argc
, char *argv
[]);
133 static void sendSignal(void);
134 static void serverConnectionsOpen(void);
135 static void serverConnectionsClose(void);
136 static void watch_child(char **);
137 static void setEffectiveUser(void);
139 extern void log_trace_done();
140 extern void log_trace_init(char *);
142 static void SquidShutdown(void);
143 static void mainSetCwd(void);
144 static int checkRunningPid(void);
146 #ifndef _SQUID_MSWIN_
147 static const char *squid_start_script
= "squid_start";
151 #include "test_access.c"
154 /** temporary thunk across to the unrefactored store interface */
156 class StoreRootEngine
: public AsyncEngine
160 int checkEvents(int timeout
) {
161 Store::Root().callback();
166 class SignalEngine
: public AsyncEngine
170 SignalEngine(EventLoop
&loop
) : loop(loop
) {}
171 virtual int checkEvents(int timeout
);
174 static void StopEventLoop(void * data
) {
175 static_cast<SignalEngine
*>(data
)->loop
.stop();
178 void doShutdown(time_t wait
);
184 SignalEngine::checkEvents(int timeout
)
186 PROF_start(SignalEngine_checkEvents
);
188 if (do_reconfigure
) {
189 mainReconfigureStart();
191 } else if (do_rotate
) {
194 } else if (do_shutdown
) {
195 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
199 PROF_stop(SignalEngine_checkEvents
);
204 SignalEngine::doShutdown(time_t wait
)
206 debugs(1, 1, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
207 debugs(1, 1, "Waiting " << wait
<< " seconds for active connections to finish");
211 #if USE_WIN32_SERVICE
212 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
215 serverConnectionsClose();
216 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
223 #if USE_WIN32_SERVICE
224 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
226 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
228 " -a port Specify HTTP port number (default: %d).\n"
229 " -d level Write debugging to stderr also.\n"
230 " -f file Use given config-file instead of\n"
232 " -h Print help message.\n"
233 #if USE_WIN32_SERVICE
234 " -i Installs as a Windows Service (see -n option).\n"
236 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
237 " Parse configuration file, then send signal to \n"
238 " running copy (except -k parse) and exit.\n"
239 #if USE_WIN32_SERVICE
240 " -n name Specify Windows Service name to use for service operations\n"
241 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
242 " -r Removes a Windows Service (see -n option).\n"
244 " -s | -l facility\n"
245 " Enable logging to syslog.\n"
246 " -u port Specify ICP port number (default: %d), disable with 0.\n"
247 " -v Print version.\n"
248 " -z Create swap directories\n"
249 " -C Do not catch fatal signals.\n"
250 " -D OBSOLETE. Scheduled for removal.\n"
251 " -F Don't serve any requests until store is rebuilt.\n"
252 " -N No daemon mode.\n"
253 #if USE_WIN32_SERVICE
255 " Set Windows Service Command line options in Registry.\n"
257 " -R Do not set REUSEADDR on port.\n"
258 " -S Double-check swap during rebuild.\n"
259 " -X Force full debugging.\n"
260 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
261 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
266 * Parse the parameters received via command line interface.
268 \param argc Number of options received on command line
269 \param argv List of parameters received on command line
272 mainParseOptions(int argc
, char *argv
[])
277 #if USE_WIN32_SERVICE
278 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
280 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
288 * Unset/disabel global option for catchign signals. opt_catch_signals */
289 opt_catch_signals
= 0;
294 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
295 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
300 * Set global option for foreground rebuild. opt_foreground_rebuild */
301 opt_foreground_rebuild
= 1;
306 * Set global option for 'no_daemon' mode. opt_no_daemon */
310 #if USE_WIN32_SERVICE
314 * Set global option. opt_command_lin and WIN32_Command_Line */
315 opt_command_line
= 1;
316 WIN32_Command_Line
= xstrdup(optarg
);
322 * Unset/disable global option opt_reuseaddr */
328 * Set global option opt_store_doublecheck */
329 opt_store_doublecheck
= 1;
334 * Force full debugging */
335 Debug::parseOptions("rotate=0 ALL,9");
336 Debug::override_X
= 1;
337 sigusr2_handle(SIGUSR2
);
342 * Set global option opt_reload_hit_only */
343 opt_reload_hit_only
= 1;
346 #if USE_WIN32_SERVICE
350 * Set global option opt_install_service (to TRUE) */
351 opt_install_service
= TRUE
;
357 * Add optional HTTP port as given following the option */
358 add_http_port(optarg
);
363 * Set global option Debug::log_stderr to the number given follwoign the option */
364 Debug::log_stderr
= atoi(optarg
);
369 * Load the file given instead of the default squid.conf. */
371 ConfigFile
= xstrdup(optarg
);
376 * Run the administrative action given following the option */
378 /** \li When its an unknown option display the usage help. */
379 if ((int) strlen(optarg
) < 1)
382 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
383 /** \li On reconfigure send SIGHUP. */
384 opt_send_signal
= SIGHUP
;
385 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
386 /** \li On rotate send SIGQUIT or SIGUSR1. */
387 #ifdef _SQUID_LINUX_THREADS_
389 opt_send_signal
= SIGQUIT
;
393 opt_send_signal
= SIGUSR1
;
397 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
398 /** \li On debug send SIGTRAP or SIGUSR2. */
399 #ifdef _SQUID_LINUX_THREADS_
401 opt_send_signal
= SIGTRAP
;
405 opt_send_signal
= SIGUSR2
;
409 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
410 /** \li On shutdown send SIGTERM. */
411 opt_send_signal
= SIGTERM
;
412 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
413 /** \li On interrupt send SIGINT. */
414 opt_send_signal
= SIGINT
;
415 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
416 /** \li On kill send SIGKILL. */
417 opt_send_signal
= SIGKILL
;
421 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
422 /** \li On restart send SIGTTIN. (exit and restart by parent) */
423 opt_send_signal
= SIGTTIN
;
427 else if (!strncmp(optarg
, "check", strlen(optarg
)))
428 /** \li On check send 0 / SIGNULL. */
429 opt_send_signal
= 0; /* SIGNULL */
430 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
431 /** \li On parse set global flag to re-parse the config file only. */
432 opt_parse_cfg_only
= 1;
440 * Set global malloc_debug_level to the value given following the option.
441 * if none is given it toggles the xmalloc_trace option on/off */
444 malloc_debug_level
= atoi(optarg
);
446 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
451 xmalloc_trace
= !xmalloc_trace
;
453 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
458 #if USE_WIN32_SERVICE
462 * Set global option opt_signal_service (to TRUE).
463 * Stores the additional parameter given in global WIN32_Service_name */
464 xfree(WIN32_Service_name
);
466 WIN32_Service_name
= xstrdup(optarg
);
468 opt_signal_service
= TRUE
;
474 * Set global option opt_remove_service (to TRUE) */
475 opt_remove_service
= TRUE
;
483 * Stores the syslog facility name in global opt_syslog_facility
484 * then performs actions for -s option. */
485 opt_syslog_facility
= xstrdup(optarg
);
489 * Initialize the syslog for output */
492 _db_set_syslog(opt_syslog_facility
);
498 fatal("Logging to syslog not available on this platform");
505 * Store the ICP port number given in global option icpPortNumOverride
506 * ensuring its a positive number. */
507 icpPortNumOverride
= atoi(optarg
);
509 if (icpPortNumOverride
< 0)
510 icpPortNumOverride
= 0;
516 * Display squid version and build information. Then exit. */
517 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string
, SQUID_CONFIGURE_OPTIONS
);
519 #if USE_WIN32_SERVICE
521 printf("Compiled as Windows System Service.\n");
531 * Set global option Debug::log_stderr and opt_create_swap_dirs */
532 Debug::log_stderr
= 1;
533 opt_create_swap_dirs
= 1;
541 /** \par h,?, or unknown
542 * \copydoc usage() */
556 #ifndef _SQUID_MSWIN_
559 signal(sig
, rotate_logs
);
569 #ifndef _SQUID_MSWIN_
572 signal(sig
, reconfigure
);
580 do_shutdown
= sig
== SIGINT
? -1 : 1;
587 #ifndef _SQUID_MSWIN_
588 #ifdef KILL_PARENT_OPT
591 debugs(1, 1, "Killing RunCache, pid " << getppid());
593 if (kill(getppid(), sig
) < 0)
594 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
598 #if SA_RESETHAND == 0
599 signal(SIGTERM
, SIG_DFL
);
601 signal(SIGINT
, SIG_DFL
);
608 serverConnectionsOpen(void)
610 clientOpenListenSockets();
611 icpConnectionsOpen();
618 snmpConnectionOpen();
622 wccpConnectionOpen();
627 wccp2ConnectionOpen();
639 peerSourceHashInit();
643 serverConnectionsClose(void)
645 assert(shutting_down
|| reconfiguring
);
646 clientHttpConnectionsClose();
647 icpConnectionShutdown();
650 htcpSocketShutdown();
656 snmpConnectionShutdown();
660 wccpConnectionClose();
664 wccp2ConnectionClose();
671 mainReconfigureStart(void)
673 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
676 // Initiate asynchronous closing sequence
677 serverConnectionsClose();
678 icpConnectionClose();
685 snmpConnectionClose();
696 authenticateShutdown();
697 externalAclShutdown();
698 storeDirCloseSwapLogs();
707 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
712 mainReconfigureFinish(void *)
714 debugs(1, 3, "finishing reconfiguring");
717 enter_suid(); /* root to read config file */
719 // we may have disabled the need for PURGE
720 if(Config2
.onoff
.enable_purge
)
721 Config2
.onoff
.enable_purge
= 2;
723 parseConfigFile(ConfigFile
);
725 setUmask(Config
.umask
);
728 _db_init(Debug::cache_log
, Debug::debugOptions
);
729 ipcache_restart(); /* clear stuck entries */
730 authenticateUserCacheRestart(); /* clear stuck ACL entries */
731 fqdncache_restart(); /* sigh, fqdncache too */
733 errorInitialize(); /* reload error pages */
750 authenticateInit(&Config
.authConfiguration
);
761 serverConnectionsOpen();
765 storeDirOpenSwapLogs();
767 mimeInit(Config
.mimeTablePathname
);
769 if (Config
.onoff
.announce
) {
770 if (!eventFind(start_announce
, NULL
))
771 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
773 if (eventFind(start_announce
, NULL
))
774 eventDelete(start_announce
, NULL
);
777 writePidFile(); /* write PID file */
779 debugs(1, 1, "Ready to serve requests.");
792 authenticateShutdown();
793 externalAclShutdown();
795 _db_rotate_log(); /* cache.log */
796 storeDirWriteCleanLogs(1);
797 storeLogRotate(); /* store.log */
798 accessLogRotate(); /* access.log */
799 useragentRotateLog(); /* useragent.log */
800 refererRotateLog(); /* referer.log */
802 icapLogRotate(); /*icap.log*/
813 authenticateInit(&Config
.authConfiguration
);
818 setEffectiveUser(void)
821 leave_suid(); /* Run as non privilegied user */
827 if (geteuid() == 0) {
828 debugs(0, 0, "Squid is not safe to run as root! If you must");
829 debugs(0, 0, "start Squid as root, then you must configure");
830 debugs(0, 0, "it to run as a non-priveledged user with the");
831 debugs(0, 0, "'cache_effective_user' option in the config file.");
832 fatal("Don't run Squid as root, set 'cache_effective_user'!");
839 char pathbuf
[MAXPATHLEN
];
841 if (Config
.coredump_dir
) {
842 if (0 == strcmp("none", Config
.coredump_dir
)) {
844 } else if (chdir(Config
.coredump_dir
) == 0) {
845 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
848 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
852 /* If we don't have coredump_dir or couldn't cd there, report current dir */
853 if (getcwd(pathbuf
, MAXPATHLEN
)) {
854 debugs(0, 1, "Current Directory is " << pathbuf
);
856 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
861 #include "DelayPools.h"
867 /* chroot if configured to run inside chroot */
869 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
870 fatal("failed to chroot");
873 if (opt_catch_signals
) {
874 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
875 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
878 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
879 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
883 if (icpPortNumOverride
!= 1)
884 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
886 _db_init(Debug::cache_log
, Debug::debugOptions
);
888 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
892 log_trace_init("/tmp/squid.alloc");
896 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
900 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
901 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
902 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
904 debugs(1, 0, "Running on " << WIN32_OS_string
);
908 debugs(1, 1, "Process ID " << getpid());
910 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
914 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
916 if (WIN32_Socks_initialized
)
917 debugs(1, 1, "Windows sockets initialized");
919 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
920 WIN32_IpAddrChangeMonitorInit();
925 if (!configured_once
)
926 disk_init(); /* disk_init must go before ipcache_init() */
946 authenticateInit(&Config
.authConfiguration
);
954 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
956 httpReplyInitModule(); /* must go before accepting replies */
977 malloc_debug(0, malloc_debug_level
);
981 if (!configured_once
) {
990 /* after this point we want to see the mallinfo() output */
992 mimeInit(Config
.mimeTablePathname
);
999 FwdState::initModule();
1000 /* register the modules in the cache manager menus */
1002 cbdataRegisterWithCacheManager();
1003 /* These use separate calls so that the comm loops can eventually
1009 // TODO: pconn is a good candidate for new-style registration
1010 // PconnModule::GetInstance()->registerWithCacheManager();
1011 // moved to PconnModule::PconnModule()
1024 serverConnectionsOpen();
1028 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1030 if (Config
.chroot_dir
)
1033 if (!configured_once
)
1034 writePidFile(); /* write PID file */
1036 #ifdef _SQUID_LINUX_THREADS_
1038 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1040 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1044 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1046 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1050 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1052 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1054 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1058 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1064 #if USE_LOADABLE_MODULES
1065 LoadableModulesConfigure(Config
.loadable_module_names
);
1069 bool enableAdaptation
= false;
1071 // We can remove this dependency on specific adaptation mechanisms
1072 // if we create a generic Registry of such mechanisms. Should we?
1074 Adaptation::Icap::TheConfig
.finalize();
1075 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1078 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1079 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1081 // must be the last adaptation-related finalize
1082 Adaptation::Config::Finalize(enableAdaptation
);
1089 debugs(1, 1, "Ready to serve requests.");
1091 if (!configured_once
) {
1092 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1094 if (Config
.onoff
.announce
)
1095 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1097 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1099 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1103 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1107 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1110 configured_once
= 1;
1113 /// unsafe main routine -- may throw
1114 int SquidMain(int argc
, char **argv
);
1115 /// unsafe main routine wrapper to catch exceptions
1116 static int SquidMainSafe(int argc
, char **argv
);
1118 #if USE_WIN32_SERVICE
1119 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1120 extern "C" void WINAPI
1121 SquidWinSvcMain(int argc
, char **argv
)
1124 main(int argc
, char **argv
)
1127 SquidMainSafe(argc
, argv
);
1131 SquidMainSafe(int argc
, char **argv
)
1134 return SquidMain(argc
, argv
);
1135 } catch (const std::exception
&e
) {
1136 std::cerr
<< "dying from an unhandled exception: " << e
.what() << std::endl
;
1139 std::cerr
<< "dying from an unhandled exception." << std::endl
;
1142 return -1; // not reached
1146 SquidMain(int argc
, char **argv
)
1148 #ifdef _SQUID_WIN32_
1155 sbrk_start
= sbrk(0);
1158 Debug::parseOptions(NULL
);
1161 #if defined(SQUID_MAXFD_LIMIT)
1163 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1164 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1168 #ifdef _SQUID_WIN32_
1170 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1171 return WIN32_init_err
;
1175 /* call mallopt() before anything else */
1178 /* Round up all sizes to a multiple of this */
1179 mallopt(M_GRAIN
, 16);
1183 /* biggest size that is considered a small block */
1184 mallopt(M_MXFAST
, 256);
1188 /* allocate this many small blocks at once */
1189 mallopt(M_NLBLKS
, 32);
1192 #endif /* HAVE_MALLOPT */
1194 squid_srandom(time(NULL
));
1198 squid_start
= current_time
;
1200 failure_notify
= fatal_dump
;
1202 #if USE_WIN32_SERVICE
1204 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1208 mainParseOptions(argc
, argv
);
1210 if (opt_parse_cfg_only
) {
1211 Debug::parseOptions("ALL,1");
1214 #if USE_WIN32_SERVICE
1216 if (opt_install_service
) {
1217 WIN32_InstallService();
1221 if (opt_remove_service
) {
1222 WIN32_RemoveService();
1226 if (opt_command_line
) {
1227 WIN32_SetServiceCommandLine();
1233 /* parse configuration file
1234 * note: in "normal" case this used to be called from mainInitialize() */
1239 ConfigFile
= xstrdup(DefaultConfigFile
);
1241 assert(!configured_once
);
1245 storeFsInit(); /* required for config parsing */
1247 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1250 /* May not be needed for parsing, have not audited for such */
1251 DiskIOModule::SetupAllModules();
1253 /* Shouldn't be needed for config parsing, but have not audited for such */
1254 StoreFileSystem::SetupAllFs();
1256 /* we may want the parsing process to set this up in the future */
1257 Store::Root(new StoreController
);
1259 parse_err
= parseConfigFile(ConfigFile
);
1263 if (opt_parse_cfg_only
)
1267 setUmask(Config
.umask
);
1268 if (-1 == opt_send_signal
)
1269 if (checkRunningPid())
1286 /* send signal to running copy and exit */
1287 if (opt_send_signal
!= -1) {
1288 /* chroot if configured to run inside chroot */
1290 if (Config
.chroot_dir
) {
1291 if (chroot(Config
.chroot_dir
))
1292 fatal("failed to chroot");
1303 if (opt_create_swap_dirs
) {
1304 /* chroot if configured to run inside chroot */
1306 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1307 fatal("failed to chroot");
1311 debugs(0, 0, "Creating Swap Directories");
1312 Store::Root().create();
1322 /* init comm module */
1327 if (opt_no_daemon
) {
1328 /* we have to init fdstat here. */
1329 fd_open(0, FD_LOG
, "stdin");
1330 fd_open(1, FD_LOG
, "stdout");
1331 fd_open(2, FD_LOG
, "stderr");
1334 #if USE_WIN32_SERVICE
1336 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1342 #if USE_WIN32_SERVICE
1344 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1351 SignalEngine
signalEngine(mainLoop
);
1353 mainLoop
.registerEngine(&signalEngine
);
1355 /* TODO: stop requiring the singleton here */
1356 mainLoop
.registerEngine(EventScheduler::GetInstance());
1358 StoreRootEngine store_engine
;
1360 mainLoop
.registerEngine(&store_engine
);
1362 CommSelectEngine comm_engine
;
1364 mainLoop
.registerEngine(&comm_engine
);
1366 mainLoop
.setPrimaryEngine(&comm_engine
);
1368 /* use the standard time service */
1369 TimeEngine time_engine
;
1371 mainLoop
.setTimeService(&time_engine
);
1375 if (mainLoop
.errcount
== 10)
1376 fatal_dump("Event loop exited with failure.");
1378 /* shutdown squid now */
1391 if (strcmp(Config
.pidFilename
, "none") == 0) {
1392 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1395 pid
= readPidFile();
1398 #if USE_WIN32_SERVICE
1400 if (opt_signal_service
) {
1401 WIN32_sendSignal(opt_send_signal
);
1404 #ifdef _SQUID_MSWIN_
1406 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1407 fprintf(stderr
, "signal to Squid Service:\n");
1408 fprintf(stderr
, "missing -n command line switch.\n");
1417 if (kill(pid
, opt_send_signal
) &&
1418 /* ignore permissions if just running check */
1419 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1420 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1421 fprintf(stderr
, "signal %d to process %d: %s\n",
1422 opt_send_signal
, (int) pid
, xstrerror());
1426 if (opt_send_signal
!= SIGTERM
) {
1427 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1430 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1435 /* signal successfully sent */
1439 #ifndef _SQUID_MSWIN_
1441 * This function is run when Squid is in daemon mode, just
1442 * before the parent forks and starts up the child process.
1443 * It can be used for admin-specific tasks, such as notifying
1444 * someone that Squid is (re)started.
1447 mainStartScript(const char *prog
)
1449 char script
[SQUID_MAXPATHLEN
];
1454 xstrncpy(script
, prog
, MAXPATHLEN
);
1456 if ((t
= strrchr(script
, '/'))) {
1458 sl
= strlen(script
);
1461 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1463 if ((cpid
= fork()) == 0) {
1465 execl(script
, squid_start_script
, (char *)NULL
);
1471 rpid
= wait3(&status
, 0, NULL
);
1475 rpid
= waitpid(-1, &status
, 0);
1478 } while (rpid
!= cpid
);
1482 #endif /* _SQUID_MSWIN_ */
1485 checkRunningPid(void)
1492 pid
= readPidFile();
1497 if (kill(pid
, 0) < 0)
1500 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1506 watch_child(char *argv
[])
1508 #ifndef _SQUID_MSWIN_
1529 if (*(argv
[0]) == '(')
1532 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1534 if ((pid
= fork()) < 0)
1535 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1540 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1546 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1547 ioctl(i
, TIOCNOTTY
, NULL
);
1554 * RBCOLLINS - if cygwin stackdumps when squid is run without
1555 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1556 * 1.1.3. execvp had a bit overflow error in a loop..
1558 /* Connect stdio to /dev/null in daemon mode */
1559 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1562 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1566 if (Debug::log_stderr
< 0) {
1572 mainStartScript(argv
[0]);
1574 if ((pid
= fork()) == 0) {
1576 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1577 prog
= xstrdup(argv
[0]);
1578 argv
[0] = xstrdup("(squid)");
1580 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1584 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1586 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1590 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1594 pid
= wait3(&status
, 0, NULL
);
1598 pid
= waitpid(-1, &status
, 0);
1604 if (WIFEXITED(status
)) {
1606 "Squid Parent: child process %d exited with status %d",
1607 pid
, WEXITSTATUS(status
));
1608 } else if (WIFSIGNALED(status
)) {
1610 "Squid Parent: child process %d exited due to signal %d with status %d",
1611 pid
, WTERMSIG(status
), WEXITSTATUS(status
));
1613 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", pid
);
1616 if (stop
- start
< 10)
1621 if (failcount
== 5) {
1622 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1626 if (WIFEXITED(status
))
1627 if (WEXITSTATUS(status
) == 0)
1630 if (WIFSIGNALED(status
)) {
1631 switch (WTERMSIG(status
)) {
1639 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1648 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1653 #endif /* _SQUID_MSWIN_ */
1660 /* XXX: This function is called after the main loop has quit, which
1661 * means that no AsyncCalls would be called, including close handlers.
1662 * TODO: We need to close/shut/free everything that needs calls before
1666 #if USE_WIN32_SERVICE
1667 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1670 debugs(1, 1, "Shutting down...");
1680 externalAclShutdown();
1681 icpConnectionClose();
1688 snmpConnectionClose();
1692 wccpConnectionClose();
1696 wccp2ConnectionClose();
1699 releaseServerSockets();
1700 commCloseAllSockets();
1708 DelayPools::FreePools();
1711 authenticateShutdown();
1712 #if USE_WIN32_SERVICE
1714 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1717 Store::Root().sync(); /* Flush pending object writes/unlinks */
1720 unlinkdClose(); /* after sync/flush */
1723 storeDirWriteCleanLogs(0);
1726 Store::Root().sync(); /* Flush log writes */
1729 useragentLogClose();
1736 Store::Root().sync(); /* Flush log close */
1737 StoreFileSystem::FreeAllFs();
1738 DiskIOModule::FreeAllModules();
1739 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1743 /*stmemFreeMemory(); */
1745 ipcacheFreeMemory();
1746 fqdncacheFreeMemory();
1748 clientdbFreeMemory();
1749 httpHeaderCleanModule();
1757 if (opt_no_daemon
) {
1772 xmalloc_find_leaks();
1774 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1783 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1785 safeunlink(Config
.pidFilename
, 0);
1789 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1793 * We used to fclose(debug_log) here if it was set, but then
1794 * we forgot to set it to NULL. That caused some coredumps
1795 * because exit() ends up calling a bunch of destructors and
1796 * such. So rather than forcing the debug_log to close, we'll
1797 * leave it open so that those destructors can write some
1798 * debugging if necessary. The file will be closed anyway when
1799 * the process truly exits.
1802 exit(shutdown_status
);