2 * $Id: main.cc,v 1.459 2008/02/26 21:49:35 amosjeffries Exp $
4 * DEBUG: section 1 Startup and Main Loop
5 * AUTHOR: Harvest Derived
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 #include "AccessLogEntry.h"
37 #include "authenticate.h"
38 #include "ConfigParser.h"
39 #include "errorpage.h"
41 #include "EventLoop.h"
42 #include "ExternalACL.h"
46 #include "HttpReply.h"
52 #include "StoreFileSystem.h"
53 #include "DiskIO/DiskIOModule.h"
56 #include "comm_epoll.h"
59 #include "comm_kqueue.h"
62 #include "comm_poll.h"
64 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
65 #include "comm_select.h"
67 #include "SquidTime.h"
71 #include "ICMPSquid.h"
72 #include "TextException.h"
74 #if USE_LOADABLE_MODULES
75 #include "LoadableModules.h"
79 #include "ICAP/ICAPConfig.h"
82 #include "eCAP/Config.h"
85 #include "adaptation/Config.h"
90 #include "squid_windows.h"
93 static int opt_install_service
= FALSE
;
94 static int opt_remove_service
= FALSE
;
95 static int opt_signal_service
= FALSE
;
96 static int opt_command_line
= FALSE
;
97 extern void WIN32_svcstatusupdate(DWORD
, DWORD
);
98 void WINAPI
WIN32_svcHandler(DWORD
);
102 /** for error reporting from xmalloc and friends */
103 SQUIDCEXTERN
void (*failure_notify
) (const char *);
105 static int opt_parse_cfg_only
= 0;
106 static char *opt_syslog_facility
= NULL
;
107 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
108 static int configured_once
= 0;
110 static int malloc_debug_level
= 0;
112 static volatile int do_reconfigure
= 0;
113 static volatile int do_rotate
= 0;
114 static volatile int do_shutdown
= 0;
115 static volatile int shutdown_status
= 0;
117 static void mainRotate(void);
118 static void mainReconfigureStart(void);
119 static void mainReconfigureFinish(void*);
120 static void mainInitialize(void);
121 static void usage(void);
122 static void mainParseOptions(int argc
, char *argv
[]);
123 static void sendSignal(void);
124 static void serverConnectionsOpen(void);
125 static void serverConnectionsClose(void);
126 static void watch_child(char **);
127 static void setEffectiveUser(void);
129 extern void log_trace_done();
130 extern void log_trace_init(char *);
132 static void SquidShutdown(void);
133 static void mainSetCwd(void);
134 static int checkRunningPid(void);
136 #ifndef _SQUID_MSWIN_
137 static const char *squid_start_script
= "squid_start";
141 #include "test_access.c"
144 /** temporary thunk across to the unrefactored store interface */
146 class StoreRootEngine
: public AsyncEngine
150 int checkEvents(int timeout
)
152 Store::Root().callback();
157 class SignalEngine
: public AsyncEngine
161 SignalEngine(EventLoop
&loop
) : loop(loop
) {}
162 virtual int checkEvents(int timeout
);
165 static void StopEventLoop(void * data
)
167 static_cast<SignalEngine
*>(data
)->loop
.stop();
170 void doShutdown(time_t wait
);
176 SignalEngine::checkEvents(int timeout
)
178 PROF_start(SignalEngine_checkEvents
);
180 if (do_reconfigure
) {
181 mainReconfigureStart();
183 } else if (do_rotate
) {
186 } else if (do_shutdown
) {
187 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
191 PROF_stop(SignalEngine_checkEvents
);
196 SignalEngine::doShutdown(time_t wait
)
198 debugs(1, 1, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
199 debugs(1, 1, "Waiting " << wait
<< " seconds for active connections to finish");
203 #if USE_WIN32_SERVICE
204 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
207 serverConnectionsClose();
208 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
215 #if USE_WIN32_SERVICE
216 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
218 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
220 " -a port Specify HTTP port number (default: %d).\n"
221 " -d level Write debugging to stderr also.\n"
222 " -f file Use given config-file instead of\n"
224 " -h Print help message.\n"
225 #if USE_WIN32_SERVICE
226 " -i Installs as a Windows Service (see -n option).\n"
228 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
229 " Parse configuration file, then send signal to \n"
230 " running copy (except -k parse) and exit.\n"
231 #if USE_WIN32_SERVICE
232 " -n name Specify Windows Service name to use for service operations\n"
233 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
234 " -r Removes a Windows Service (see -n option).\n"
236 " -s | -l facility\n"
237 " Enable logging to syslog.\n"
238 " -u port Specify ICP port number (default: %d), disable with 0.\n"
239 " -v Print version.\n"
240 " -z Create swap directories\n"
241 " -C Do not catch fatal signals.\n"
242 " -D OBSOLETE. Scheduled for removal.\n"
243 " -F Don't serve any requests until store is rebuilt.\n"
244 " -N No daemon mode.\n"
245 #if USE_WIN32_SERVICE
247 " Set Windows Service Command line options in Registry.\n"
249 " -R Do not set REUSEADDR on port.\n"
250 " -S Double-check swap during rebuild.\n"
251 " -V Virtual host httpd-accelerator.\n"
252 " -X Force full debugging.\n"
253 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
254 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
259 * Parse the parameters received via command line interface.
261 \param argc[in] Number of options received on command line
262 \param argv[in] List of parameters received on command line
265 mainParseOptions(int argc
, char *argv
[])
270 #if USE_WIN32_SERVICE
271 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
273 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
282 * Unset/disabel global option for catchign signals. opt_catch_signals */
283 opt_catch_signals
= 0;
288 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
289 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
294 * Set global option for foreground rebuild. opt_foreground_rebuild */
295 opt_foreground_rebuild
= 1;
300 * Set global option for 'no_daemon' mode. opt_no_daemon */
304 #if USE_WIN32_SERVICE
308 * Set global option. opt_command_lin and WIN32_Command_Line */
309 opt_command_line
= 1;
310 WIN32_Command_Line
= xstrdup(optarg
);
316 * Unset/disable global option opt_reuseaddr */
322 * Set global option opt_store_doublecheck */
323 opt_store_doublecheck
= 1;
328 * Force full debugging */
329 Debug::parseOptions("debug_options ALL,9");
330 Config
.onoff
.debug_override_X
= 1;
331 sigusr2_handle(SIGUSR2
);
336 * Set global option opt_reload_hit_only */
337 opt_reload_hit_only
= 1;
340 #if USE_WIN32_SERVICE
344 * Set global option opt_install_service (to TRUE) */
345 opt_install_service
= TRUE
;
351 * Add optional HTTP port as given following the option */
352 add_http_port(optarg
);
357 * Set global option opt_debug_stderr to the number given follwoign the option */
358 opt_debug_stderr
= atoi(optarg
);
363 * Load the file given instead of the default squid.conf. */
365 ConfigFile
= xstrdup(optarg
);
370 * Run the administrative action given following the option */
372 /** \li When its an unknown option display the usage help. */
373 if ((int) strlen(optarg
) < 1)
376 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
377 /** \li On reconfigure send SIGHUP. */
378 opt_send_signal
= SIGHUP
;
379 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
380 /** \li On rotate send SIGQUIT or SIGUSR1. */
381 #ifdef _SQUID_LINUX_THREADS_
383 opt_send_signal
= SIGQUIT
;
387 opt_send_signal
= SIGUSR1
;
391 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
392 /** \li On debug send SIGTRAP or SIGUSR2. */
393 #ifdef _SQUID_LINUX_THREADS_
395 opt_send_signal
= SIGTRAP
;
399 opt_send_signal
= SIGUSR2
;
403 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
404 /** \li On shutdown send SIGTERM. */
405 opt_send_signal
= SIGTERM
;
406 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
407 /** \li On interrupt send SIGINT. */
408 opt_send_signal
= SIGINT
;
409 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
410 /** \li On kill send SIGKILL. */
411 opt_send_signal
= SIGKILL
;
415 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
416 /** \li On restart send SIGTTIN. (exit and restart by parent) */
417 opt_send_signal
= SIGTTIN
;
421 else if (!strncmp(optarg
, "check", strlen(optarg
)))
422 /** \li On check send 0 / SIGNULL. */
423 opt_send_signal
= 0; /* SIGNULL */
424 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
425 /** \li On parse set global flag to re-parse the config file only. */
426 opt_parse_cfg_only
= 1;
434 * Set global malloc_debug_level to the value given following the option.
435 * if none is given it toggles the xmalloc_trace option on/off */
438 malloc_debug_level
= atoi(optarg
);
440 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
445 xmalloc_trace
= !xmalloc_trace
;
447 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
452 #if USE_WIN32_SERVICE
456 * Set global option opt_signal_service (to TRUE).
457 * Stores the additional parameter given in global WIN32_Service_name */
458 xfree(WIN32_Service_name
);
460 WIN32_Service_name
= xstrdup(optarg
);
462 opt_signal_service
= TRUE
;
468 * Set global option opt_remove_service (to TRUE) */
469 opt_remove_service
= TRUE
;
477 * Stores the syslog facility name in global opt_syslog_facility
478 * then performs actions for -s option. */
479 opt_syslog_facility
= xstrdup(optarg
);
483 * Initialize the syslog for output */
486 _db_set_syslog(opt_syslog_facility
);
492 fatal("Logging to syslog not available on this platform");
499 * Store the ICP port number given in global option icpPortNumOverride
500 * ensuring its a positive number. */
501 icpPortNumOverride
= atoi(optarg
);
503 if (icpPortNumOverride
< 0)
504 icpPortNumOverride
= 0;
510 * Display squid version and build information. Then exit. */
511 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string
, SQUID_CONFIGURE_OPTIONS
);
513 #if USE_WIN32_SERVICE
515 printf("Compiled as Windows System Service.\n");
525 * Set global option opt_debug_stderr and opt_create_swap_dirs */
526 opt_debug_stderr
= 1;
528 opt_create_swap_dirs
= 1;
537 /** \par h,?, or unknown
538 * \copydoc usage() */
552 #ifndef _SQUID_MSWIN_
555 signal(sig
, rotate_logs
);
565 #ifndef _SQUID_MSWIN_
568 signal(sig
, reconfigure
);
576 do_shutdown
= sig
== SIGINT
? -1 : 1;
583 #ifndef _SQUID_MSWIN_
584 #ifdef KILL_PARENT_OPT
587 debugs(1, 1, "Killing RunCache, pid " << getppid());
589 if (kill(getppid(), sig
) < 0)
590 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
594 #if SA_RESETHAND == 0
595 signal(SIGTERM
, SIG_DFL
);
597 signal(SIGINT
, SIG_DFL
);
604 serverConnectionsOpen(void)
606 clientOpenListenSockets();
607 icpConnectionsOpen();
614 snmpConnectionOpen();
618 wccpConnectionOpen();
623 wccp2ConnectionOpen();
635 peerSourceHashInit();
639 serverConnectionsClose(void)
641 assert(shutting_down
|| reconfiguring
);
642 clientHttpConnectionsClose();
643 icpConnectionShutdown();
646 htcpSocketShutdown();
652 snmpConnectionShutdown();
656 wccpConnectionClose();
660 wccp2ConnectionClose();
667 mainReconfigureStart(void)
669 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
672 // Initiate asynchronous closing sequence
673 serverConnectionsClose();
674 icpConnectionClose();
681 snmpConnectionClose();
692 authenticateShutdown();
693 externalAclShutdown();
694 storeDirCloseSwapLogs();
700 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
705 mainReconfigureFinish(void *) {
706 debugs(1, 3, "finishing reconfiguring");
709 enter_suid(); /* root to read config file */
710 parseConfigFile(ConfigFile
);
711 setUmask(Config
.umask
);
714 _db_init(Config
.Log
.log
, Config
.debugOptions
);
715 ipcache_restart(); /* clear stuck entries */
716 authenticateUserCacheRestart(); /* clear stuck ACL entries */
717 fqdncache_restart(); /* sigh, fqdncache too */
719 errorInitialize(); /* reload error pages */
733 authenticateInit(&Config
.authConfiguration
);
744 serverConnectionsOpen();
748 storeDirOpenSwapLogs();
750 mimeInit(Config
.mimeTablePathname
);
752 if (Config
.onoff
.announce
) {
753 if (!eventFind(start_announce
, NULL
))
754 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
756 if (eventFind(start_announce
, NULL
))
757 eventDelete(start_announce
, NULL
);
760 writePidFile(); /* write PID file */
762 debugs(1, 1, "Ready to serve requests.");
777 authenticateShutdown();
778 externalAclShutdown();
779 _db_rotate_log(); /* cache.log */
780 storeDirWriteCleanLogs(1);
781 storeLogRotate(); /* store.log */
782 accessLogRotate(); /* access.log */
783 useragentRotateLog(); /* useragent.log */
784 refererRotateLog(); /* referer.log */
797 authenticateInit(&Config
.authConfiguration
);
802 setEffectiveUser(void)
805 leave_suid(); /* Run as non privilegied user */
811 if (geteuid() == 0) {
812 debugs(0, 0, "Squid is not safe to run as root! If you must");
813 debugs(0, 0, "start Squid as root, then you must configure");
814 debugs(0, 0, "it to run as a non-priveledged user with the");
815 debugs(0, 0, "'cache_effective_user' option in the config file.");
816 fatal("Don't run Squid as root, set 'cache_effective_user'!");
823 char pathbuf
[MAXPATHLEN
];
825 if (Config
.coredump_dir
) {
826 if (0 == strcmp("none", Config
.coredump_dir
)) {
828 } else if (chdir(Config
.coredump_dir
) == 0) {
829 debugs(0, 1, "Set Current Directory to " << Config
.coredump_dir
);
832 debugs(50, 0, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
836 /* If we don't have coredump_dir or couldn't cd there, report current dir */
837 if (getcwd(pathbuf
, MAXPATHLEN
)) {
838 debugs(0, 1, "Current Directory is " << pathbuf
);
840 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
845 #include "DelayPools.h"
851 /* chroot if configured to run inside chroot */
853 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
854 fatal("failed to chroot");
857 if (opt_catch_signals
) {
858 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
859 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
862 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
863 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
867 if (icpPortNumOverride
!= 1)
868 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
870 _db_init(Config
.Log
.log
, Config
.debugOptions
);
872 fd_open(fileno(debug_log
), FD_LOG
, Config
.Log
.log
);
876 log_trace_init("/tmp/squid.alloc");
880 debugs(1, 0, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
884 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
885 debugs(1, 0, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
886 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line
);
888 debugs(1, 0, "Running on " << WIN32_OS_string
);
892 debugs(1, 1, "Process ID " << getpid());
894 debugs(1, 1, "With " << Squid_MaxFD
<< " file descriptors available");
898 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
900 if (WIN32_Socks_initialized
)
901 debugs(1, 1, "Windows sockets initialized");
903 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
904 WIN32_IpAddrChangeMonitorInit();
909 if (!configured_once
)
910 disk_init(); /* disk_init must go before ipcache_init() */
930 authenticateInit(&Config
.authConfiguration
);
938 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
940 httpReplyInitModule(); /* must go before accepting replies */
958 malloc_debug(0, malloc_debug_level
);
962 if (!configured_once
) {
971 /* after this point we want to see the mallinfo() output */
973 mimeInit(Config
.mimeTablePathname
);
980 FwdState::initModule();
981 /* register the modules in the cache manager menus */
983 cbdataRegisterWithCacheManager();
984 /* These use separate calls so that the comm loops can eventually
990 // TODO: pconn is a good candidate for new-style registration
991 // PconnModule::GetInstance()->registerWithCacheManager();
992 // moved to PconnModule::PconnModule()
1005 serverConnectionsOpen();
1009 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1011 if (Config
.chroot_dir
)
1014 if (!configured_once
)
1015 writePidFile(); /* write PID file */
1017 #ifdef _SQUID_LINUX_THREADS_
1019 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1021 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1025 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1027 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1031 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1033 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1035 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1039 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1045 #if USE_LOADABLE_MODULES
1046 LoadableModulesConfigure(Config
.loadable_module_names
);
1050 bool enableAdaptation
= false;
1052 // We can remove this dependency on specific adaptation mechanisms
1053 // if we create a generic Registry of such mechanisms. Should we?
1055 TheICAPConfig
.finalize();
1056 enableAdaptation
= TheICAPConfig
.onoff
|| enableAdaptation
;
1059 Ecap::TheConfig
.finalize(); // must be after we load modules
1060 enableAdaptation
= Ecap::TheConfig
.onoff
|| enableAdaptation
;
1062 // must be the last adaptation-related finalize
1063 Adaptation::Config::Finalize(enableAdaptation
);
1067 debugs(1, 1, "Ready to serve requests.");
1069 if (!configured_once
) {
1070 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1072 if (Config
.onoff
.announce
)
1073 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1075 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1077 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1081 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1085 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1088 configured_once
= 1;
1091 static int SquidMain(int argc
, char **argv
);
1092 static int SquidMainSafe(int argc
, char **argv
);
1094 #if USE_WIN32_SERVICE
1095 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1096 extern "C" void WINAPI
1097 SquidWinSvcMain(int argc
, char **argv
)
1100 main(int argc
, char **argv
)
1103 SquidMainSafe(argc
, argv
);
1107 SquidMainSafe(int argc
, char **argv
)
1110 return SquidMain(argc
, argv
);
1112 catch (const TextException
&e
) {
1113 // XXX: add TextException::print
1114 std::cerr
<< "dying from unhandled exception: " << e
.message
<< std::endl
;
1117 std::cerr
<< "dying from unhandled exception." << std::endl
;
1123 SquidMain(int argc
, char **argv
)
1125 #ifdef _SQUID_WIN32_
1132 sbrk_start
= sbrk(0);
1135 Debug::parseOptions(NULL
);
1138 #if defined(SQUID_MAXFD_LIMIT)
1140 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1141 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1145 #ifdef _SQUID_WIN32_
1147 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1148 return WIN32_init_err
;
1152 /* call mallopt() before anything else */
1155 /* Round up all sizes to a multiple of this */
1156 mallopt(M_GRAIN
, 16);
1160 /* biggest size that is considered a small block */
1161 mallopt(M_MXFAST
, 256);
1165 /* allocate this many small blocks at once */
1166 mallopt(M_NLBLKS
, 32);
1169 #endif /* HAVE_MALLOPT */
1171 squid_srandom(time(NULL
));
1175 squid_start
= current_time
;
1177 failure_notify
= fatal_dump
;
1179 #if USE_WIN32_SERVICE
1181 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1185 mainParseOptions(argc
, argv
);
1187 if (opt_parse_cfg_only
) {
1188 Debug::parseOptions("ALL,1");
1191 #if USE_WIN32_SERVICE
1193 if (opt_install_service
)
1195 WIN32_InstallService();
1199 if (opt_remove_service
)
1201 WIN32_RemoveService();
1205 if (opt_command_line
)
1207 WIN32_SetServiceCommandLine();
1213 /* parse configuration file
1214 * note: in "normal" case this used to be called from mainInitialize() */
1219 ConfigFile
= xstrdup(DefaultConfigFile
);
1221 assert(!configured_once
);
1225 storeFsInit(); /* required for config parsing */
1227 /* May not be needed for parsing, have not audited for such */
1228 DiskIOModule::SetupAllModules();
1230 /* Shouldn't be needed for config parsing, but have not audited for such */
1231 StoreFileSystem::SetupAllFs();
1233 /* we may want the parsing process to set this up in the future */
1234 Store::Root(new StoreController
);
1236 parse_err
= parseConfigFile(ConfigFile
);
1240 if (opt_parse_cfg_only
)
1244 setUmask(Config
.umask
);
1245 if (-1 == opt_send_signal
)
1246 if (checkRunningPid())
1263 /* send signal to running copy and exit */
1264 if (opt_send_signal
!= -1)
1266 /* chroot if configured to run inside chroot */
1268 if (Config
.chroot_dir
) {
1269 if (chroot(Config
.chroot_dir
))
1270 fatal("failed to chroot");
1281 if (opt_create_swap_dirs
)
1283 /* chroot if configured to run inside chroot */
1285 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1286 fatal("failed to chroot");
1290 debugs(0, 0, "Creating Swap Directories");
1291 Store::Root().create();
1301 /* init comm module */
1308 /* we have to init fdstat here. */
1309 fd_open(0, FD_LOG
, "stdin");
1310 fd_open(1, FD_LOG
, "stdout");
1311 fd_open(2, FD_LOG
, "stderr");
1314 #if USE_WIN32_SERVICE
1316 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1322 #if USE_WIN32_SERVICE
1324 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1331 SignalEngine
signalEngine(mainLoop
);
1333 mainLoop
.registerEngine(&signalEngine
);
1335 /* TODO: stop requiring the singleton here */
1336 mainLoop
.registerEngine(EventScheduler::GetInstance());
1338 StoreRootEngine store_engine
;
1340 mainLoop
.registerEngine(&store_engine
);
1342 CommSelectEngine comm_engine
;
1344 mainLoop
.registerEngine(&comm_engine
);
1346 mainLoop
.setPrimaryEngine(&comm_engine
);
1348 /* use the standard time service */
1349 TimeEngine time_engine
;
1351 mainLoop
.setTimeService(&time_engine
);
1355 if (mainLoop
.errcount
== 10)
1356 fatal_dump("Event loop exited with failure.");
1358 /* shutdown squid now */
1371 if (strcmp(Config
.pidFilename
, "none") == 0) {
1372 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1375 pid
= readPidFile();
1378 #if USE_WIN32_SERVICE
1380 if (opt_signal_service
) {
1381 WIN32_sendSignal(opt_send_signal
);
1384 #ifdef _SQUID_MSWIN_
1386 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1387 fprintf(stderr
, "signal to Squid Service:\n");
1388 fprintf(stderr
, "missing -n command line switch.\n");
1397 if (kill(pid
, opt_send_signal
) &&
1398 /* ignore permissions if just running check */
1399 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1400 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1401 fprintf(stderr
, "signal %d to process %d: %s\n",
1402 opt_send_signal
, (int) pid
, xstrerror());
1406 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1410 /* signal successfully sent */
1414 #ifndef _SQUID_MSWIN_
1416 * This function is run when Squid is in daemon mode, just
1417 * before the parent forks and starts up the child process.
1418 * It can be used for admin-specific tasks, such as notifying
1419 * someone that Squid is (re)started.
1422 mainStartScript(const char *prog
)
1424 char script
[SQUID_MAXPATHLEN
];
1429 xstrncpy(script
, prog
, MAXPATHLEN
);
1431 if ((t
= strrchr(script
, '/'))) {
1433 sl
= strlen(script
);
1436 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1438 if ((cpid
= fork()) == 0) {
1440 execl(script
, squid_start_script
, (char *)NULL
);
1446 rpid
= wait3(&status
, 0, NULL
);
1450 rpid
= waitpid(-1, &status
, 0);
1453 } while (rpid
!= cpid
);
1457 #endif /* _SQUID_MSWIN_ */
1460 checkRunningPid(void)
1467 pid
= readPidFile();
1472 if (kill(pid
, 0) < 0)
1475 debugs(0, 0, "Squid is already running! Process ID " << pid
);
1481 watch_child(char *argv
[])
1483 #ifndef _SQUID_MSWIN_
1504 if (*(argv
[0]) == '(')
1507 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1509 if ((pid
= fork()) < 0)
1510 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1515 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1521 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1522 ioctl(i
, TIOCNOTTY
, NULL
);
1529 * RBCOLLINS - if cygwin stackdumps when squid is run without
1530 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1531 * 1.1.3. execvp had a bit overflow error in a loop..
1533 /* Connect stdio to /dev/null in daemon mode */
1534 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1537 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1541 if (opt_debug_stderr
< 0) {
1547 mainStartScript(argv
[0]);
1549 if ((pid
= fork()) == 0) {
1551 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1552 prog
= xstrdup(argv
[0]);
1553 argv
[0] = xstrdup("(squid)");
1555 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1559 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1561 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
1565 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1569 pid
= wait3(&status
, 0, NULL
);
1573 pid
= waitpid(-1, &status
, 0);
1579 if (WIFEXITED(status
)) {
1581 "Squid Parent: child process %d exited with status %d",
1582 pid
, WEXITSTATUS(status
));
1583 } else if (WIFSIGNALED(status
)) {
1585 "Squid Parent: child process %d exited due to signal %d with status %d",
1586 pid
, WTERMSIG(status
), WEXITSTATUS(status
));
1588 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", pid
);
1591 if (stop
- start
< 10)
1596 if (failcount
== 5) {
1597 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1601 if (WIFEXITED(status
))
1602 if (WEXITSTATUS(status
) == 0)
1605 if (WIFSIGNALED(status
)) {
1606 switch (WTERMSIG(status
)) {
1614 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1623 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1628 #endif /* _SQUID_MSWIN_ */
1635 /* XXX: This function is called after the main loop has quit, which
1636 * means that no AsyncCalls would be called, including close handlers.
1637 * TODO: We need to close/shut/free everything that needs calls before
1641 #if USE_WIN32_SERVICE
1642 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1645 debugs(1, 1, "Shutting down...");
1655 externalAclShutdown();
1656 icpConnectionClose();
1663 snmpConnectionClose();
1667 wccpConnectionClose();
1671 wccp2ConnectionClose();
1674 releaseServerSockets();
1675 commCloseAllSockets();
1678 DelayPools::FreePools();
1681 authenticateShutdown();
1682 #if USE_WIN32_SERVICE
1684 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1687 Store::Root().sync(); /* Flush pending object writes/unlinks */
1690 unlinkdClose(); /* after sync/flush */
1693 storeDirWriteCleanLogs(0);
1696 Store::Root().sync(); /* Flush log writes */
1699 useragentLogClose();
1706 Store::Root().sync(); /* Flush log close */
1707 StoreFileSystem::FreeAllFs();
1708 DiskIOModule::FreeAllModules();
1709 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1713 /*stmemFreeMemory(); */
1715 ipcacheFreeMemory();
1716 fqdncacheFreeMemory();
1718 clientdbFreeMemory();
1719 httpHeaderCleanModule();
1727 if (opt_no_daemon
) {
1742 xmalloc_find_leaks();
1744 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total
);
1753 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1755 safeunlink(Config
.pidFilename
, 0);
1759 debugs(1, 1, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1763 * We used to fclose(debug_log) here if it was set, but then
1764 * we forgot to set it to NULL. That caused some coredumps
1765 * because exit() ends up calling a bunch of destructors and
1766 * such. So rather than forcing the debug_log to close, we'll
1767 * leave it open so that those destructors can write some
1768 * debugging if necessary. The file will be closed anyway when
1769 * the process truly exits.
1772 exit(shutdown_status
);