2 * DEBUG: section 01 Startup and Main Loop
3 * AUTHOR: Harvest Derived
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "AccessLogEntry.h"
38 #include "base/RunnersRegistry.h"
39 #include "base/Subscription.h"
40 #include "base/TextException.h"
43 #include "client_db.h"
44 #include "client_side.h"
46 #include "ConfigParser.h"
47 #include "CpuAffinity.h"
49 #include "DiskIO/DiskIOModule.h"
50 #include "errorpage.h"
52 #include "EventLoop.h"
53 #include "ExternalACL.h"
55 #include "format/Token.h"
57 #include "fs/Module.h"
58 #include "fqdncache.h"
61 #include "HttpHeader.h"
62 #include "HttpReply.h"
63 #include "icmp/IcmpSquid.h"
64 #include "icmp/net_db.h"
66 #include "ident/Ident.h"
68 #include "ipc/Coordinator.h"
70 #include "ipc/Strand.h"
75 #include "neighbors.h"
77 #include "PeerSelectState.h"
78 #include "peer_sourcehash.h"
79 #include "peer_userhash.h"
80 #include "profiler/Profiler.h"
83 #include "send-announce.h"
84 #include "store_log.h"
86 #include "SquidConfig.h"
88 #include "SquidTime.h"
90 #include "StatCounters.h"
91 #include "StoreFileSystem.h"
101 #include "adaptation/Config.h"
104 #include "adaptation/ecap/Config.h"
107 #include "adaptation/icap/Config.h"
108 #include "adaptation/icap/icap_log.h"
111 #include "auth/Gadgets.h"
114 #include "ClientDelayConfig.h"
117 #include "DelayPools.h"
119 #if USE_LOADABLE_MODULES
120 #include "LoadableModules.h"
123 #include "ssl/certificate_db.h"
126 #include "ssl/helper.h"
127 #include "ssl/context_storage.h"
130 #include "adaptation/icap/Config.h"
133 #include "adaptation/ecap/Config.h"
136 #include "adaptation/Config.h"
139 #include "esi/Module.h"
142 #include "snmp_core.h"
149 #include <sys/wait.h>
155 #if USE_WIN32_SERVICE
158 static int opt_install_service
= FALSE
;
159 static int opt_remove_service
= FALSE
;
160 static int opt_signal_service
= FALSE
;
161 static int opt_command_line
= FALSE
;
162 void WIN32_svcstatusupdate(DWORD
, DWORD
);
163 void WINAPI
WIN32_svcHandler(DWORD
);
166 #if !defined(SQUID_BUILD_INFO)
167 #define SQUID_BUILD_INFO ""
170 static char *opt_syslog_facility
= NULL
;
171 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
172 static int configured_once
= 0;
174 static int malloc_debug_level
= 0;
176 static volatile int do_reconfigure
= 0;
177 static volatile int do_rotate
= 0;
178 static volatile int do_shutdown
= 0;
179 static volatile int shutdown_status
= 0;
181 static int RotateSignal
= -1;
182 static int ReconfigureSignal
= -1;
183 static int ShutdownSignal
= -1;
185 static void mainRotate(void);
186 static void mainReconfigureStart(void);
187 static void mainReconfigureFinish(void*);
188 static void mainInitialize(void);
189 static void usage(void);
190 static void mainParseOptions(int argc
, char *argv
[]);
191 static void sendSignal(void);
192 static void serverConnectionsOpen(void);
193 static void serverConnectionsClose(void);
194 static void watch_child(char **);
195 static void setEffectiveUser(void);
197 void log_trace_done();
198 void log_trace_init(char *);
200 static void SquidShutdown(void);
201 static void mainSetCwd(void);
202 static int checkRunningPid(void);
205 static const char *squid_start_script
= "squid_start";
209 #include "test_access.c"
212 /** temporary thunk across to the unrefactored store interface */
214 class StoreRootEngine
: public AsyncEngine
218 int checkEvents(int timeout
) {
219 Store::Root().callback();
224 class SignalEngine
: public AsyncEngine
228 SignalEngine(EventLoop
&evtLoop
) : loop(evtLoop
) {}
229 virtual int checkEvents(int timeout
);
232 static void StopEventLoop(void * data
) {
233 static_cast<SignalEngine
*>(data
)->loop
.stop();
236 void doShutdown(time_t wait
);
242 SignalEngine::checkEvents(int timeout
)
244 PROF_start(SignalEngine_checkEvents
);
246 if (do_reconfigure
) {
247 mainReconfigureStart();
249 } else if (do_rotate
) {
252 } else if (do_shutdown
) {
253 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
256 BroadcastSignalIfAny(DebugSignal
);
257 BroadcastSignalIfAny(RotateSignal
);
258 BroadcastSignalIfAny(ReconfigureSignal
);
259 BroadcastSignalIfAny(ShutdownSignal
);
261 PROF_stop(SignalEngine_checkEvents
);
266 SignalEngine::doShutdown(time_t wait
)
268 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
269 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
273 #if USE_WIN32_SERVICE
274 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
277 /* run the closure code which can be shared with reconfigure */
278 serverConnectionsClose();
280 /* detach the auth components (only do this on full shutdown) */
281 Auth::Scheme::FreeAll();
283 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
290 #if USE_WIN32_SERVICE
291 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
293 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
295 " -a port Specify HTTP port number (default: %d).\n"
296 " -d level Write debugging to stderr also.\n"
297 " -f file Use given config-file instead of\n"
299 " -h Print help message.\n"
300 #if USE_WIN32_SERVICE
301 " -i Installs as a Windows Service (see -n option).\n"
303 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
304 " Parse configuration file, then send signal to \n"
305 " running copy (except -k parse) and exit.\n"
306 #if USE_WIN32_SERVICE
307 " -n name Specify Windows Service name to use for service operations\n"
308 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
309 " -r Removes a Windows Service (see -n option).\n"
311 " -s | -l facility\n"
312 " Enable logging to syslog.\n"
313 " -u port Specify ICP port number (default: %d), disable with 0.\n"
314 " -v Print version.\n"
315 " -z Create swap directories\n"
316 " -C Do not catch fatal signals.\n"
317 " -D OBSOLETE. Scheduled for removal.\n"
318 " -F Don't serve any requests until store is rebuilt.\n"
319 " -N No daemon mode.\n"
320 #if USE_WIN32_SERVICE
322 " Set Windows Service Command line options in Registry.\n"
324 " -R Do not set REUSEADDR on port.\n"
325 " -S Double-check swap during rebuild.\n"
326 " -X Force full debugging.\n"
327 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
328 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
333 * Parse the parameters received via command line interface.
335 \param argc Number of options received on command line
336 \param argv List of parameters received on command line
339 mainParseOptions(int argc
, char *argv
[])
344 #if USE_WIN32_SERVICE
345 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
347 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
355 * Unset/disabel global option for catchign signals. opt_catch_signals */
356 opt_catch_signals
= 0;
361 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
362 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
367 * Set global option for foreground rebuild. opt_foreground_rebuild */
368 opt_foreground_rebuild
= 1;
373 * Set global option for 'no_daemon' mode. opt_no_daemon */
377 #if USE_WIN32_SERVICE
381 * Set global option. opt_command_lin and WIN32_Command_Line */
382 opt_command_line
= 1;
383 WIN32_Command_Line
= xstrdup(optarg
);
389 * Unset/disable global option opt_reuseaddr */
395 * Set global option opt_store_doublecheck */
396 opt_store_doublecheck
= 1;
401 * Force full debugging */
402 Debug::parseOptions("rotate=0 ALL,9");
403 Debug::override_X
= 1;
404 sigusr2_handle(SIGUSR2
);
409 * Set global option opt_reload_hit_only */
410 opt_reload_hit_only
= 1;
413 #if USE_WIN32_SERVICE
417 * Set global option opt_install_service (to TRUE) */
418 opt_install_service
= TRUE
;
424 * Add optional HTTP port as given following the option */
425 add_http_port(optarg
);
430 * Set global option Debug::log_stderr to the number given follwoign the option */
431 Debug::log_stderr
= atoi(optarg
);
436 * Load the file given instead of the default squid.conf. */
438 ConfigFile
= xstrdup(optarg
);
443 * Run the administrative action given following the option */
445 /** \li When its an unknown option display the usage help. */
446 if ((int) strlen(optarg
) < 1)
449 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
450 /** \li On reconfigure send SIGHUP. */
451 opt_send_signal
= SIGHUP
;
452 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
453 /** \li On rotate send SIGQUIT or SIGUSR1. */
454 #if defined(_SQUID_LINUX_THREADS_)
455 opt_send_signal
= SIGQUIT
;
457 opt_send_signal
= SIGUSR1
;
460 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
461 /** \li On debug send SIGTRAP or SIGUSR2. */
462 #if defined(_SQUID_LINUX_THREADS_)
463 opt_send_signal
= SIGTRAP
;
465 opt_send_signal
= SIGUSR2
;
468 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
469 /** \li On shutdown send SIGTERM. */
470 opt_send_signal
= SIGTERM
;
471 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
472 /** \li On interrupt send SIGINT. */
473 opt_send_signal
= SIGINT
;
474 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
475 /** \li On kill send SIGKILL. */
476 opt_send_signal
= SIGKILL
;
480 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
481 /** \li On restart send SIGTTIN. (exit and restart by parent) */
482 opt_send_signal
= SIGTTIN
;
486 else if (!strncmp(optarg
, "check", strlen(optarg
)))
487 /** \li On check send 0 / SIGNULL. */
488 opt_send_signal
= 0; /* SIGNULL */
489 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
490 /** \li On parse set global flag to re-parse the config file only. */
491 opt_parse_cfg_only
= 1;
499 * Set global malloc_debug_level to the value given following the option.
500 * if none is given it toggles the xmalloc_trace option on/off */
503 malloc_debug_level
= atoi(optarg
);
505 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
510 xmalloc_trace
= !xmalloc_trace
;
512 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
517 #if USE_WIN32_SERVICE
521 * Set global option opt_signal_service (to TRUE).
522 * Stores the additional parameter given in global WIN32_Service_name */
523 xfree(WIN32_Service_name
);
525 WIN32_Service_name
= xstrdup(optarg
);
527 opt_signal_service
= TRUE
;
533 * Set global option opt_remove_service (to TRUE) */
534 opt_remove_service
= TRUE
;
542 * Stores the syslog facility name in global opt_syslog_facility
543 * then performs actions for -s option. */
544 xfree(opt_syslog_facility
); // ignore any previous options sent
545 opt_syslog_facility
= xstrdup(optarg
);
549 * Initialize the syslog for output */
552 _db_set_syslog(opt_syslog_facility
);
558 fatal("Logging to syslog not available on this platform");
565 * Store the ICP port number given in global option icpPortNumOverride
566 * ensuring its a positive number. */
567 icpPortNumOverride
= atoi(optarg
);
569 if (icpPortNumOverride
< 0)
570 icpPortNumOverride
= 0;
576 * Display squid version and build information. Then exit. */
577 printf("Squid Cache: Version %s\n" ,version_string
);
578 if (strlen(SQUID_BUILD_INFO
))
579 printf("%s\n",SQUID_BUILD_INFO
);
580 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
582 #if USE_WIN32_SERVICE
584 printf("Compiled as Windows System Service.\n");
594 * Set global option Debug::log_stderr and opt_create_swap_dirs */
595 Debug::log_stderr
= 1;
596 opt_create_swap_dirs
= 1;
604 /** \par h,?, or unknown
605 * \copydoc usage() */
623 signal(sig
, rotate_logs
);
633 ReconfigureSignal
= sig
;
637 signal(sig
, reconfigure
);
645 do_shutdown
= sig
== SIGINT
? -1 : 1;
646 ShutdownSignal
= sig
;
654 const pid_t ppid
= getppid();
656 if (!IamMasterProcess() && ppid
> 1) {
657 // notify master that we are shutting down
658 if (kill(ppid
, SIGUSR1
) < 0)
659 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
660 " pid " << ppid
<< ": " << xstrerror());
666 if (!IamMasterProcess() && ppid
> 1) {
667 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
669 if (kill(ppid
, sig
) < 0)
670 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
673 #endif /* KILL_PARENT_OPT */
674 #if SA_RESETHAND == 0
675 signal(SIGTERM
, SIG_DFL
);
677 signal(SIGINT
, SIG_DFL
);
684 serverConnectionsOpen(void)
686 if (IamPrimaryProcess()) {
688 wccpConnectionOpen();
693 wccp2ConnectionOpen();
696 // start various proxying services if we are responsible for them
697 if (IamWorkerProcess()) {
698 clientOpenListenSockets();
718 peerSourceHashInit();
723 serverConnectionsClose(void)
725 assert(shutting_down
|| reconfiguring
);
727 if (IamPrimaryProcess()) {
730 wccpConnectionClose();
734 wccp2ConnectionClose();
737 if (IamWorkerProcess()) {
738 clientHttpConnectionsClose();
739 icpConnectionShutdown();
741 htcpSocketShutdown();
754 mainReconfigureStart(void)
756 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
759 // Initiate asynchronous closing sequence
760 serverConnectionsClose();
767 Ssl::Helper::GetInstance()->Shutdown();
770 #if 1 // USE_SSL_CERT_VALIDATOR
771 if (Ssl::CertValidationHelper::GetInstance())
772 Ssl::CertValidationHelper::GetInstance()->Shutdown();
774 Ssl::TheGlobalContextStorage
.reconfigureStart();
780 externalAclShutdown();
781 storeDirCloseSwapLogs();
788 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
793 mainReconfigureFinish(void *)
795 debugs(1, 3, "finishing reconfiguring");
798 enter_suid(); /* root to read config file */
800 // we may have disabled the need for PURGE
801 if (Config2
.onoff
.enable_purge
)
802 Config2
.onoff
.enable_purge
= 2;
804 // parse the config returns a count of errors encountered.
805 const int oldWorkers
= Config
.workers
;
806 if ( parseConfigFile(ConfigFile
) != 0) {
807 // for now any errors are a fatal condition...
810 if (oldWorkers
!= Config
.workers
) {
811 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
812 oldWorkers
<< " to " << Config
.workers
<<
813 ") is not supported and ignored");
814 Config
.workers
= oldWorkers
;
817 if (IamPrimaryProcess())
819 CpuAffinityReconfigure();
821 setUmask(Config
.umask
);
824 _db_init(Debug::cache_log
, Debug::debugOptions
);
825 ipcache_restart(); /* clear stuck entries */
826 fqdncache_restart(); /* sigh, fqdncache too */
828 errorInitialize(); /* reload error pages */
831 #if USE_LOADABLE_MODULES
832 LoadableModulesConfigure(Config
.loadable_module_names
);
836 bool enableAdaptation
= false;
838 Adaptation::Icap::TheConfig
.finalize();
839 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
842 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
843 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
845 Adaptation::Config::Finalize(enableAdaptation
);
854 Ssl::Helper::GetInstance()->Init();
856 #if USE_SSL // && USE_SSL_CERT_VALIDATOR
857 if (Ssl::CertValidationHelper::GetInstance())
858 Ssl::CertValidationHelper::GetInstance()->Init();
863 authenticateInit(&Auth::TheConfig
);
867 if (IamPrimaryProcess()) {
878 serverConnectionsOpen();
882 storeDirOpenSwapLogs();
884 mimeInit(Config
.mimeTablePathname
);
890 Config
.ClientDelay
.finalize();
893 if (Config
.onoff
.announce
) {
894 if (!eventFind(start_announce
, NULL
))
895 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
897 if (eventFind(start_announce
, NULL
))
898 eventDelete(start_announce
, NULL
);
901 writePidFile(); /* write PID file */
915 authenticateRotate();
917 externalAclShutdown();
919 _db_rotate_log(); /* cache.log */
920 storeDirWriteCleanLogs(1);
921 storeLogRotate(); /* store.log */
922 accessLogRotate(); /* access.log */
924 icapLogRotate(); /*icap.log*/
932 authenticateInit(&Auth::TheConfig
);
938 setEffectiveUser(void)
941 leave_suid(); /* Run as non privilegied user */
947 if (geteuid() == 0) {
948 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
949 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
950 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
951 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
952 fatal("Don't run Squid as root, set 'cache_effective_user'!");
959 char pathbuf
[MAXPATHLEN
];
961 if (Config
.coredump_dir
) {
962 if (0 == strcmp("none", Config
.coredump_dir
)) {
964 } else if (chdir(Config
.coredump_dir
) == 0) {
965 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
968 debugs(50, DBG_CRITICAL
, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
972 /* If we don't have coredump_dir or couldn't cd there, report current dir */
973 if (getcwd(pathbuf
, MAXPATHLEN
)) {
974 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
976 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
983 /* chroot if configured to run inside chroot */
985 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
986 fatal("failed to chroot");
989 if (opt_catch_signals
) {
990 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
991 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
994 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
995 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
999 if (icpPortNumOverride
!= 1)
1000 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
1002 _db_init(Debug::cache_log
, Debug::debugOptions
);
1004 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1008 log_trace_init("/tmp/squid.alloc");
1012 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1015 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1016 debugs(1, DBG_CRITICAL
, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
1017 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1019 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1022 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1024 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1027 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1031 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1033 if (WIN32_Socks_initialized
)
1034 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1036 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1037 WIN32_IpAddrChangeMonitorInit();
1042 if (!configured_once
)
1043 disk_init(); /* disk_init must go before ipcache_init() */
1054 Ssl::Helper::GetInstance()->Init();
1057 #if USE_SSL // && USE_SSL_CERT_VALIDATOR
1058 if (Ssl::CertValidationHelper::GetInstance())
1059 Ssl::CertValidationHelper::GetInstance()->Init();
1064 authenticateInit(&Auth::TheConfig
);
1068 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1070 httpReplyInitModule(); /* must go before accepting replies */
1091 malloc_debug(0, malloc_debug_level
);
1095 if (!configured_once
) {
1096 if (unlinkdNeeded())
1103 /* after this point we want to see the mallinfo() output */
1105 mimeInit(Config
.mimeTablePathname
);
1111 FwdState::initModule();
1112 /* register the modules in the cache manager menus */
1114 cbdataRegisterWithCacheManager();
1115 /* These use separate calls so that the comm loops can eventually
1121 // TODO: pconn is a good candidate for new-style registration
1122 // PconnModule::GetInstance()->registerWithCacheManager();
1123 // moved to PconnModule::PconnModule()
1126 if (IamPrimaryProcess()) {
1138 serverConnectionsOpen();
1142 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1144 if (Config
.chroot_dir
)
1147 if (!configured_once
)
1148 writePidFile(); /* write PID file */
1150 #if defined(_SQUID_LINUX_THREADS_)
1152 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1154 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1158 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1160 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1164 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1166 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1168 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1172 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1178 #if USE_LOADABLE_MODULES
1179 LoadableModulesConfigure(Config
.loadable_module_names
);
1183 bool enableAdaptation
= false;
1185 // We can remove this dependency on specific adaptation mechanisms
1186 // if we create a generic Registry of such mechanisms. Should we?
1188 Adaptation::Icap::TheConfig
.finalize();
1189 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1192 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1193 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1195 // must be the last adaptation-related finalize
1196 Adaptation::Config::Finalize(enableAdaptation
);
1204 Config
.ClientDelay
.finalize();
1207 if (!configured_once
) {
1208 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1210 if (Config
.onoff
.announce
)
1211 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1213 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1215 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1219 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1223 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1226 configured_once
= 1;
1229 /// unsafe main routine -- may throw
1230 int SquidMain(int argc
, char **argv
);
1231 /// unsafe main routine wrapper to catch exceptions
1232 static int SquidMainSafe(int argc
, char **argv
);
1234 #if USE_WIN32_SERVICE
1235 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1236 extern "C" void WINAPI
1237 SquidWinSvcMain(int argc
, char **argv
)
1239 SquidMainSafe(argc
, argv
);
1243 main(int argc
, char **argv
)
1245 return SquidMainSafe(argc
, argv
);
1250 SquidMainSafe(int argc
, char **argv
)
1253 return SquidMain(argc
, argv
);
1254 } catch (const std::exception
&e
) {
1255 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1259 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1262 return -1; // not reached
1265 /// computes name and ID for the current kid process
1267 ConfigureCurrentKid(const char *processName
)
1269 // kids are marked with parenthesis around their process names
1270 if (processName
&& processName
[0] == '(') {
1271 if (const char *idStart
= strrchr(processName
, '-')) {
1272 KidIdentifier
= atoi(idStart
+ 1);
1273 const size_t nameLen
= idStart
- (processName
+ 1);
1274 assert(nameLen
< sizeof(TheKidName
));
1275 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1276 if (!strcmp(TheKidName
, "squid-coord"))
1277 TheProcessKind
= pkCoordinator
;
1278 else if (!strcmp(TheKidName
, "squid"))
1279 TheProcessKind
= pkWorker
;
1280 else if (!strcmp(TheKidName
, "squid-disk"))
1281 TheProcessKind
= pkDisker
;
1283 TheProcessKind
= pkOther
; // including coordinator
1286 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1292 SquidMain(int argc
, char **argv
)
1294 ConfigureCurrentKid(argv
[0]);
1297 sbrk_start
= sbrk(0);
1300 Debug::parseOptions(NULL
);
1303 #if defined(SQUID_MAXFD_LIMIT)
1305 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1306 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1310 /* NOP under non-windows */
1311 int WIN32_init_err
=0;
1312 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1313 return WIN32_init_err
;
1315 /* call mallopt() before anything else */
1318 /* Round up all sizes to a multiple of this */
1319 mallopt(M_GRAIN
, 16);
1323 /* biggest size that is considered a small block */
1324 mallopt(M_MXFAST
, 256);
1328 /* allocate this many small blocks at once */
1329 mallopt(M_NLBLKS
, 32);
1332 #endif /* HAVE_MALLOPT */
1334 squid_srandom(time(NULL
));
1338 squid_start
= current_time
;
1340 failure_notify
= fatal_dump
;
1342 #if USE_WIN32_SERVICE
1344 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1348 mainParseOptions(argc
, argv
);
1350 if (opt_parse_cfg_only
) {
1351 Debug::parseOptions("ALL,1");
1354 #if USE_WIN32_SERVICE
1356 if (opt_install_service
) {
1357 WIN32_InstallService();
1361 if (opt_remove_service
) {
1362 WIN32_RemoveService();
1366 if (opt_command_line
) {
1367 WIN32_SetServiceCommandLine();
1373 /* parse configuration file
1374 * note: in "normal" case this used to be called from mainInitialize() */
1379 ConfigFile
= xstrdup(DefaultConfigFile
);
1381 assert(!configured_once
);
1385 storeFsInit(); /* required for config parsing */
1387 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1390 /* May not be needed for parsing, have not audited for such */
1391 DiskIOModule::SetupAllModules();
1393 /* Shouldn't be needed for config parsing, but have not audited for such */
1394 StoreFileSystem::SetupAllFs();
1396 /* we may want the parsing process to set this up in the future */
1397 Store::Root(new StoreController
);
1398 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1399 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1401 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1403 parse_err
= parseConfigFile(ConfigFile
);
1407 if (opt_parse_cfg_only
|| parse_err
> 0)
1410 setUmask(Config
.umask
);
1411 if (-1 == opt_send_signal
)
1412 if (checkRunningPid())
1427 /* send signal to running copy and exit */
1428 if (opt_send_signal
!= -1) {
1429 /* chroot if configured to run inside chroot */
1431 if (Config
.chroot_dir
) {
1432 if (chroot(Config
.chroot_dir
))
1433 fatal("failed to chroot");
1444 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1446 ActivateRegistered(rrFinalizeConfig
);
1447 ActivateRegistered(rrClaimMemoryNeeds
);
1448 ActivateRegistered(rrAfterConfig
);
1451 if (!opt_no_daemon
&& Config
.workers
> 0)
1454 if (opt_create_swap_dirs
) {
1455 /* chroot if configured to run inside chroot */
1457 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1458 fatal("failed to chroot");
1462 debugs(0, DBG_CRITICAL
, "Creating Swap Directories");
1463 Store::Root().create();
1468 if (IamPrimaryProcess())
1474 /* init comm module */
1477 if (opt_no_daemon
) {
1478 /* we have to init fdstat here. */
1479 fd_open(0, FD_LOG
, "stdin");
1480 fd_open(1, FD_LOG
, "stdout");
1481 fd_open(2, FD_LOG
, "stderr");
1484 #if USE_WIN32_SERVICE
1486 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1492 #if USE_WIN32_SERVICE
1494 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1501 SignalEngine
signalEngine(mainLoop
);
1503 mainLoop
.registerEngine(&signalEngine
);
1505 /* TODO: stop requiring the singleton here */
1506 mainLoop
.registerEngine(EventScheduler::GetInstance());
1508 StoreRootEngine store_engine
;
1510 mainLoop
.registerEngine(&store_engine
);
1512 CommSelectEngine comm_engine
;
1514 mainLoop
.registerEngine(&comm_engine
);
1516 mainLoop
.setPrimaryEngine(&comm_engine
);
1518 /* use the standard time service */
1519 TimeEngine time_engine
;
1521 mainLoop
.setTimeService(&time_engine
);
1523 if (IamCoordinatorProcess())
1524 AsyncJob::Start(Ipc::Coordinator::Instance());
1525 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1526 AsyncJob::Start(new Ipc::Strand
);
1528 /* at this point we are finished the synchronous startup. */
1533 if (mainLoop
.errcount
== 10)
1534 fatal_dump("Event loop exited with failure.");
1536 /* shutdown squid now */
1549 if (strcmp(Config
.pidFilename
, "none") == 0) {
1550 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1553 pid
= readPidFile();
1556 #if USE_WIN32_SERVICE
1557 if (opt_signal_service
) {
1558 WIN32_sendSignal(opt_send_signal
);
1561 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1562 fprintf(stderr
, "signal to Squid Service:\n");
1563 fprintf(stderr
, "missing -n command line switch.\n");
1569 if (kill(pid
, opt_send_signal
) &&
1570 /* ignore permissions if just running check */
1571 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1572 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1573 fprintf(stderr
, "signal %d to process %d: %s\n",
1574 opt_send_signal
, (int) pid
, xstrerror());
1578 if (opt_send_signal
!= SIGTERM
) {
1579 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1582 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1587 /* signal successfully sent */
1591 #if !_SQUID_WINDOWS_
1593 * This function is run when Squid is in daemon mode, just
1594 * before the parent forks and starts up the child process.
1595 * It can be used for admin-specific tasks, such as notifying
1596 * someone that Squid is (re)started.
1599 mainStartScript(const char *prog
)
1601 char script
[MAXPATHLEN
];
1606 xstrncpy(script
, prog
, MAXPATHLEN
);
1608 if ((t
= strrchr(script
, '/'))) {
1610 sl
= strlen(script
);
1613 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1615 if ((cpid
= fork()) == 0) {
1617 execl(script
, squid_start_script
, (char *)NULL
);
1623 rpid
= wait4(cpid
, &status
, 0, NULL
);
1627 rpid
= waitpid(cpid
, &status
, 0);
1630 } while (rpid
!= cpid
);
1634 #endif /* _SQUID_WINDOWS_ */
1637 checkRunningPid(void)
1639 // master process must start alone, but its kids processes may co-exist
1640 if (!IamMasterProcess())
1648 pid
= readPidFile();
1653 if (kill(pid
, 0) < 0)
1656 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1662 watch_child(char *argv
[])
1664 #if !_SQUID_WINDOWS_
1682 if (!IamMasterProcess())
1685 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1687 if ((pid
= fork()) < 0)
1688 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1693 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1699 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1700 ioctl(i
, TIOCNOTTY
, NULL
);
1707 * RBCOLLINS - if cygwin stackdumps when squid is run without
1708 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1709 * 1.1.3. execvp had a bit overflow error in a loop..
1711 /* Connect stdio to /dev/null in daemon mode */
1712 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1715 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1719 if (Debug::log_stderr
< 0) {
1724 // handle shutdown notifications from kids
1725 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1727 if (Config
.workers
> 128) {
1728 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1730 // but we keep going in hope that user knows best
1734 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1736 // keep [re]starting kids until it is time to quit
1738 mainStartScript(argv
[0]);
1740 // start each kid that needs to be [re]started; once
1741 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1742 Kid
& kid
= TheKids
.get(i
);
1743 if (!kid
.shouldRestart())
1746 if ((pid
= fork()) == 0) {
1748 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1750 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1752 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1756 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1757 kid
.name().termedBuf(), pid
);
1761 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1763 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1767 pid
= wait3(&status
, 0, NULL
);
1771 pid
= waitpid(-1, &status
, 0);
1774 // Loop to collect all stopped kids before we go to sleep below.
1776 Kid
* kid
= TheKids
.find(pid
);
1779 if (kid
->calledExit()) {
1781 "Squid Parent: %s process %d exited with status %d",
1782 kid
->name().termedBuf(),
1783 kid
->getPid(), kid
->exitStatus());
1784 } else if (kid
->signaled()) {
1786 "Squid Parent: %s process %d exited due to signal %d with status %d",
1787 kid
->name().termedBuf(),
1788 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1790 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1791 kid
->name().termedBuf(), kid
->getPid());
1793 if (kid
->hopeless()) {
1794 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1795 " be restarted due to repeated, frequent failures",
1796 kid
->name().termedBuf(), kid
->getPid());
1799 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1802 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1805 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1808 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1810 DeactivateRegistered(rrAfterConfig
);
1811 DeactivateRegistered(rrClaimMemoryNeeds
);
1812 DeactivateRegistered(rrFinalizeConfig
);
1815 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1816 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1820 if (TheKids
.allHopeless()) {
1821 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1828 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1833 #endif /* _SQUID_WINDOWS_ */
1840 /* XXX: This function is called after the main loop has quit, which
1841 * means that no AsyncCalls would be called, including close handlers.
1842 * TODO: We need to close/shut/free everything that needs calls before
1846 #if USE_WIN32_SERVICE
1847 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1850 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1853 Ssl::Helper::GetInstance()->Shutdown();
1855 #if USE_SSL //&& USE_SSL_CERT_VALIDATOR
1856 if (Ssl::CertValidationHelper::GetInstance())
1857 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1860 externalAclShutdown();
1870 wccpConnectionClose();
1874 wccp2ConnectionClose();
1877 releaseServerSockets();
1878 commCloseAllSockets();
1885 DelayPools::FreePools();
1888 authenticateReset();
1890 #if USE_WIN32_SERVICE
1892 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1895 Store::Root().sync(); /* Flush pending object writes/unlinks */
1897 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1899 storeDirWriteCleanLogs(0);
1902 Store::Root().sync(); /* Flush log writes */
1905 Store::Root().sync(); /* Flush log close */
1906 StoreFileSystem::FreeAllFs();
1907 DiskIOModule::FreeAllModules();
1908 DeactivateRegistered(rrAfterConfig
);
1909 DeactivateRegistered(rrClaimMemoryNeeds
);
1910 DeactivateRegistered(rrFinalizeConfig
);
1911 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1915 /*stmemFreeMemory(); */
1917 ipcacheFreeMemory();
1918 fqdncacheFreeMemory();
1920 clientdbFreeMemory();
1921 httpHeaderCleanModule();
1929 if (opt_no_daemon
) {
1936 // clear StoreController
1947 xmalloc_find_leaks();
1949 debugs(1, DBG_CRITICAL
, "Memory used after shutdown: " << xmalloc_total
);
1958 if (IamPrimaryProcess()) {
1959 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1961 safeunlink(Config
.pidFilename
, 0);
1966 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1970 * We used to fclose(debug_log) here if it was set, but then
1971 * we forgot to set it to NULL. That caused some coredumps
1972 * because exit() ends up calling a bunch of destructors and
1973 * such. So rather than forcing the debug_log to close, we'll
1974 * leave it open so that those destructors can write some
1975 * debugging if necessary. The file will be closed anyway when
1976 * the process truly exits.
1979 exit(shutdown_status
);