3 * $Id: main.cc,v 1.452 2007/12/14 23:11:47 amosjeffries Exp $
5 * DEBUG: section 1 Startup and Main Loop
6 * AUTHOR: Harvest Derived
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 #include "AccessLogEntry.h"
38 #include "authenticate.h"
39 #include "CacheManager.h"
40 #include "ConfigParser.h"
41 #include "errorpage.h"
43 #include "EventLoop.h"
44 #include "ExternalACL.h"
47 #include "HttpReply.h"
53 #include "StoreFileSystem.h"
54 #include "DiskIO/DiskIOModule.h"
57 #include "comm_epoll.h"
60 #include "comm_kqueue.h"
63 #include "comm_poll.h"
66 #include "comm_select.h"
69 #include "comm_select.h"
71 #include "SquidTime.h"
75 #include "ICMPSquid.h"
79 #include "squid_windows.h"
82 static int opt_install_service
= FALSE
;
83 static int opt_remove_service
= FALSE
;
84 static int opt_signal_service
= FALSE
;
85 static int opt_command_line
= FALSE
;
86 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
87 void WINAPI
WIN32_svcHandler(DWORD
);
91 /* for error reporting from xmalloc and friends */
92 SQUIDCEXTERN
void (*failure_notify
) (const char *);
94 static int opt_parse_cfg_only
= 0;
95 static char *opt_syslog_facility
= NULL
;
96 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
97 static int configured_once
= 0;
99 static int malloc_debug_level
= 0;
101 static volatile int do_reconfigure
= 0;
102 static volatile int do_rotate
= 0;
103 static volatile int do_shutdown
= 0;
104 static volatile int shutdown_status
= 0;
106 static void mainRotate(void);
107 static void mainReconfigure(void);
108 static void mainInitialize(void);
109 static void usage(void);
110 static void mainParseOptions(int, char **);
111 static void sendSignal(void);
112 static void serverConnectionsOpen(void);
113 static void watch_child(char **);
114 static void setEffectiveUser(void);
116 extern void log_trace_done();
117 extern void log_trace_init(char *);
119 static void SquidShutdown(void);
120 static void mainSetCwd(void);
121 static int checkRunningPid(void);
123 static CacheManager manager
;
125 #ifndef _SQUID_MSWIN_
126 static const char *squid_start_script
= "squid_start";
130 #include "test_access.c"
133 /* temporary thunk across to the unrefactored store interface */
135 class StoreRootEngine
: public AsyncEngine
139 int checkEvents(int timeout
)
141 Store::Root().callback();
146 class SignalDispatcher
: public CompletionDispatcher
150 SignalDispatcher(EventLoop
&loop
) : loop(loop
), events_dispatched(false) {}
152 void addEventLoop(EventLoop
* loop
);
153 virtual bool dispatch();
156 static void StopEventLoop(void * data
)
158 static_cast<SignalDispatcher
*>(data
)->loop
.stop();
162 bool events_dispatched
;
166 SignalDispatcher::dispatch()
168 PROF_start(SignalDispatcher_dispatch
);
170 if (do_reconfigure
) {
173 } else if (do_rotate
) {
176 } else if (do_shutdown
) {
177 time_t wait
= do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0;
178 debugs(1, 1, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
179 debugs(1, 1, "Waiting " << wait
<< " seconds for active connections to finish");
182 #if USE_WIN32_SERVICE
184 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
187 serverConnectionsClose();
188 eventAdd("SquidShutdown", StopEventLoop
, this, (double) (wait
+ 1), 1, false);
191 bool result
= events_dispatched
;
192 events_dispatched
= false;
193 PROF_stop(SignalDispatcher_dispatch
);
201 #if USE_WIN32_SERVICE
202 "Usage: %s [-cdhirvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
204 "Usage: %s [-cdhvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
206 " -a port Specify HTTP port number (default: %d).\n"
207 " -d level Write debugging to stderr also.\n"
208 " -f file Use given config-file instead of\n"
210 " -h Print help message.\n"
211 #if USE_WIN32_SERVICE
212 " -i Installs as a Windows Service (see -n option).\n"
214 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
215 " Parse configuration file, then send signal to \n"
216 " running copy (except -k parse) and exit.\n"
217 #if USE_WIN32_SERVICE
218 " -n name Specify Windows Service name to use for service operations\n"
219 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
220 " -r Removes a Windows Service (see -n option).\n"
222 " -s | -l facility\n"
223 " Enable logging to syslog.\n"
224 " -u port Specify ICP port number (default: %d), disable with 0.\n"
225 " -v Print version.\n"
226 " -z Create swap directories\n"
227 " -C Do not catch fatal signals.\n"
228 " -D Disable initial DNS tests.\n"
229 " -F Don't serve any requests until store is rebuilt.\n"
230 " -N No daemon mode.\n"
231 #if USE_WIN32_SERVICE
233 " Set Windows Service Command line options in Registry.\n"
235 " -R Do not set REUSEADDR on port.\n"
236 " -S Double-check swap during rebuild.\n"
237 " -V Virtual host httpd-accelerator.\n"
238 " -X Force full debugging.\n"
239 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
240 appname
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
245 mainParseOptions(int argc
, char *argv
[])
250 #if USE_WIN32_SERVICE
252 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
255 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
264 opt_catch_signals
= 0;
272 opt_foreground_rebuild
= 1;
278 #if USE_WIN32_SERVICE
281 opt_command_line
= 1;
282 WIN32_Command_Line
= xstrdup(optarg
);
291 opt_store_doublecheck
= 1;
295 /* force full debugging */
296 Debug::parseOptions("debug_options ALL,9");
297 Config
.onoff
.debug_override_X
= 1;
298 sigusr2_handle(SIGUSR2
);
302 opt_reload_hit_only
= 1;
306 #if USE_WIN32_SERVICE
309 opt_install_service
= TRUE
;
316 add_http_port(optarg
);
321 opt_debug_stderr
= atoi(optarg
);
328 ConfigFile
= xstrdup(optarg
);
339 if ((int) strlen(optarg
) < 1)
342 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
343 opt_send_signal
= SIGHUP
;
344 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
345 #ifdef _SQUID_LINUX_THREADS_
347 opt_send_signal
= SIGQUIT
;
351 opt_send_signal
= SIGUSR1
;
355 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
356 #ifdef _SQUID_LINUX_THREADS_
358 opt_send_signal
= SIGTRAP
;
362 opt_send_signal
= SIGUSR2
;
366 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
367 opt_send_signal
= SIGTERM
;
368 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
369 opt_send_signal
= SIGINT
;
370 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
371 opt_send_signal
= SIGKILL
;
375 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
376 opt_send_signal
= SIGTTIN
; /* exit and restart by parent */
380 else if (!strncmp(optarg
, "check", strlen(optarg
)))
381 opt_send_signal
= 0; /* SIGNULL */
382 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
383 opt_parse_cfg_only
= 1; /* parse cfg file only */
392 malloc_debug_level
= atoi(optarg
);
395 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
400 xmalloc_trace
= !xmalloc_trace
;
403 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
411 #if USE_WIN32_SERVICE
414 xfree(WIN32_Service_name
);
416 WIN32_Service_name
= xstrdup(optarg
);
418 opt_signal_service
= TRUE
;
423 opt_remove_service
= TRUE
;
430 opt_syslog_facility
= xstrdup(optarg
);
435 _db_set_syslog(opt_syslog_facility
);
441 fatal("Logging to syslog not available on this platform");
447 icpPortNumOverride
= atoi(optarg
);
449 if (icpPortNumOverride
< 0)
450 icpPortNumOverride
= 0;
455 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string
, SQUID_CONFIGURE_OPTIONS
);
457 #if USE_WIN32_SERVICE
459 printf("Compiled as Windows System Service.\n");
468 opt_debug_stderr
= 1;
470 opt_create_swap_dirs
= 1;
490 #ifndef _SQUID_MSWIN_
493 signal(sig
, rotate_logs
);
503 #ifndef _SQUID_MSWIN_
506 signal(sig
, reconfigure
);
514 do_shutdown
= sig
== SIGINT
? -1 : 1;
521 #ifndef _SQUID_MSWIN_
522 #ifdef KILL_PARENT_OPT
525 debugs(1, 1, "Killing RunCache, pid " << getppid());
527 if (kill(getppid(), sig
) < 0)
528 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
532 #if SA_RESETHAND == 0
533 signal(SIGTERM
, SIG_DFL
);
535 signal(SIGINT
, SIG_DFL
);
542 serverConnectionsOpen(void)
544 clientOpenListenSockets();
545 icpConnectionsOpen();
552 snmpConnectionOpen();
556 wccpConnectionOpen();
561 wccp2ConnectionOpen();
577 serverConnectionsClose(void)
579 assert(shutting_down
|| reconfiguring
);
580 clientHttpConnectionsClose();
581 icpConnectionShutdown();
584 htcpSocketShutdown();
590 snmpConnectionShutdown();
594 wccpConnectionClose();
598 wccp2ConnectionClose();
605 mainReconfigure(void)
607 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
609 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
610 serverConnectionsClose();
611 icpConnectionClose();
618 snmpConnectionClose();
629 authenticateShutdown();
630 externalAclShutdown();
631 storeDirCloseSwapLogs();
637 enter_suid(); /* root to read config file */
638 parseConfigFile(ConfigFile
, manager
);
640 _db_init(Config
.Log
.log
, Config
.debugOptions
);
641 ipcache_restart(); /* clear stuck entries */
642 authenticateUserCacheRestart(); /* clear stuck ACL entries */
643 fqdncache_restart(); /* sigh, fqdncache too */
645 errorInitialize(); /* reload error pages */
659 authenticateInit(&Config
.authConfiguration
);
670 serverConnectionsOpen();
673 neighborsRegisterWithCacheManager(manager
);
675 storeDirOpenSwapLogs();
677 mimeInit(Config
.mimeTablePathname
);
679 if (Config
.onoff
.announce
) {
680 if (!eventFind(start_announce
, NULL
))
681 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
683 if (eventFind(start_announce
, NULL
))
684 eventDelete(start_announce
, NULL
);
687 writePidFile(); /* write PID file */
689 debugs(1, 1, "Ready to serve requests.");
704 authenticateShutdown();
705 externalAclShutdown();
706 _db_rotate_log(); /* cache.log */
707 storeDirWriteCleanLogs(1);
708 storeLogRotate(); /* store.log */
709 accessLogRotate(); /* access.log */
710 useragentRotateLog(); /* useragent.log */
711 refererRotateLog(); /* referer.log */
724 authenticateInit(&Config
.authConfiguration
);
729 setEffectiveUser(void)
732 leave_suid(); /* Run as non privilegied user */
738 if (geteuid() == 0) {
739 debugs(0, 0, "Squid is not safe to run as root! If you must");
740 debugs(0, 0, "start Squid as root, then you must configure");
741 debugs(0, 0, "it to run as a non-priveledged user with the");
742 debugs(0, 0, "'cache_effective_user' option in the config file.");
743 fatal("Don't run Squid as root, set 'cache_effective_user'!");
750 char pathbuf
[MAXPATHLEN
];
752 if (Config
.coredump_dir
) {
753 if (0 == strcmp("none", Config
.coredump_dir
)) {
755 } else if (chdir(Config
.coredump_dir
) == 0) {
756 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
759 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
763 /* If we don't have coredump_dir or couldn't cd there, report current dir */
764 if (getcwd(pathbuf
, MAXPATHLEN
)) {
765 debugs(0, 1, "Current Directory is " << pathbuf
);
767 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
772 #include "DelayPools.h"
778 /* chroot if configured to run inside chroot */
780 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
781 fatal("failed to chroot");
784 if (opt_catch_signals
) {
785 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
786 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
789 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
790 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
794 if (icpPortNumOverride
!= 1)
795 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
797 _db_init(Config
.Log
.log
, Config
.debugOptions
);
799 fd_open(fileno(debug_log
), FD_LOG
, Config
.Log
.log
);
803 log_trace_init("/tmp/squid.alloc");
807 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
811 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
812 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
813 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
815 debugs(1, 0, "Running on " << WIN32_OS_string
);
819 debugs(1, 1, "Process ID " << getpid());
821 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
825 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
827 if (WIN32_Socks_initialized
)
828 debugs(1, 1, "Windows sockets initialized");
832 if (!configured_once
)
833 disk_init(); /* disk_init must go before ipcache_init() */
853 authenticateInit(&Config
.authConfiguration
);
861 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
863 httpReplyInitModule(); /* must go before accepting replies */
881 malloc_debug(0, malloc_debug_level
);
885 if (!configured_once
) {
894 /* after this point we want to see the mallinfo() output */
896 mimeInit(Config
.mimeTablePathname
);
903 FwdState::initModule();
904 /* register the modules in the cache manager menus */
905 accessLogRegisterWithCacheManager(manager
);
906 asnRegisterWithCacheManager(manager
);
907 authenticateRegisterWithCacheManager(&Config
.authConfiguration
, manager
);
910 carpRegisterWithCacheManager(manager
);
913 cbdataRegisterWithCacheManager(manager
);
914 /* These use separate calls so that the comm loops can eventually
919 commEPollRegisterWithCacheManager(manager
);
923 commKQueueRegisterWithCacheManager(manager
);
927 commPollRegisterWithCacheManager(manager
);
931 commSelectRegisterWithCacheManager(manager
);
934 clientdbRegisterWithCacheManager(manager
);
937 DelayPools::RegisterWithCacheManager(manager
);
940 DiskIOModule::RegisterAllModulesWithCacheManager(manager
);
943 dnsRegisterWithCacheManager(manager
);
947 externalAclRegisterWithCacheManager(manager
);
948 fqdncacheRegisterWithCacheManager(manager
);
949 FwdState::RegisterWithCacheManager(manager
);
950 httpHeaderRegisterWithCacheManager(manager
);
953 idnsRegisterWithCacheManager(manager
);
956 ipcacheRegisterWithCacheManager(manager
);
957 Mem::RegisterWithCacheManager(manager
);
958 netdbRegisterWitHCacheManager(manager
);
959 PconnModule::GetInstance()->registerWithCacheManager(manager
);
960 redirectRegisterWithCacheManager(manager
);
961 refreshRegisterWithCacheManager(manager
);
962 statRegisterWithCacheManager(manager
);
963 storeDigestRegisterWithCacheManager(manager
);
964 StoreFileSystem::RegisterAllFsWithCacheManager(manager
);
965 storeRegisterWithCacheManager(manager
);
966 storeLogRegisterWithCacheManager(manager
);
969 StringRegistry::Instance().registerWithCacheManager(manager
);
974 xprofRegisterWithCacheManager(manager
);
989 serverConnectionsOpen();
993 neighborsRegisterWithCacheManager(manager
);
995 if (Config
.chroot_dir
)
998 if (!configured_once
)
999 writePidFile(); /* write PID file */
1001 #ifdef _SQUID_LINUX_THREADS_
1003 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1005 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1009 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1011 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1015 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1017 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1019 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1023 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1029 debugs(1, 1, "Ready to serve requests.");
1031 if (!configured_once
) {
1032 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1034 if (Config
.onoff
.announce
)
1035 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1037 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1039 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1043 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1047 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1049 eventAdd("commCheckHalfClosed", commCheckHalfClosed
, NULL
, 1.0, false);
1052 configured_once
= 1;
1055 #if USE_WIN32_SERVICE
1056 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1057 extern "C" void WINAPI
1058 SquidWinSvcMain(int argc
, char **argv
)
1060 SquidMain(argc
, argv
);
1064 SquidMain(int argc
, char **argv
)
1067 main(int argc
, char **argv
)
1071 #ifdef _SQUID_WIN32_
1078 sbrk_start
= sbrk(0);
1081 Debug::parseOptions("ALL,1");
1084 #if defined(SQUID_MAXFD_LIMIT)
1086 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1087 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1091 #ifdef _SQUID_WIN32_
1093 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1094 return WIN32_init_err
;
1098 /* call mallopt() before anything else */
1101 /* Round up all sizes to a multiple of this */
1102 mallopt(M_GRAIN
, 16);
1106 /* biggest size that is considered a small block */
1107 mallopt(M_MXFAST
, 256);
1111 /* allocate this many small blocks at once */
1112 mallopt(M_NLBLKS
, 32);
1115 #endif /* HAVE_MALLOPT */
1118 * The plan here is to set the umask to 007 (deny others for
1119 * read,write,execute), but only if the umask is not already
1120 * set. Unfortunately, there is no way to get the current
1121 * umask value without setting it.
1123 oldmask
= umask(S_IRWXO
);
1128 squid_srandom(time(NULL
));
1132 squid_start
= current_time
;
1134 failure_notify
= fatal_dump
;
1136 #if USE_WIN32_SERVICE
1138 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1142 mainParseOptions(argc
, argv
);
1144 #if USE_WIN32_SERVICE
1146 if (opt_install_service
)
1148 WIN32_InstallService();
1152 if (opt_remove_service
)
1154 WIN32_RemoveService();
1158 if (opt_command_line
)
1160 WIN32_SetServiceCommandLine();
1166 /* parse configuration file
1167 * note: in "normal" case this used to be called from mainInitialize() */
1172 ConfigFile
= xstrdup(DefaultConfigFile
);
1174 assert(!configured_once
);
1178 storeFsInit(); /* required for config parsing */
1180 /* May not be needed for parsing, have not audited for such */
1181 DiskIOModule::SetupAllModules();
1183 /* Shouldn't be needed for config parsing, but have not audited for such */
1184 StoreFileSystem::SetupAllFs();
1186 /* we may want the parsing process to set this up in the future */
1187 Store::Root(new StoreController
);
1189 parse_err
= parseConfigFile(ConfigFile
, manager
);
1191 if (opt_parse_cfg_only
)
1195 if (-1 == opt_send_signal
)
1196 if (checkRunningPid())
1213 /* send signal to running copy and exit */
1214 if (opt_send_signal
!= -1)
1216 /* chroot if configured to run inside chroot */
1218 if (Config
.chroot_dir
) {
1219 if (chroot(Config
.chroot_dir
))
1220 fatal("failed to chroot");
1231 if (opt_create_swap_dirs
)
1233 /* chroot if configured to run inside chroot */
1235 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1236 fatal("failed to chroot");
1240 debugs(0, 0, "Creating Swap Directories");
1241 Store::Root().create();
1251 /* init comm module */
1258 /* we have to init fdstat here. */
1259 fd_open(0, FD_LOG
, "stdin");
1260 fd_open(1, FD_LOG
, "stdout");
1261 fd_open(2, FD_LOG
, "stderr");
1264 #if USE_WIN32_SERVICE
1266 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1272 #if USE_WIN32_SERVICE
1274 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1281 SignalDispatcher
signal_dispatcher(mainLoop
);
1283 mainLoop
.registerDispatcher(&signal_dispatcher
);
1285 /* TODO: stop requiring the singleton here */
1286 mainLoop
.registerDispatcher(EventDispatcher::GetInstance());
1288 /* TODO: stop requiring the singleton here */
1289 mainLoop
.registerEngine(EventScheduler::GetInstance());
1291 StoreRootEngine store_engine
;
1293 mainLoop
.registerEngine(&store_engine
);
1295 CommDispatcher comm_dispatcher
;
1297 mainLoop
.registerDispatcher(&comm_dispatcher
);
1299 CommSelectEngine comm_engine
;
1301 mainLoop
.registerEngine(&comm_engine
);
1303 mainLoop
.setPrimaryEngine(&comm_engine
);
1305 /* use the standard time service */
1306 TimeEngine time_engine
;
1308 mainLoop
.setTimeService(&time_engine
);
1312 if (mainLoop
.errcount
== 10)
1313 fatal_dump("Event loop exited with failure.");
1315 /* shutdown squid now */
1328 if (strcmp(Config
.pidFilename
, "none") == 0) {
1329 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1332 pid
= readPidFile();
1335 #if USE_WIN32_SERVICE
1337 if (opt_signal_service
) {
1338 WIN32_sendSignal(opt_send_signal
);
1341 #ifdef _SQUID_MSWIN_
1343 fprintf(stderr
, "%s: ERROR: Could not send ", appname
);
1344 fprintf(stderr
, "signal to Squid Service:\n");
1345 fprintf(stderr
, "missing -n command line switch.\n");
1354 if (kill(pid
, opt_send_signal
) &&
1355 /* ignore permissions if just running check */
1356 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1357 fprintf(stderr
, "%s: ERROR: Could not send ", appname
);
1358 fprintf(stderr
, "signal %d to process %d: %s\n",
1359 opt_send_signal
, (int) pid
, xstrerror());
1363 fprintf(stderr
, "%s: ERROR: No running copy\n", appname
);
1367 /* signal successfully sent */
1371 #ifndef _SQUID_MSWIN_
1373 * This function is run when Squid is in daemon mode, just
1374 * before the parent forks and starts up the child process.
1375 * It can be used for admin-specific tasks, such as notifying
1376 * someone that Squid is (re)started.
1379 mainStartScript(const char *prog
)
1381 char script
[SQUID_MAXPATHLEN
];
1386 xstrncpy(script
, prog
, MAXPATHLEN
);
1388 if ((t
= strrchr(script
, '/'))) {
1390 sl
= strlen(script
);
1393 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1395 if ((cpid
= fork()) == 0) {
1397 execl(script
, squid_start_script
, (char *)NULL
);
1403 rpid
= wait3(&status
, 0, NULL
);
1407 rpid
= waitpid(-1, &status
, 0);
1410 } while (rpid
!= cpid
);
1414 #endif /* _SQUID_MSWIN_ */
1417 checkRunningPid(void)
1424 pid
= readPidFile();
1429 if (kill(pid
, 0) < 0)
1432 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1438 watch_child(char *argv
[])
1440 #ifndef _SQUID_MSWIN_
1461 if (*(argv
[0]) == '(')
1464 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1466 if ((pid
= fork()) < 0)
1467 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1472 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1478 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1479 ioctl(i
, TIOCNOTTY
, NULL
);
1486 * RBCOLLINS - if cygwin stackdumps when squid is run without
1487 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1488 * 1.1.3. execvp had a bit overflow error in a loop..
1490 /* Connect stdio to /dev/null in daemon mode */
1491 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1494 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1498 if (opt_debug_stderr
< 0) {
1504 mainStartScript(argv
[0]);
1506 if ((pid
= fork()) == 0) {
1508 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1509 prog
= xstrdup(argv
[0]);
1510 argv
[0] = xstrdup("(squid)");
1512 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1516 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1518 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1522 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1526 pid
= wait3(&status
, 0, NULL
);
1530 pid
= waitpid(-1, &status
, 0);
1536 if (WIFEXITED(status
)) {
1538 "Squid Parent: child process %d exited with status %d",
1539 pid
, WEXITSTATUS(status
));
1540 } else if (WIFSIGNALED(status
)) {
1542 "Squid Parent: child process %d exited due to signal %d with status %d",
1543 pid
, WTERMSIG(status
), WEXITSTATUS(status
));
1545 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", pid
);
1548 if (stop
- start
< 10)
1553 if (failcount
== 5) {
1554 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1558 if (WIFEXITED(status
))
1559 if (WEXITSTATUS(status
) == 0)
1562 if (WIFSIGNALED(status
)) {
1563 switch (WTERMSIG(status
)) {
1571 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1580 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1585 #endif /* _SQUID_MSWIN_ */
1592 #if USE_WIN32_SERVICE
1593 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1596 debugs(1, 1, "Shutting down...");
1606 externalAclShutdown();
1607 icpConnectionClose();
1614 snmpConnectionClose();
1618 wccpConnectionClose();
1622 wccp2ConnectionClose();
1625 releaseServerSockets();
1626 commCloseAllSockets();
1629 DelayPools::FreePools();
1632 authenticateShutdown();
1633 #if USE_WIN32_SERVICE
1635 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1638 Store::Root().sync(); /* Flush pending object writes/unlinks */
1641 unlinkdClose(); /* after sync/flush */
1644 storeDirWriteCleanLogs(0);
1647 Store::Root().sync(); /* Flush log writes */
1650 useragentLogClose();
1657 Store::Root().sync(); /* Flush log close */
1658 StoreFileSystem::FreeAllFs();
1659 DiskIOModule::FreeAllModules();
1660 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1664 /*stmemFreeMemory(); */
1666 ipcacheFreeMemory();
1667 fqdncacheFreeMemory();
1669 clientdbFreeMemory();
1670 httpHeaderCleanModule();
1678 if (opt_no_daemon
) {
1693 xmalloc_find_leaks();
1695 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1704 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1706 safeunlink(Config
.pidFilename
, 0);
1710 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1714 * We used to fclose(debug_log) here if it was set, but then
1715 * we forgot to set it to NULL. That caused some coredumps
1716 * because exit() ends up calling a bunch of destructors and
1717 * such. So rather than forcing the debug_log to close, we'll
1718 * leave it open so that those destructors can write some
1719 * debugging if necessary. The file will be closed anyway when
1720 * the process truly exits.
1723 exit(shutdown_status
);