3 * $Id: main.cc,v 1.431 2006/08/20 09:50:05 serassio 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"
42 #include "EventLoop.h"
43 #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"
65 #include "comm_select.h"
68 #include "comm_select.h"
70 #include "SquidTime.h"
77 #include "squid_windows.h"
80 static int opt_install_service
= FALSE
;
81 static int opt_remove_service
= FALSE
;
82 static int opt_signal_service
= FALSE
;
83 static int opt_command_line
= FALSE
;
84 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
85 void WINAPI
WIN32_svcHandler(DWORD
);
89 /* for error reporting from xmalloc and friends */
90 SQUIDCEXTERN
void (*failure_notify
) (const char *);
92 static int opt_parse_cfg_only
= 0;
93 static char *opt_syslog_facility
= NULL
;
94 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
95 static int configured_once
= 0;
97 static int malloc_debug_level
= 0;
99 static volatile int do_reconfigure
= 0;
100 static volatile int do_rotate
= 0;
101 static volatile int do_shutdown
= 0;
102 static volatile int shutdown_status
= 0;
104 static void mainRotate(void);
105 static void mainReconfigure(void);
106 static void mainInitialize(void);
107 static void usage(void);
108 static void mainParseOptions(int, char **);
109 static void sendSignal(void);
110 static void serverConnectionsOpen(void);
111 static void watch_child(char **);
112 static void setEffectiveUser(void);
114 extern void log_trace_done();
115 extern void log_trace_init(char *);
117 static void SquidShutdown(void);
118 static void mainSetCwd(void);
119 static int checkRunningPid(void);
121 static CacheManager manager
;
123 #ifndef _SQUID_MSWIN_
124 static const char *squid_start_script
= "squid_start";
128 #include "test_access.c"
131 /* temporary thunk across to the unrefactored store interface */
133 class StoreRootEngine
: public AsyncEngine
137 int checkEvents(int timeout
)
139 Store::Root().callback();
144 class SignalDispatcher
: public CompletionDispatcher
148 SignalDispatcher(EventLoop
&loop
) : loop(loop
), events_dispatched(false) {}
150 void addEventLoop(EventLoop
* loop
);
151 virtual bool dispatch();
154 static void StopEventLoop(void * data
)
156 static_cast<SignalDispatcher
*>(data
)->loop
.stop();
160 bool events_dispatched
;
164 SignalDispatcher::dispatch()
166 if (do_reconfigure
) {
169 #if defined(_SQUID_MSWIN_) && defined(_DEBUG)
171 } else if (do_debug_trap
) {
176 } else if (do_rotate
) {
179 } else if (do_shutdown
) {
180 time_t wait
= do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0;
181 debug(1, 1) ("Preparing for shutdown after %d requests\n",
182 statCounter
.client_http
.requests
);
183 debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
187 #if USE_WIN32_SERVICE
189 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
192 serverConnectionsClose();
193 eventAdd("SquidShutdown", StopEventLoop
, this, (double) (wait
+ 1), 1, false);
196 bool result
= events_dispatched
;
197 events_dispatched
= false;
205 #if USE_WIN32_SERVICE
206 "Usage: %s [-cdhirvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
208 "Usage: %s [-cdhvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
210 " -a port Specify HTTP port number (default: %d).\n"
211 " -d level Write debugging to stderr also.\n"
212 " -f file Use given config-file instead of\n"
214 " -h Print help message.\n"
215 #if USE_WIN32_SERVICE
216 " -i Installs as a Windows Service (see -n option).\n"
218 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
219 " Parse configuration file, then send signal to \n"
220 " running copy (except -k parse) and exit.\n"
221 #if USE_WIN32_SERVICE
222 " -n name Specify Windows Service name to use for service operations\n"
223 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
224 " -r Removes a Windows Service (see -n option).\n"
226 " -s | -l facility\n"
227 " Enable logging to syslog.\n"
228 " -u port Specify ICP port number (default: %d), disable with 0.\n"
229 " -v Print version.\n"
230 " -z Create swap directories\n"
231 " -C Do not catch fatal signals.\n"
232 " -D Disable initial DNS tests.\n"
233 " -F Don't serve any requests until store is rebuilt.\n"
234 " -N No daemon mode.\n"
235 #if USE_WIN32_SERVICE
237 " Set Windows Service Command line options in Registry.\n"
239 " -R Do not set REUSEADDR on port.\n"
240 " -S Double-check swap during rebuild.\n"
241 " -V Virtual host httpd-accelerator.\n"
242 " -X Force full debugging.\n"
243 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
244 appname
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
249 mainParseOptions(int argc
, char *argv
[])
254 #if USE_WIN32_SERVICE
256 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
259 while ((c
= getopt(argc
, argv
, "CDFNRSVYXa:d:f:hk:m::sl:u:vz?")) != -1)
268 opt_catch_signals
= 0;
276 opt_foreground_rebuild
= 1;
282 #if USE_WIN32_SERVICE
285 opt_command_line
= 1;
286 WIN32_Command_Line
= xstrdup(optarg
);
295 opt_store_doublecheck
= 1;
300 if (Config
.Sockaddr
.http
)
301 Config
.Sockaddr
.http
->vhost
= 1;
305 else if (Config
.Sockaddr
.https
)
306 Config
.Sockaddr
.https
->http
.vhost
= 1;
311 fatal("No http_port specified\n");
316 /* force full debugging */
317 sigusr2_handle(SIGUSR2
);
322 opt_reload_hit_only
= 1;
326 #if USE_WIN32_SERVICE
329 opt_install_service
= TRUE
;
336 add_http_port(optarg
);
341 opt_debug_stderr
= atoi(optarg
);
348 ConfigFile
= xstrdup(optarg
);
358 if ((int) strlen(optarg
) < 1)
361 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
362 opt_send_signal
= SIGHUP
;
363 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
364 #ifdef _SQUID_LINUX_THREADS_
366 opt_send_signal
= SIGQUIT
;
370 opt_send_signal
= SIGUSR1
;
374 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
375 #ifdef _SQUID_LINUX_THREADS_
377 opt_send_signal
= SIGTRAP
;
381 opt_send_signal
= SIGUSR2
;
385 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
386 opt_send_signal
= SIGTERM
;
387 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
388 opt_send_signal
= SIGINT
;
389 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
390 opt_send_signal
= SIGKILL
;
394 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
395 opt_send_signal
= SIGTTIN
; /* exit and restart by parent */
399 else if (!strncmp(optarg
, "check", strlen(optarg
)))
400 opt_send_signal
= 0; /* SIGNULL */
401 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
402 opt_parse_cfg_only
= 1; /* parse cfg file only */
410 if (*optarg
== 'c') {
411 MemPools::GetInstance().setDefaultPoolChunking(0);
414 malloc_debug_level
= atoi(optarg
);
417 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
424 xmalloc_trace
= !xmalloc_trace
;
427 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
435 #if USE_WIN32_SERVICE
438 xfree(WIN32_Service_name
);
440 WIN32_Service_name
= xstrdup(optarg
);
442 opt_signal_service
= TRUE
;
447 opt_remove_service
= TRUE
;
454 opt_syslog_facility
= xstrdup(optarg
);
459 _db_set_syslog(opt_syslog_facility
);
465 fatal("Logging to syslog not available on this platform");
471 icpPortNumOverride
= atoi(optarg
);
473 if (icpPortNumOverride
< 0)
474 icpPortNumOverride
= 0;
479 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string
, SQUID_CONFIGURE_OPTIONS
);
481 #if USE_WIN32_SERVICE
483 printf("Compiled as Windows System Service.\n");
492 opt_debug_stderr
= 1;
494 opt_create_swap_dirs
= 1;
514 #ifndef _SQUID_MSWIN_
517 signal(sig
, rotate_logs
);
527 #ifndef _SQUID_MSWIN_
530 signal(sig
, reconfigure
);
538 do_shutdown
= sig
== SIGINT
? -1 : 1;
545 #ifndef _SQUID_MSWIN_
546 #ifdef KILL_PARENT_OPT
549 debugs(1, 1, "Killing RunCache, pid " << getppid());
551 if (kill(getppid(), sig
) < 0)
552 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
556 #if SA_RESETHAND == 0
557 signal(SIGTERM
, SIG_DFL
);
559 signal(SIGINT
, SIG_DFL
);
566 serverConnectionsOpen(void)
568 clientOpenListenSockets();
569 icpConnectionsOpen();
576 snmpConnectionOpen();
580 wccpConnectionOpen();
585 wccp2ConnectionOpen();
601 serverConnectionsClose(void)
603 assert(shutting_down
|| reconfiguring
);
604 clientHttpConnectionsClose();
605 icpConnectionShutdown();
608 htcpSocketShutdown();
614 snmpConnectionShutdown();
618 wccpConnectionClose();
622 wccp2ConnectionClose();
629 mainReconfigure(void)
631 debug(1, 1) ("Reconfiguring Squid Cache (version %s)...\n", version_string
);
633 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
634 serverConnectionsClose();
635 icpConnectionClose();
642 snmpConnectionClose();
653 authenticateShutdown();
654 externalAclShutdown();
655 storeDirCloseSwapLogs();
661 enter_suid(); /* root to read config file */
662 parseConfigFile(ConfigFile
, manager
);
664 _db_init(Config
.Log
.log
, Config
.debugOptions
);
665 ipcache_restart(); /* clear stuck entries */
666 authenticateUserCacheRestart(); /* clear stuck ACL entries */
667 fqdncache_restart(); /* sigh, fqdncache too */
669 errorInitialize(); /* reload error pages */
683 authenticateInit(&Config
.authConfiguration
);
694 serverConnectionsOpen();
696 if (theOutIcpConnection
>= 0) {
698 neighborsRegisterWithCacheManager(manager
);
701 storeDirOpenSwapLogs();
703 mimeInit(Config
.mimeTablePathname
);
705 writePidFile(); /* write PID file */
707 debug(1, 1) ("Ready to serve requests.\n");
722 authenticateShutdown();
723 externalAclShutdown();
724 _db_rotate_log(); /* cache.log */
725 storeDirWriteCleanLogs(1);
726 storeLogRotate(); /* store.log */
727 accessLogRotate(); /* access.log */
728 useragentRotateLog(); /* useragent.log */
729 refererRotateLog(); /* referer.log */
742 authenticateInit(&Config
.authConfiguration
);
747 setEffectiveUser(void)
749 leave_suid(); /* Run as non privilegied user */
755 if (geteuid() == 0) {
756 debug(0, 0) ("Squid is not safe to run as root! If you must\n");
757 debug(0, 0) ("start Squid as root, then you must configure\n");
758 debug(0, 0) ("it to run as a non-priveledged user with the\n");
759 debug(0, 0) ("'cache_effective_user' option in the config file.\n");
760 fatal("Don't run Squid as root, set 'cache_effective_user'!");
767 char pathbuf
[MAXPATHLEN
];
769 if (Config
.coredump_dir
) {
770 if (0 == strcmp("none", Config
.coredump_dir
)) {
772 } else if (chdir(Config
.coredump_dir
) == 0) {
773 debug(0, 1) ("Set Current Directory to %s\n", Config
.coredump_dir
);
776 debug(50, 0) ("chdir: %s: %s\n", Config
.coredump_dir
, xstrerror());
780 /* If we don't have coredump_dir or couldn't cd there, report current dir */
781 if (getcwd(pathbuf
, MAXPATHLEN
)) {
782 debug(0, 1) ("Current Directory is %s\n", pathbuf
);
784 debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
789 #include "DelayPools.h"
795 /* chroot if configured to run inside chroot */
797 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
798 fatal("failed to chroot");
801 if (opt_catch_signals
) {
802 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
803 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
806 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
807 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
811 if (icpPortNumOverride
!= 1)
812 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
814 _db_init(Config
.Log
.log
, Config
.debugOptions
);
816 fd_open(fileno(debug_log
), FD_LOG
, Config
.Log
.log
);
820 log_trace_init("/tmp/squid.alloc");
824 debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
830 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
831 debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name
, WIN32_OS_string
);
832 debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line
);
834 debug(1, 0) ("Running on %s\n",WIN32_OS_string
);
838 debugs(1, 1, "Process ID " << getpid());
840 debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD
);
844 debug(1, 1) ("With %d CRT stdio descriptors available\n", _getmaxstdio());
846 if (WIN32_Socks_initialized
)
847 debug(1, 1)("Windows sockets initialized\n");
851 if (!configured_once
)
852 disk_init(); /* disk_init must go before ipcache_init() */
872 authenticateInit(&Config
.authConfiguration
);
880 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
882 httpReplyInitModule(); /* must go before accepting replies */
900 malloc_debug(0, malloc_debug_level
);
904 if (!configured_once
) {
913 /* after this point we want to see the mallinfo() output */
915 mimeInit(Config
.mimeTablePathname
);
922 FwdState::initModule();
923 /* register the modules in the cache manager menus */
924 accessLogRegisterWithCacheManager(manager
);
925 asnRegisterWithCacheManager(manager
);
926 authenticateRegisterWithCacheManager(&Config
.authConfiguration
, manager
);
929 carpRegisterWithCacheManager(manager
);
932 cbdataRegisterWithCacheManager(manager
);
933 /* These use separate calls so that the comm loops can eventually
938 commEPollRegisterWithCacheManager(manager
);
942 commKQueueRegisterWithCacheManager(manager
);
946 commPollRegisterWithCacheManager(manager
);
950 commSelectRegisterWithCacheManager(manager
);
953 clientdbRegisterWithCacheManager(manager
);
956 DelayPools::RegisterWithCacheManager(manager
);
959 DiskIOModule::RegisterAllModulesWithCacheManager(manager
);
962 dnsRegisterWithCacheManager(manager
);
966 externalAclRegisterWithCacheManager(manager
);
967 fqdncacheRegisterWithCacheManager(manager
);
968 FwdState::RegisterWithCacheManager(manager
);
969 httpHeaderRegisterWithCacheManager(manager
);
972 idnsRegisterWithCacheManager(manager
);
975 ipcacheRegisterWithCacheManager(manager
);
976 Mem::RegisterWithCacheManager(manager
);
977 netdbRegisterWitHCacheManager(manager
);
978 PconnModule::GetInstance()->registerWithCacheManager(manager
);
979 redirectRegisterWithCacheManager(manager
);
980 refreshRegisterWithCacheManager(manager
);
981 statRegisterWithCacheManager(manager
);
982 storeDigestRegisterWithCacheManager(manager
);
983 StoreFileSystem::RegisterAllFsWithCacheManager(manager
);
984 storeRegisterWithCacheManager(manager
);
987 StringRegistry::Instance().registerWithCacheManager(manager
);
992 xprofRegisterWithCacheManager(manager
);
1007 serverConnectionsOpen();
1009 if (theOutIcpConnection
>= 0) {
1011 neighborsRegisterWithCacheManager(manager
);
1014 if (Config
.chroot_dir
)
1017 if (!configured_once
)
1018 writePidFile(); /* write PID file */
1020 #ifdef _SQUID_LINUX_THREADS_
1022 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1024 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1028 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1030 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1034 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1036 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1038 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1042 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1048 debug(1, 1) ("Ready to serve requests.\n");
1050 if (!configured_once
) {
1051 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1053 if (Config
.onoff
.announce
)
1054 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1056 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1058 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1062 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1066 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1068 eventAdd("commCheckHalfClosed", commCheckHalfClosed
, NULL
, 1.0, false);
1071 configured_once
= 1;
1074 #if USE_WIN32_SERVICE
1075 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1076 extern "C" void WINAPI
1077 SquidWinSvcMain(int argc
, char **argv
)
1079 SquidMain(argc
, argv
);
1083 SquidMain(int argc
, char **argv
)
1086 main(int argc
, char **argv
)
1090 #ifdef _SQUID_WIN32_
1097 sbrk_start
= sbrk(0);
1100 Debug::parseOptions("ALL,1");
1103 #if defined(SQUID_MAXFD_LIMIT)
1105 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1106 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1110 #ifdef _SQUID_WIN32_
1112 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1113 return WIN32_init_err
;
1117 /* call mallopt() before anything else */
1120 /* Round up all sizes to a multiple of this */
1121 mallopt(M_GRAIN
, 16);
1125 /* biggest size that is considered a small block */
1126 mallopt(M_MXFAST
, 256);
1130 /* allocate this many small blocks at once */
1131 mallopt(M_NLBLKS
, 32);
1134 #endif /* HAVE_MALLOPT */
1137 * The plan here is to set the umask to 007 (deny others for
1138 * read,write,execute), but only if the umask is not already
1139 * set. Unfortunately, there is no way to get the current
1140 * umask value without setting it.
1142 oldmask
= umask(S_IRWXO
);
1147 memset(&local_addr
, '\0', sizeof(struct IN_ADDR
));
1149 safe_inet_addr(localhost
, &local_addr
);
1151 memset(&any_addr
, '\0', sizeof(struct IN_ADDR
));
1153 safe_inet_addr("0.0.0.0", &any_addr
);
1155 memset(&no_addr
, '\0', sizeof(struct IN_ADDR
));
1157 safe_inet_addr("255.255.255.255", &no_addr
);
1159 squid_srandom(time(NULL
));
1163 squid_start
= current_time
;
1165 failure_notify
= fatal_dump
;
1167 #if USE_WIN32_SERVICE
1169 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1173 mainParseOptions(argc
, argv
);
1175 #if USE_WIN32_SERVICE
1177 if (opt_install_service
)
1179 WIN32_InstallService();
1183 if (opt_remove_service
)
1185 WIN32_RemoveService();
1189 if (opt_command_line
)
1191 WIN32_SetServiceCommandLine();
1197 /* parse configuration file
1198 * note: in "normal" case this used to be called from mainInitialize() */
1203 ConfigFile
= xstrdup(DefaultConfigFile
);
1205 assert(!configured_once
);
1211 storeFsInit(); /* required for config parsing */
1213 /* May not be needed for parsing, have not audited for such */
1214 DiskIOModule::SetupAllModules();
1216 /* Shouldn't be needed for config parsing, but have not audited for such */
1217 StoreFileSystem::SetupAllFs();
1219 /* we may want the parsing process to set this up in the future */
1220 Store::Root(new StoreController
);
1222 parse_err
= parseConfigFile(ConfigFile
, manager
);
1224 if (opt_parse_cfg_only
)
1228 if (-1 == opt_send_signal
)
1229 if (checkRunningPid())
1246 /* send signal to running copy and exit */
1247 if (opt_send_signal
!= -1)
1249 /* chroot if configured to run inside chroot */
1251 if (Config
.chroot_dir
) {
1252 if (chroot(Config
.chroot_dir
))
1253 fatal("failed to chroot");
1264 if (opt_create_swap_dirs
)
1266 /* chroot if configured to run inside chroot */
1268 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1269 fatal("failed to chroot");
1273 debug(0, 0) ("Creating Swap Directories\n");
1274 Store::Root().create();
1284 /* init comm module */
1291 /* we have to init fdstat here. */
1292 fd_open(0, FD_LOG
, "stdin");
1293 fd_open(1, FD_LOG
, "stdout");
1294 fd_open(2, FD_LOG
, "stderr");
1297 #if USE_WIN32_SERVICE
1299 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1305 #if USE_WIN32_SERVICE
1307 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1314 SignalDispatcher
signal_dispatcher(mainLoop
);
1316 mainLoop
.registerDispatcher(&signal_dispatcher
);
1318 /* TODO: stop requiring the singleton here */
1319 mainLoop
.registerDispatcher(EventDispatcher::GetInstance());
1321 /* TODO: stop requiring the singleton here */
1322 mainLoop
.registerEngine(EventScheduler::GetInstance());
1324 StoreRootEngine store_engine
;
1326 mainLoop
.registerEngine(&store_engine
);
1328 CommDispatcher comm_dispatcher
;
1330 mainLoop
.registerDispatcher(&comm_dispatcher
);
1332 CommSelectEngine comm_engine
;
1334 mainLoop
.registerEngine(&comm_engine
);
1336 mainLoop
.setPrimaryEngine(&comm_engine
);
1338 /* use the standard time service */
1339 TimeEngine time_engine
;
1341 mainLoop
.setTimeService(&time_engine
);
1345 if (mainLoop
.errcount
== 10)
1346 fatal_dump("Event loop exited with failure.");
1348 /* shutdown squid now */
1361 if (strcmp(Config
.pidFilename
, "none") == 0) {
1362 debug(0, 1) ("No pid_filename specified. Trusting you know what you are doing.\n");
1365 pid
= readPidFile();
1368 #if USE_WIN32_SERVICE
1370 if (opt_signal_service
) {
1371 WIN32_sendSignal(opt_send_signal
);
1374 #ifdef _SQUID_MSWIN_
1376 fprintf(stderr
, "%s: ERROR: Could not send ", appname
);
1377 fprintf(stderr
, "signal to Squid Service:\n");
1378 fprintf(stderr
, "missing -n command line switch.\n");
1387 if (kill(pid
, opt_send_signal
) &&
1388 /* ignore permissions if just running check */
1389 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1390 fprintf(stderr
, "%s: ERROR: Could not send ", appname
);
1391 fprintf(stderr
, "signal %d to process %d: %s\n",
1392 opt_send_signal
, (int) pid
, xstrerror());
1396 fprintf(stderr
, "%s: ERROR: No running copy\n", appname
);
1400 /* signal successfully sent */
1404 #ifndef _SQUID_MSWIN_
1406 * This function is run when Squid is in daemon mode, just
1407 * before the parent forks and starts up the child process.
1408 * It can be used for admin-specific tasks, such as notifying
1409 * someone that Squid is (re)started.
1412 mainStartScript(const char *prog
)
1414 char script
[SQUID_MAXPATHLEN
];
1419 xstrncpy(script
, prog
, MAXPATHLEN
);
1421 if ((t
= strrchr(script
, '/'))) {
1423 sl
= strlen(script
);
1426 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1428 if ((cpid
= fork()) == 0) {
1430 execl(script
, squid_start_script
, (char *)NULL
);
1436 rpid
= wait3(&status
, 0, NULL
);
1440 rpid
= waitpid(-1, &status
, 0);
1443 } while (rpid
!= cpid
);
1447 #endif /* _SQUID_MSWIN_ */
1450 checkRunningPid(void)
1457 pid
= readPidFile();
1462 if (kill(pid
, 0) < 0)
1465 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1471 watch_child(char *argv
[])
1473 #ifndef _SQUID_MSWIN_
1494 if (*(argv
[0]) == '(')
1497 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1499 if ((pid
= fork()) < 0)
1500 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1505 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1511 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1512 ioctl(i
, TIOCNOTTY
, NULL
);
1519 * RBCOLLINS - if cygwin stackdumps when squid is run without
1520 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1521 * 1.1.3. execvp had a bit overflow error in a loop..
1523 /* Connect stdio to /dev/null in daemon mode */
1524 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1527 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1531 if (opt_debug_stderr
< 0) {
1537 mainStartScript(argv
[0]);
1539 if ((pid
= fork()) == 0) {
1541 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1542 prog
= xstrdup(argv
[0]);
1543 argv
[0] = xstrdup("(squid)");
1545 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1549 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1551 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1555 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1559 pid
= wait3(&status
, 0, NULL
);
1563 pid
= waitpid(-1, &status
, 0);
1569 if (WIFEXITED(status
)) {
1571 "Squid Parent: child process %d exited with status %d",
1572 pid
, WEXITSTATUS(status
));
1573 } else if (WIFSIGNALED(status
)) {
1575 "Squid Parent: child process %d exited due to signal %d",
1576 pid
, WTERMSIG(status
));
1578 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", pid
);
1581 if (stop
- start
< 10)
1586 if (failcount
== 5) {
1587 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1591 if (WIFEXITED(status
))
1592 if (WEXITSTATUS(status
) == 0)
1595 if (WIFSIGNALED(status
)) {
1596 switch (WTERMSIG(status
)) {
1607 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1612 #endif /* _SQUID_MSWIN_ */
1619 #if USE_WIN32_SERVICE
1620 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1623 debug(1, 1) ("Shutting down...\n");
1633 externalAclShutdown();
1634 icpConnectionClose();
1641 snmpConnectionClose();
1645 wccpConnectionClose();
1649 wccp2ConnectionClose();
1652 releaseServerSockets();
1653 commCloseAllSockets();
1656 DelayPools::FreePools();
1659 authenticateShutdown();
1664 #if USE_WIN32_SERVICE
1666 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1669 Store::Root().sync(); /* Flush pending object writes/unlinks */
1670 storeDirWriteCleanLogs(0);
1673 Store::Root().sync(); /* Flush log writes */
1676 useragentLogClose();
1683 Store::Root().sync(); /* Flush log close */
1684 StoreFileSystem::FreeAllFs();
1685 DiskIOModule::FreeAllModules();
1686 #if PURIFY || XMALLOC_TRACE
1690 /*stmemFreeMemory(); */
1692 ipcacheFreeMemory();
1693 fqdncacheFreeMemory();
1695 clientdbFreeMemory();
1696 httpHeaderCleanModule();
1704 if (opt_no_daemon
) {
1719 xmalloc_find_leaks();
1721 debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total
);
1730 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1732 safeunlink(Config
.pidFilename
, 0);
1736 debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
1742 exit(shutdown_status
);