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 "base/TextException.h"
42 #include "ConfigParser.h"
43 #include "errorpage.h"
45 #include "EventLoop.h"
46 #include "ExternalACL.h"
49 #include "ident/Ident.h"
50 #include "HttpReply.h"
56 #include "StoreFileSystem.h"
57 #include "DiskIO/DiskIOModule.h"
60 #include "comm_epoll.h"
63 #include "comm_kqueue.h"
66 #include "comm_poll.h"
68 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
69 #include "comm_select.h"
71 #include "SquidTime.h"
75 #include "icmp/IcmpSquid.h"
76 #include "icmp/net_db.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
&evtLoop
) : loop(evtLoop
) {}
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 master process, 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(); /* destroys any unused auth schemas */
697 InitAuthSchemes(); /* create new ones required for config parsing */
699 externalAclShutdown();
700 storeDirCloseSwapLogs();
709 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
714 mainReconfigureFinish(void *)
716 debugs(1, 3, "finishing reconfiguring");
719 enter_suid(); /* root to read config file */
721 // we may have disabled the need for PURGE
722 if (Config2
.onoff
.enable_purge
)
723 Config2
.onoff
.enable_purge
= 2;
725 // parse the config returns a count of errors encountered.
726 if ( parseConfigFile(ConfigFile
) != 0) {
727 // for now any errors are a fatal condition...
731 setUmask(Config
.umask
);
734 _db_init(Debug::cache_log
, Debug::debugOptions
);
735 ipcache_restart(); /* clear stuck entries */
736 authenticateUserCacheRestart(); /* clear stuck ACL entries */
737 fqdncache_restart(); /* sigh, fqdncache too */
739 errorInitialize(); /* reload error pages */
756 authenticateInit(&Auth::TheConfig
);
767 serverConnectionsOpen();
771 storeDirOpenSwapLogs();
773 mimeInit(Config
.mimeTablePathname
);
775 if (Config
.onoff
.announce
) {
776 if (!eventFind(start_announce
, NULL
))
777 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
779 if (eventFind(start_announce
, NULL
))
780 eventDelete(start_announce
, NULL
);
783 writePidFile(); /* write PID file */
785 debugs(1, 1, "Ready to serve requests.");
799 /* TODO: should only terminate the helpers they are using. nothing else. */
800 authenticateShutdown(); /* destroys any unused auth schemas */
801 InitAuthSchemes(); /* create new ones required for config parsing */
803 externalAclShutdown();
805 _db_rotate_log(); /* cache.log */
806 storeDirWriteCleanLogs(1);
807 storeLogRotate(); /* store.log */
808 accessLogRotate(); /* access.log */
809 useragentRotateLog(); /* useragent.log */
810 refererRotateLog(); /* referer.log */
812 icapLogRotate(); /*icap.log*/
823 authenticateInit(&Auth::TheConfig
);
828 setEffectiveUser(void)
831 leave_suid(); /* Run as non privilegied user */
837 if (geteuid() == 0) {
838 debugs(0, 0, "Squid is not safe to run as root! If you must");
839 debugs(0, 0, "start Squid as root, then you must configure");
840 debugs(0, 0, "it to run as a non-priveledged user with the");
841 debugs(0, 0, "'cache_effective_user' option in the config file.");
842 fatal("Don't run Squid as root, set 'cache_effective_user'!");
849 char pathbuf
[MAXPATHLEN
];
851 if (Config
.coredump_dir
) {
852 if (0 == strcmp("none", Config
.coredump_dir
)) {
854 } else if (chdir(Config
.coredump_dir
) == 0) {
855 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
858 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
862 /* If we don't have coredump_dir or couldn't cd there, report current dir */
863 if (getcwd(pathbuf
, MAXPATHLEN
)) {
864 debugs(0, 1, "Current Directory is " << pathbuf
);
866 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
871 #include "DelayPools.h"
877 /* chroot if configured to run inside chroot */
879 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
880 fatal("failed to chroot");
883 if (opt_catch_signals
) {
884 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
885 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
888 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
889 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
893 if (icpPortNumOverride
!= 1)
894 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
896 _db_init(Debug::cache_log
, Debug::debugOptions
);
898 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
902 log_trace_init("/tmp/squid.alloc");
906 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
910 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
911 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
912 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
914 debugs(1, 0, "Running on " << WIN32_OS_string
);
918 debugs(1, 1, "Process ID " << getpid());
920 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
924 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
926 if (WIN32_Socks_initialized
)
927 debugs(1, 1, "Windows sockets initialized");
929 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
930 WIN32_IpAddrChangeMonitorInit();
935 if (!configured_once
)
936 disk_init(); /* disk_init must go before ipcache_init() */
956 authenticateInit(&Auth::TheConfig
);
964 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
966 httpReplyInitModule(); /* must go before accepting replies */
987 malloc_debug(0, malloc_debug_level
);
991 if (!configured_once
) {
1000 /* after this point we want to see the mallinfo() output */
1002 mimeInit(Config
.mimeTablePathname
);
1009 FwdState::initModule();
1010 /* register the modules in the cache manager menus */
1012 cbdataRegisterWithCacheManager();
1013 /* These use separate calls so that the comm loops can eventually
1019 // TODO: pconn is a good candidate for new-style registration
1020 // PconnModule::GetInstance()->registerWithCacheManager();
1021 // moved to PconnModule::PconnModule()
1034 serverConnectionsOpen();
1038 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1040 if (Config
.chroot_dir
)
1043 if (!configured_once
)
1044 writePidFile(); /* write PID file */
1046 #ifdef _SQUID_LINUX_THREADS_
1048 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1050 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1054 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1056 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1060 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1062 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1064 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1068 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1074 #if USE_LOADABLE_MODULES
1075 LoadableModulesConfigure(Config
.loadable_module_names
);
1079 bool enableAdaptation
= false;
1081 // We can remove this dependency on specific adaptation mechanisms
1082 // if we create a generic Registry of such mechanisms. Should we?
1084 Adaptation::Icap::TheConfig
.finalize();
1085 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1088 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1089 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1091 // must be the last adaptation-related finalize
1092 Adaptation::Config::Finalize(enableAdaptation
);
1099 debugs(1, 1, "Ready to serve requests.");
1101 if (!configured_once
) {
1102 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1104 if (Config
.onoff
.announce
)
1105 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1107 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1109 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1113 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1117 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1120 configured_once
= 1;
1123 /// unsafe main routine -- may throw
1124 int SquidMain(int argc
, char **argv
);
1125 /// unsafe main routine wrapper to catch exceptions
1126 static int SquidMainSafe(int argc
, char **argv
);
1128 #if USE_WIN32_SERVICE
1129 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1130 extern "C" void WINAPI
1131 SquidWinSvcMain(int argc
, char **argv
)
1133 SquidMainSafe(argc
, argv
);
1137 main(int argc
, char **argv
)
1139 return SquidMainSafe(argc
, argv
);
1144 SquidMainSafe(int argc
, char **argv
)
1147 return SquidMain(argc
, argv
);
1148 } catch (const std::exception
&e
) {
1149 std::cerr
<< "dying from an unhandled exception: " << e
.what() << std::endl
;
1152 std::cerr
<< "dying from an unhandled exception." << std::endl
;
1155 return -1; // not reached
1159 SquidMain(int argc
, char **argv
)
1161 #ifdef _SQUID_WIN32_
1168 sbrk_start
= sbrk(0);
1171 Debug::parseOptions(NULL
);
1174 #if defined(SQUID_MAXFD_LIMIT)
1176 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1177 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1181 #ifdef _SQUID_WIN32_
1183 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1184 return WIN32_init_err
;
1188 /* call mallopt() before anything else */
1191 /* Round up all sizes to a multiple of this */
1192 mallopt(M_GRAIN
, 16);
1196 /* biggest size that is considered a small block */
1197 mallopt(M_MXFAST
, 256);
1201 /* allocate this many small blocks at once */
1202 mallopt(M_NLBLKS
, 32);
1205 #endif /* HAVE_MALLOPT */
1207 squid_srandom(time(NULL
));
1211 squid_start
= current_time
;
1213 failure_notify
= fatal_dump
;
1215 #if USE_WIN32_SERVICE
1217 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1221 mainParseOptions(argc
, argv
);
1223 if (opt_parse_cfg_only
) {
1224 Debug::parseOptions("ALL,1");
1227 #if USE_WIN32_SERVICE
1229 if (opt_install_service
) {
1230 WIN32_InstallService();
1234 if (opt_remove_service
) {
1235 WIN32_RemoveService();
1239 if (opt_command_line
) {
1240 WIN32_SetServiceCommandLine();
1246 /* parse configuration file
1247 * note: in "normal" case this used to be called from mainInitialize() */
1252 ConfigFile
= xstrdup(DefaultConfigFile
);
1254 assert(!configured_once
);
1258 storeFsInit(); /* required for config parsing */
1260 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1263 /* May not be needed for parsing, have not audited for such */
1264 DiskIOModule::SetupAllModules();
1266 /* Shouldn't be needed for config parsing, but have not audited for such */
1267 StoreFileSystem::SetupAllFs();
1269 /* we may want the parsing process to set this up in the future */
1270 Store::Root(new StoreController
);
1272 InitAuthSchemes(); /* required for config parsing */
1274 parse_err
= parseConfigFile(ConfigFile
);
1278 if (opt_parse_cfg_only
|| parse_err
> 0)
1281 setUmask(Config
.umask
);
1282 if (-1 == opt_send_signal
)
1283 if (checkRunningPid())
1300 /* send signal to running copy and exit */
1301 if (opt_send_signal
!= -1) {
1302 /* chroot if configured to run inside chroot */
1304 if (Config
.chroot_dir
) {
1305 if (chroot(Config
.chroot_dir
))
1306 fatal("failed to chroot");
1317 if (opt_create_swap_dirs
) {
1318 /* chroot if configured to run inside chroot */
1320 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1321 fatal("failed to chroot");
1325 debugs(0, 0, "Creating Swap Directories");
1326 Store::Root().create();
1336 /* init comm module */
1341 if (opt_no_daemon
) {
1342 /* we have to init fdstat here. */
1343 fd_open(0, FD_LOG
, "stdin");
1344 fd_open(1, FD_LOG
, "stdout");
1345 fd_open(2, FD_LOG
, "stderr");
1348 #if USE_WIN32_SERVICE
1350 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1356 #if USE_WIN32_SERVICE
1358 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1365 SignalEngine
signalEngine(mainLoop
);
1367 mainLoop
.registerEngine(&signalEngine
);
1369 /* TODO: stop requiring the singleton here */
1370 mainLoop
.registerEngine(EventScheduler::GetInstance());
1372 StoreRootEngine store_engine
;
1374 mainLoop
.registerEngine(&store_engine
);
1376 CommSelectEngine comm_engine
;
1378 mainLoop
.registerEngine(&comm_engine
);
1380 mainLoop
.setPrimaryEngine(&comm_engine
);
1382 /* use the standard time service */
1383 TimeEngine time_engine
;
1385 mainLoop
.setTimeService(&time_engine
);
1387 /* at this point we are finished the synchronous startup. */
1392 if (mainLoop
.errcount
== 10)
1393 fatal_dump("Event loop exited with failure.");
1395 /* shutdown squid now */
1408 if (strcmp(Config
.pidFilename
, "none") == 0) {
1409 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1412 pid
= readPidFile();
1415 #if USE_WIN32_SERVICE
1417 if (opt_signal_service
) {
1418 WIN32_sendSignal(opt_send_signal
);
1421 #ifdef _SQUID_MSWIN_
1423 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1424 fprintf(stderr
, "signal to Squid Service:\n");
1425 fprintf(stderr
, "missing -n command line switch.\n");
1434 if (kill(pid
, opt_send_signal
) &&
1435 /* ignore permissions if just running check */
1436 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1437 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1438 fprintf(stderr
, "signal %d to process %d: %s\n",
1439 opt_send_signal
, (int) pid
, xstrerror());
1443 if (opt_send_signal
!= SIGTERM
) {
1444 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1447 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1452 /* signal successfully sent */
1456 #ifndef _SQUID_MSWIN_
1458 * This function is run when Squid is in daemon mode, just
1459 * before the parent forks and starts up the child process.
1460 * It can be used for admin-specific tasks, such as notifying
1461 * someone that Squid is (re)started.
1464 mainStartScript(const char *prog
)
1466 char script
[MAXPATHLEN
];
1471 xstrncpy(script
, prog
, MAXPATHLEN
);
1473 if ((t
= strrchr(script
, '/'))) {
1475 sl
= strlen(script
);
1478 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1480 if ((cpid
= fork()) == 0) {
1482 execl(script
, squid_start_script
, (char *)NULL
);
1488 rpid
= wait3(&status
, 0, NULL
);
1492 rpid
= waitpid(-1, &status
, 0);
1495 } while (rpid
!= cpid
);
1499 #endif /* _SQUID_MSWIN_ */
1502 checkRunningPid(void)
1509 pid
= readPidFile();
1514 if (kill(pid
, 0) < 0)
1517 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1523 watch_child(char *argv
[])
1525 #ifndef _SQUID_MSWIN_
1546 if (*(argv
[0]) == '(')
1549 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1551 if ((pid
= fork()) < 0)
1552 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1557 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1563 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1564 ioctl(i
, TIOCNOTTY
, NULL
);
1571 * RBCOLLINS - if cygwin stackdumps when squid is run without
1572 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1573 * 1.1.3. execvp had a bit overflow error in a loop..
1575 /* Connect stdio to /dev/null in daemon mode */
1576 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1579 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1583 if (Debug::log_stderr
< 0) {
1589 mainStartScript(argv
[0]);
1591 if ((pid
= fork()) == 0) {
1593 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1594 prog
= xstrdup(argv
[0]);
1595 argv
[0] = xstrdup("(squid)");
1597 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1601 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1603 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1607 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1611 pid
= wait3(&status
, 0, NULL
);
1615 pid
= waitpid(-1, &status
, 0);
1621 if (WIFEXITED(status
)) {
1623 "Squid Parent: child process %d exited with status %d",
1624 pid
, WEXITSTATUS(status
));
1625 } else if (WIFSIGNALED(status
)) {
1627 "Squid Parent: child process %d exited due to signal %d with status %d",
1628 pid
, WTERMSIG(status
), WEXITSTATUS(status
));
1630 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", pid
);
1633 if (stop
- start
< 10)
1638 if (failcount
== 5) {
1639 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1643 if (WIFEXITED(status
))
1644 if (WEXITSTATUS(status
) == 0)
1647 if (WIFSIGNALED(status
)) {
1648 switch (WTERMSIG(status
)) {
1656 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1665 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1670 #endif /* _SQUID_MSWIN_ */
1677 /* XXX: This function is called after the main loop has quit, which
1678 * means that no AsyncCalls would be called, including close handlers.
1679 * TODO: We need to close/shut/free everything that needs calls before
1683 #if USE_WIN32_SERVICE
1684 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1687 debugs(1, 1, "Shutting down...");
1697 externalAclShutdown();
1698 icpConnectionClose();
1705 snmpConnectionClose();
1709 wccpConnectionClose();
1713 wccp2ConnectionClose();
1716 releaseServerSockets();
1717 commCloseAllSockets();
1725 DelayPools::FreePools();
1728 authenticateShutdown();
1729 #if USE_WIN32_SERVICE
1731 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1734 Store::Root().sync(); /* Flush pending object writes/unlinks */
1737 unlinkdClose(); /* after sync/flush */
1740 storeDirWriteCleanLogs(0);
1743 Store::Root().sync(); /* Flush log writes */
1746 useragentLogClose();
1753 Store::Root().sync(); /* Flush log close */
1754 StoreFileSystem::FreeAllFs();
1755 DiskIOModule::FreeAllModules();
1756 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1760 /*stmemFreeMemory(); */
1762 ipcacheFreeMemory();
1763 fqdncacheFreeMemory();
1765 clientdbFreeMemory();
1766 httpHeaderCleanModule();
1774 if (opt_no_daemon
) {
1789 xmalloc_find_leaks();
1791 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1800 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1802 safeunlink(Config
.pidFilename
, 0);
1806 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1810 * We used to fclose(debug_log) here if it was set, but then
1811 * we forgot to set it to NULL. That caused some coredumps
1812 * because exit() ends up calling a bunch of destructors and
1813 * such. So rather than forcing the debug_log to close, we'll
1814 * leave it open so that those destructors can write some
1815 * debugging if necessary. The file will be closed anyway when
1816 * the process truly exits.
1819 exit(shutdown_status
);