2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 01 Startup and Main Loop */
12 #include "AccessLogEntry.h"
16 #include "base/RunnersRegistry.h"
17 #include "base/Subscription.h"
18 #include "base/TextException.h"
21 #include "client_db.h"
22 #include "client_side.h"
24 #include "ConfigParser.h"
25 #include "CpuAffinity.h"
27 #include "DiskIO/DiskIOModule.h"
28 #include "errorpage.h"
30 #include "EventLoop.h"
31 #include "ExternalACL.h"
33 #include "format/Token.h"
34 #include "fqdncache.h"
35 #include "fs/Module.h"
39 #include "HttpHeader.h"
40 #include "HttpReply.h"
41 #include "icmp/IcmpSquid.h"
42 #include "icmp/net_db.h"
44 #include "ident/Ident.h"
46 #include "ipc/Coordinator.h"
48 #include "ipc/Strand.h"
51 #include "neighbors.h"
52 #include "parser/Tokenizer.h"
54 #include "peer_sourcehash.h"
55 #include "peer_userhash.h"
56 #include "PeerSelectState.h"
57 #include "profiler/Profiler.h"
60 #include "send-announce.h"
61 #include "SquidConfig.h"
63 #include "SquidTime.h"
65 #include "StatCounters.h"
67 #include "store_log.h"
68 #include "StoreFileSystem.h"
78 #include "adaptation/Config.h"
81 #include "adaptation/ecap/Config.h"
84 #include "adaptation/icap/Config.h"
85 #include "adaptation/icap/icap_log.h"
88 #include "auth/Gadgets.h"
91 #include "ClientDelayConfig.h"
94 #include "DelayPools.h"
96 #if USE_LOADABLE_MODULES
97 #include "LoadableModules.h"
100 #include "ssl/certificate_db.h"
103 #include "ssl/context_storage.h"
104 #include "ssl/helper.h"
107 #include "adaptation/icap/Config.h"
110 #include "adaptation/ecap/Config.h"
113 #include "adaptation/Config.h"
116 #include "esi/Module.h"
119 #include "snmp_core.h"
130 #include <sys/wait.h>
133 #if USE_WIN32_SERVICE
136 static int opt_install_service
= FALSE
;
137 static int opt_remove_service
= FALSE
;
138 static int opt_command_line
= FALSE
;
139 void WIN32_svcstatusupdate(DWORD
, DWORD
);
140 void WINAPI
WIN32_svcHandler(DWORD
);
143 static int opt_signal_service
= FALSE
;
144 static char *opt_syslog_facility
= NULL
;
145 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
146 static int configured_once
= 0;
148 static int malloc_debug_level
= 0;
150 static volatile int do_reconfigure
= 0;
151 static volatile int do_rotate
= 0;
152 static volatile int do_shutdown
= 0;
153 static volatile int shutdown_status
= 0;
155 static int RotateSignal
= -1;
156 static int ReconfigureSignal
= -1;
157 static int ShutdownSignal
= -1;
159 static void mainRotate(void);
160 static void mainReconfigureStart(void);
161 static void mainReconfigureFinish(void*);
162 static void mainInitialize(void);
163 static void usage(void);
164 static void mainParseOptions(int argc
, char *argv
[]);
165 static void sendSignal(void);
166 static void serverConnectionsOpen(void);
167 static void serverConnectionsClose(void);
168 static void watch_child(char **);
169 static void setEffectiveUser(void);
170 static void SquidShutdown(void);
171 static void mainSetCwd(void);
172 static int checkRunningPid(void);
175 static const char *squid_start_script
= "squid_start";
179 #include "test_access.c"
182 /** temporary thunk across to the unrefactored store interface */
184 class StoreRootEngine
: public AsyncEngine
188 int checkEvents(int timeout
) {
189 Store::Root().callback();
194 class SignalEngine
: public AsyncEngine
198 virtual int checkEvents(int timeout
);
201 static void StopEventLoop(void *) {
202 if (EventLoop::Running
)
203 EventLoop::Running
->stop();
206 void doShutdown(time_t wait
);
210 SignalEngine::checkEvents(int timeout
)
212 PROF_start(SignalEngine_checkEvents
);
214 if (do_reconfigure
) {
215 mainReconfigureStart();
217 } else if (do_rotate
) {
220 } else if (do_shutdown
) {
221 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
224 BroadcastSignalIfAny(DebugSignal
);
225 BroadcastSignalIfAny(RotateSignal
);
226 BroadcastSignalIfAny(ReconfigureSignal
);
227 BroadcastSignalIfAny(ShutdownSignal
);
229 PROF_stop(SignalEngine_checkEvents
);
234 SignalEngine::doShutdown(time_t wait
)
236 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
237 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
241 #if USE_WIN32_SERVICE
242 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
245 /* run the closure code which can be shared with reconfigure */
246 serverConnectionsClose();
248 /* detach the auth components (only do this on full shutdown) */
249 Auth::Scheme::FreeAll();
252 RunRegisteredHere(RegisteredRunner::startShutdown
);
253 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
260 "Usage: %s [-cdzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
261 #if USE_WIN32_SERVICE
262 "[-ir] [-O CommandLine]"
265 " -h | --help Print help message.\n"
266 " -v | --version Print version details.\n"
268 " -a port Specify HTTP port number (default: %d).\n"
269 " -d level Write debugging to stderr also.\n"
270 " -f file Use given config-file instead of\n"
272 #if USE_WIN32_SERVICE
273 " -i Installs as a Windows Service (see -n option).\n"
275 " -k reconfigure|rotate|shutdown|"
279 "interrupt|kill|debug|check|parse\n"
280 " Parse configuration file, then send signal to \n"
281 " running copy (except -k parse) and exit.\n"
282 " -n name Specify service name to use for service operations\n"
283 " default is: " APP_SHORTNAME
".\n"
284 #if USE_WIN32_SERVICE
285 " -r Removes a Windows Service (see -n option).\n"
287 " -s | -l facility\n"
288 " Enable logging to syslog.\n"
289 " -u port Specify ICP port number (default: %d), disable with 0.\n"
290 " -z Create missing swap directories and then exit.\n"
291 " -C Do not catch fatal signals.\n"
292 " -D OBSOLETE. Scheduled for removal.\n"
293 " -F Don't serve any requests until store is rebuilt.\n"
294 " -N No daemon mode.\n"
295 #if USE_WIN32_SERVICE
297 " Set Windows Service Command line options in Registry.\n"
299 " -R Do not set REUSEADDR on port.\n"
300 " -S Double-check swap during rebuild.\n"
301 " -X Force full debugging.\n"
302 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
303 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
308 * Parse the parameters received via command line interface.
310 * \param argc Number of options received on command line
311 * \param argv List of parameters received on command line
314 mainParseOptions(int argc
, char *argv
[])
319 const char *shortOpStr
=
320 #if USE_WIN32_SERVICE
323 "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?";
326 static struct option squidOptions
[] = {
327 {"help", no_argument
, 0, 'h'},
328 {"version", no_argument
, 0, 'v'},
333 while ((c
= getopt_long(argc
, argv
, shortOpStr
, squidOptions
, &optIndex
)) != -1) {
339 * Unset/disabel global option for catchign signals. opt_catch_signals */
340 opt_catch_signals
= 0;
345 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
346 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
351 * Set global option for foreground rebuild. opt_foreground_rebuild */
352 opt_foreground_rebuild
= 1;
357 * Set global option for 'no_daemon' mode. opt_no_daemon */
361 #if USE_WIN32_SERVICE
365 * Set global option. opt_command_lin and WIN32_Command_Line */
366 opt_command_line
= 1;
367 WIN32_Command_Line
= xstrdup(optarg
);
373 * Unset/disable global option opt_reuseaddr */
379 * Set global option opt_store_doublecheck */
380 opt_store_doublecheck
= 1;
385 * Force full debugging */
386 Debug::parseOptions("rotate=0 ALL,9");
387 Debug::override_X
= 1;
388 sigusr2_handle(SIGUSR2
);
393 * Set global option opt_reload_hit_only */
394 opt_reload_hit_only
= 1;
397 #if USE_WIN32_SERVICE
401 * Set global option opt_install_service (to TRUE) */
402 opt_install_service
= TRUE
;
408 * Add optional HTTP port as given following the option */
409 add_http_port(optarg
);
414 * Set global option Debug::log_stderr to the number given following the option */
415 Debug::log_stderr
= atoi(optarg
);
420 * Load the file given instead of the default squid.conf. */
422 ConfigFile
= xstrdup(optarg
);
427 * Run the administrative action given following the option */
429 /** \li When its an unknown option display the usage help. */
430 if ((int) strlen(optarg
) < 1)
433 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
434 /** \li On reconfigure send SIGHUP. */
435 opt_send_signal
= SIGHUP
;
436 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
437 /** \li On rotate send SIGQUIT or SIGUSR1. */
438 #if defined(_SQUID_LINUX_THREADS_)
439 opt_send_signal
= SIGQUIT
;
441 opt_send_signal
= SIGUSR1
;
444 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
445 /** \li On debug send SIGTRAP or SIGUSR2. */
446 #if defined(_SQUID_LINUX_THREADS_)
447 opt_send_signal
= SIGTRAP
;
449 opt_send_signal
= SIGUSR2
;
452 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
453 /** \li On shutdown send SIGTERM. */
454 opt_send_signal
= SIGTERM
;
455 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
456 /** \li On interrupt send SIGINT. */
457 opt_send_signal
= SIGINT
;
458 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
459 /** \li On kill send SIGKILL. */
460 opt_send_signal
= SIGKILL
;
464 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
465 /** \li On restart send SIGTTIN. (exit and restart by parent) */
466 opt_send_signal
= SIGTTIN
;
470 else if (!strncmp(optarg
, "check", strlen(optarg
)))
471 /** \li On check send 0 / SIGNULL. */
472 opt_send_signal
= 0; /* SIGNULL */
473 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
474 /** \li On parse set global flag to re-parse the config file only. */
475 opt_parse_cfg_only
= 1;
483 * Set global malloc_debug_level to the value given following the option.
484 * if none is given it toggles the xmalloc_trace option on/off */
487 malloc_debug_level
= atoi(optarg
);
489 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
497 * Set global option opt_signal_service (to true).
498 * Stores the additional parameter given in global service_name */
499 if (optarg
&& *optarg
!= '\0') {
500 const SBuf
t(optarg
);
501 ::Parser::Tokenizer
tok(t
);
502 const CharacterSet chr
= CharacterSet::ALPHA
+CharacterSet::DIGIT
;
503 if (!tok
.prefix(service_name
, chr
))
504 fatalf("Expected alphanumeric service name for the -n option but got: %s", optarg
);
506 fatalf("Garbage after alphanumeric service name in the -n option value: %s", optarg
);
507 if (service_name
.length() > 32)
508 fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name
.length());
509 opt_signal_service
= true;
511 fatal("A service name is required for the -n option");
515 #if USE_WIN32_SERVICE
519 * Set global option opt_remove_service (to TRUE) */
520 opt_remove_service
= TRUE
;
528 * Stores the syslog facility name in global opt_syslog_facility
529 * then performs actions for -s option. */
530 xfree(opt_syslog_facility
); // ignore any previous options sent
531 opt_syslog_facility
= xstrdup(optarg
);
535 * Initialize the syslog for output */
538 _db_set_syslog(opt_syslog_facility
);
544 fatal("Logging to syslog not available on this platform");
551 * Store the ICP port number given in global option icpPortNumOverride
552 * ensuring its a positive number. */
553 icpPortNumOverride
= atoi(optarg
);
555 if (icpPortNumOverride
< 0)
556 icpPortNumOverride
= 0;
562 * Display squid version and build information. Then exit. */
563 printf("Squid Cache: Version %s\n" ,version_string
);
564 printf("Service Name: " SQUIDSBUFPH
"\n", SQUIDSBUFPRINT(service_name
));
565 if (strlen(SQUID_BUILD_INFO
))
566 printf("%s\n",SQUID_BUILD_INFO
);
567 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
569 #if USE_WIN32_SERVICE
571 printf("Compiled as Windows System Service.\n");
581 * Set global option Debug::log_stderr and opt_create_swap_dirs */
582 Debug::log_stderr
= 1;
583 opt_create_swap_dirs
= 1;
591 /** \par h,?, or unknown
592 * \copydoc usage() */
610 signal(sig
, rotate_logs
);
620 ReconfigureSignal
= sig
;
624 signal(sig
, reconfigure
);
632 do_shutdown
= sig
== SIGINT
? -1 : 1;
633 ShutdownSignal
= sig
;
640 const pid_t ppid
= getppid();
642 if (!IamMasterProcess() && ppid
> 1) {
643 // notify master that we are shutting down
644 if (kill(ppid
, SIGUSR1
) < 0)
645 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
646 " pid " << ppid
<< ": " << xstrerror());
650 if (!IamMasterProcess() && ppid
> 1) {
651 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
653 if (kill(ppid
, sig
) < 0)
654 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
656 #endif /* KILL_PARENT_OPT */
658 #if SA_RESETHAND == 0
659 signal(SIGTERM
, SIG_DFL
);
661 signal(SIGINT
, SIG_DFL
);
668 serverConnectionsOpen(void)
670 if (IamPrimaryProcess()) {
672 wccpConnectionOpen();
677 wccp2ConnectionOpen();
680 // start various proxying services if we are responsible for them
681 if (IamWorkerProcess()) {
682 clientOpenListenSockets();
701 peerSourceHashInit();
706 serverConnectionsClose(void)
708 assert(shutting_down
|| reconfiguring
);
710 if (IamPrimaryProcess()) {
713 wccpConnectionClose();
717 wccp2ConnectionClose();
720 if (IamWorkerProcess()) {
721 clientConnectionsClose();
722 icpConnectionShutdown();
724 htcpSocketShutdown();
737 mainReconfigureStart(void)
739 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
742 // Initiate asynchronous closing sequence
743 serverConnectionsClose();
750 Ssl::Helper::GetInstance()->Shutdown();
753 if (Ssl::CertValidationHelper::GetInstance())
754 Ssl::CertValidationHelper::GetInstance()->Shutdown();
755 Ssl::TheGlobalContextStorage
.reconfigureStart();
761 externalAclShutdown();
762 storeDirCloseSwapLogs();
769 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
774 mainReconfigureFinish(void *)
776 debugs(1, 3, "finishing reconfiguring");
779 enter_suid(); /* root to read config file */
781 // we may have disabled the need for PURGE
782 if (Config2
.onoff
.enable_purge
)
783 Config2
.onoff
.enable_purge
= 2;
785 // parse the config returns a count of errors encountered.
786 const int oldWorkers
= Config
.workers
;
787 if ( parseConfigFile(ConfigFile
) != 0) {
788 // for now any errors are a fatal condition...
791 if (oldWorkers
!= Config
.workers
) {
792 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
793 oldWorkers
<< " to " << Config
.workers
<<
794 ") requires a full restart. It has been ignored by reconfigure.");
795 Config
.workers
= oldWorkers
;
798 RunRegisteredHere(RegisteredRunner::syncConfig
);
800 if (IamPrimaryProcess())
802 CpuAffinityReconfigure();
804 setUmask(Config
.umask
);
807 _db_init(Debug::cache_log
, Debug::debugOptions
);
808 ipcache_restart(); /* clear stuck entries */
809 fqdncache_restart(); /* sigh, fqdncache too */
811 errorInitialize(); /* reload error pages */
814 #if USE_LOADABLE_MODULES
815 LoadableModulesConfigure(Config
.loadable_module_names
);
819 bool enableAdaptation
= false;
821 Adaptation::Icap::TheConfig
.finalize();
822 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
825 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
826 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
828 Adaptation::Config::Finalize(enableAdaptation
);
837 Ssl::Helper::GetInstance()->Init();
840 if (Ssl::CertValidationHelper::GetInstance())
841 Ssl::CertValidationHelper::GetInstance()->Init();
846 authenticateInit(&Auth::TheConfig
);
850 if (IamPrimaryProcess()) {
861 serverConnectionsOpen();
865 storeDirOpenSwapLogs();
867 mimeInit(Config
.mimeTablePathname
);
873 Config
.ClientDelay
.finalize();
876 if (Config
.onoff
.announce
) {
877 if (!eventFind(start_announce
, NULL
))
878 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
880 if (eventFind(start_announce
, NULL
))
881 eventDelete(start_announce
, NULL
);
884 writePidFile(); /* write PID file */
895 authenticateRotate();
897 externalAclShutdown();
899 _db_rotate_log(); /* cache.log */
900 storeDirWriteCleanLogs(1);
901 storeLogRotate(); /* store.log */
902 accessLogRotate(); /* access.log */
904 icapLogRotate(); /*icap.log*/
909 authenticateInit(&Auth::TheConfig
);
915 setEffectiveUser(void)
918 leave_suid(); /* Run as non privilegied user */
924 if (geteuid() == 0) {
925 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
926 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
927 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
928 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
929 fatal("Don't run Squid as root, set 'cache_effective_user'!");
933 /// changes working directory, providing error reporting
935 mainChangeDir(const char *dir
)
940 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
941 ": " << xstrerror());
945 /// set the working directory.
949 static bool chrooted
= false;
950 if (Config
.chroot_dir
&& !chrooted
) {
953 if (chroot(Config
.chroot_dir
) != 0)
954 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
956 if (!mainChangeDir("/"))
957 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
960 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
961 if (mainChangeDir(Config
.coredump_dir
)) {
962 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
967 /* If we don't have coredump_dir or couldn't cd there, report current dir */
968 char pathbuf
[MAXPATHLEN
];
969 if (getcwd(pathbuf
, MAXPATHLEN
)) {
970 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
972 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
979 /* chroot if configured to run inside chroot */
982 if (opt_catch_signals
) {
983 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
984 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
987 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
988 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
992 if (icpPortNumOverride
!= 1)
993 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
995 _db_init(Debug::cache_log
, Debug::debugOptions
);
997 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
999 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1000 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1003 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1004 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1006 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1009 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1011 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1014 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1018 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1020 if (WIN32_Socks_initialized
)
1021 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1023 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1024 WIN32_IpAddrChangeMonitorInit();
1029 if (!configured_once
)
1030 disk_init(); /* disk_init must go before ipcache_init() */
1041 Ssl::Helper::GetInstance()->Init();
1045 if (!configured_once
)
1046 Ssl::initialize_session_cache();
1048 if (Ssl::CertValidationHelper::GetInstance())
1049 Ssl::CertValidationHelper::GetInstance()->Init();
1054 authenticateInit(&Auth::TheConfig
);
1058 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1060 httpReplyInitModule(); /* must go before accepting replies */
1081 malloc_debug(0, malloc_debug_level
);
1085 if (!configured_once
) {
1086 if (unlinkdNeeded())
1093 mimeInit(Config
.mimeTablePathname
);
1099 FwdState::initModule();
1100 /* register the modules in the cache manager menus */
1102 cbdataRegisterWithCacheManager();
1103 /* These use separate calls so that the comm loops can eventually
1109 // TODO: pconn is a good candidate for new-style registration
1110 // PconnModule::GetInstance()->registerWithCacheManager();
1111 // moved to PconnModule::PconnModule()
1114 if (IamPrimaryProcess()) {
1126 serverConnectionsOpen();
1130 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1132 if (Config
.chroot_dir
)
1135 if (!configured_once
)
1136 writePidFile(); /* write PID file */
1138 #if defined(_SQUID_LINUX_THREADS_)
1140 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1142 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1146 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1148 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1152 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1154 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1156 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1160 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1166 #if USE_LOADABLE_MODULES
1167 LoadableModulesConfigure(Config
.loadable_module_names
);
1171 bool enableAdaptation
= false;
1173 // We can remove this dependency on specific adaptation mechanisms
1174 // if we create a generic Registry of such mechanisms. Should we?
1176 Adaptation::Icap::TheConfig
.finalize();
1177 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1180 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1181 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1183 // must be the last adaptation-related finalize
1184 Adaptation::Config::Finalize(enableAdaptation
);
1192 Config
.ClientDelay
.finalize();
1195 if (!configured_once
) {
1196 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1198 if (Config
.onoff
.announce
)
1199 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1201 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1203 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1207 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1211 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1214 configured_once
= 1;
1217 /// unsafe main routine -- may throw
1218 int SquidMain(int argc
, char **argv
);
1219 /// unsafe main routine wrapper to catch exceptions
1220 static int SquidMainSafe(int argc
, char **argv
);
1222 #if USE_WIN32_SERVICE
1223 /* Entry point for Windows services */
1224 extern "C" void WINAPI
1225 SquidWinSvcMain(int argc
, char **argv
)
1227 SquidMainSafe(argc
, argv
);
1232 main(int argc
, char **argv
)
1234 #if USE_WIN32_SERVICE
1235 SetErrorMode(SEM_NOGPFAULTERRORBOX
);
1236 if ((argc
== 2) && strstr(argv
[1], _WIN_SQUID_SERVICE_OPTION
))
1237 return WIN32_StartService(argc
, argv
);
1239 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_INTERACTIVE
;
1244 return SquidMainSafe(argc
, argv
);
1248 SquidMainSafe(int argc
, char **argv
)
1251 return SquidMain(argc
, argv
);
1252 } catch (const std::exception
&e
) {
1253 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1257 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1260 return -1; // not reached
1263 /// computes name and ID for the current kid process
1265 ConfigureCurrentKid(const char *processName
)
1267 // kids are marked with parenthesis around their process names
1268 if (processName
&& processName
[0] == '(') {
1269 if (const char *idStart
= strrchr(processName
, '-')) {
1270 KidIdentifier
= atoi(idStart
+ 1);
1271 const size_t nameLen
= idStart
- (processName
+ 1);
1272 assert(nameLen
< sizeof(TheKidName
));
1273 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1274 if (!strcmp(TheKidName
, "squid-coord"))
1275 TheProcessKind
= pkCoordinator
;
1276 else if (!strcmp(TheKidName
, "squid"))
1277 TheProcessKind
= pkWorker
;
1278 else if (!strcmp(TheKidName
, "squid-disk"))
1279 TheProcessKind
= pkDisker
;
1281 TheProcessKind
= pkOther
; // including coordinator
1284 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1290 SquidMain(int argc
, char **argv
)
1292 ConfigureCurrentKid(argv
[0]);
1294 Debug::parseOptions(NULL
);
1297 #if defined(SQUID_MAXFD_LIMIT)
1299 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1300 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1304 /* NOP under non-windows */
1305 int WIN32_init_err
=0;
1306 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1307 return WIN32_init_err
;
1309 /* call mallopt() before anything else */
1312 /* Round up all sizes to a multiple of this */
1313 mallopt(M_GRAIN
, 16);
1317 /* biggest size that is considered a small block */
1318 mallopt(M_MXFAST
, 256);
1322 /* allocate this many small blocks at once */
1323 mallopt(M_NLBLKS
, 32);
1326 #endif /* HAVE_MALLOPT */
1328 squid_srandom(time(NULL
));
1332 squid_start
= current_time
;
1334 failure_notify
= fatal_dump
;
1336 #if USE_WIN32_SERVICE
1338 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1342 mainParseOptions(argc
, argv
);
1344 if (opt_parse_cfg_only
) {
1345 Debug::parseOptions("ALL,1");
1348 #if USE_WIN32_SERVICE
1350 if (opt_install_service
) {
1351 WIN32_InstallService();
1355 if (opt_remove_service
) {
1356 WIN32_RemoveService();
1360 if (opt_command_line
) {
1361 WIN32_SetServiceCommandLine();
1367 /* parse configuration file
1368 * note: in "normal" case this used to be called from mainInitialize() */
1373 ConfigFile
= xstrdup(DefaultConfigFile
);
1375 assert(!configured_once
);
1379 storeFsInit(); /* required for config parsing */
1381 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1384 /* May not be needed for parsing, have not audited for such */
1385 DiskIOModule::SetupAllModules();
1387 /* Shouldn't be needed for config parsing, but have not audited for such */
1388 StoreFileSystem::SetupAllFs();
1390 /* we may want the parsing process to set this up in the future */
1391 Store::Root(new StoreController
);
1392 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1393 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1395 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1397 parse_err
= parseConfigFile(ConfigFile
);
1401 if (opt_parse_cfg_only
|| parse_err
> 0)
1404 setUmask(Config
.umask
);
1405 if (-1 == opt_send_signal
)
1406 if (checkRunningPid())
1421 /* send signal to running copy and exit */
1422 if (opt_send_signal
!= -1) {
1423 /* chroot if configured to run inside chroot */
1425 if (Config
.chroot_dir
) {
1435 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1437 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1438 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1439 RunRegisteredHere(RegisteredRunner::useConfig
);
1442 if (!opt_no_daemon
&& Config
.workers
> 0)
1445 if (opt_create_swap_dirs
) {
1446 /* chroot if configured to run inside chroot */
1450 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1451 Store::Root().create();
1456 if (IamPrimaryProcess())
1462 /* init comm module */
1465 if (opt_no_daemon
) {
1466 /* we have to init fdstat here. */
1467 fd_open(0, FD_LOG
, "stdin");
1468 fd_open(1, FD_LOG
, "stdout");
1469 fd_open(2, FD_LOG
, "stderr");
1472 #if USE_WIN32_SERVICE
1474 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1480 #if USE_WIN32_SERVICE
1482 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1489 SignalEngine signalEngine
;
1491 mainLoop
.registerEngine(&signalEngine
);
1493 /* TODO: stop requiring the singleton here */
1494 mainLoop
.registerEngine(EventScheduler::GetInstance());
1496 StoreRootEngine store_engine
;
1498 mainLoop
.registerEngine(&store_engine
);
1500 CommSelectEngine comm_engine
;
1502 mainLoop
.registerEngine(&comm_engine
);
1504 mainLoop
.setPrimaryEngine(&comm_engine
);
1506 /* use the standard time service */
1507 TimeEngine time_engine
;
1509 mainLoop
.setTimeService(&time_engine
);
1511 if (IamCoordinatorProcess())
1512 AsyncJob::Start(Ipc::Coordinator::Instance());
1513 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1514 AsyncJob::Start(new Ipc::Strand
);
1516 /* at this point we are finished the synchronous startup. */
1521 if (mainLoop
.errcount
== 10)
1522 fatal_dump("Event loop exited with failure.");
1524 /* shutdown squid now */
1537 if (strcmp(Config
.pidFilename
, "none") == 0) {
1538 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1541 pid
= readPidFile();
1544 #if USE_WIN32_SERVICE
1545 if (opt_signal_service
) {
1546 WIN32_sendSignal(opt_send_signal
);
1549 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1550 fprintf(stderr
, "signal to Squid Service:\n");
1551 fprintf(stderr
, "missing -n command line switch.\n");
1557 if (kill(pid
, opt_send_signal
) &&
1558 /* ignore permissions if just running check */
1559 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1560 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1561 fprintf(stderr
, "signal %d to process %d: %s\n",
1562 opt_send_signal
, (int) pid
, xstrerror());
1566 if (opt_send_signal
!= SIGTERM
) {
1567 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1570 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1575 /* signal successfully sent */
1579 #if !_SQUID_WINDOWS_
1581 * This function is run when Squid is in daemon mode, just
1582 * before the parent forks and starts up the child process.
1583 * It can be used for admin-specific tasks, such as notifying
1584 * someone that Squid is (re)started.
1587 mainStartScript(const char *prog
)
1589 char script
[MAXPATHLEN
];
1594 xstrncpy(script
, prog
, MAXPATHLEN
);
1596 if ((t
= strrchr(script
, '/'))) {
1598 sl
= strlen(script
);
1601 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1603 if ((cpid
= fork()) == 0) {
1605 execl(script
, squid_start_script
, (char *)NULL
);
1611 rpid
= wait4(cpid
, &status
, 0, NULL
);
1615 rpid
= waitpid(cpid
, &status
, 0);
1618 } while (rpid
!= cpid
);
1622 #endif /* _SQUID_WINDOWS_ */
1625 checkRunningPid(void)
1627 // master process must start alone, but its kids processes may co-exist
1628 if (!IamMasterProcess())
1636 pid
= readPidFile();
1641 if (kill(pid
, 0) < 0)
1644 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1650 watch_child(char *argv
[])
1652 #if !_SQUID_WINDOWS_
1670 if (!IamMasterProcess())
1673 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1675 if ((pid
= fork()) < 0)
1676 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1681 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1687 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1688 ioctl(i
, TIOCNOTTY
, NULL
);
1695 * RBCOLLINS - if cygwin stackdumps when squid is run without
1696 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1697 * 1.1.3. execvp had a bit overflow error in a loop..
1699 /* Connect stdio to /dev/null in daemon mode */
1700 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1703 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1707 if (Debug::log_stderr
< 0) {
1712 // handle shutdown notifications from kids
1713 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1715 if (Config
.workers
> 128) {
1716 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1718 // but we keep going in hope that user knows best
1722 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1724 // keep [re]starting kids until it is time to quit
1726 mainStartScript(argv
[0]);
1728 // start each kid that needs to be [re]started; once
1729 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1730 Kid
& kid
= TheKids
.get(i
);
1731 if (!kid
.shouldRestart())
1734 if ((pid
= fork()) == 0) {
1736 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1738 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1740 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1744 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1745 kid
.name().termedBuf(), pid
);
1749 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1751 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1755 pid
= wait3(&status
, 0, NULL
);
1759 pid
= waitpid(-1, &status
, 0);
1762 // Loop to collect all stopped kids before we go to sleep below.
1764 Kid
* kid
= TheKids
.find(pid
);
1767 if (kid
->calledExit()) {
1769 "Squid Parent: %s process %d exited with status %d",
1770 kid
->name().termedBuf(),
1771 kid
->getPid(), kid
->exitStatus());
1772 } else if (kid
->signaled()) {
1774 "Squid Parent: %s process %d exited due to signal %d with status %d",
1775 kid
->name().termedBuf(),
1776 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1778 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1779 kid
->name().termedBuf(), kid
->getPid());
1781 if (kid
->hopeless()) {
1782 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1783 " be restarted due to repeated, frequent failures",
1784 kid
->name().termedBuf(), kid
->getPid());
1787 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1790 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1793 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1796 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1798 // XXX: Master process has no main loop and, hence, should not call
1799 // RegisteredRunner::startShutdown which promises a loop iteration.
1800 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1803 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1804 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1808 if (TheKids
.allHopeless()) {
1809 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1816 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1821 #endif /* _SQUID_WINDOWS_ */
1828 /* XXX: This function is called after the main loop has quit, which
1829 * means that no AsyncCalls would be called, including close handlers.
1830 * TODO: We need to close/shut/free everything that needs calls before
1834 #if USE_WIN32_SERVICE
1835 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1838 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1841 Ssl::Helper::GetInstance()->Shutdown();
1844 if (Ssl::CertValidationHelper::GetInstance())
1845 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1848 externalAclShutdown();
1858 wccpConnectionClose();
1862 wccp2ConnectionClose();
1865 releaseServerSockets();
1866 commCloseAllSockets();
1873 DelayPools::FreePools();
1876 authenticateReset();
1878 #if USE_WIN32_SERVICE
1880 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1883 Store::Root().sync(); /* Flush pending object writes/unlinks */
1885 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1887 storeDirWriteCleanLogs(0);
1890 Store::Root().sync(); /* Flush log writes */
1893 Store::Root().sync(); /* Flush log close */
1894 StoreFileSystem::FreeAllFs();
1895 DiskIOModule::FreeAllModules();
1896 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1900 /*stmemFreeMemory(); */
1902 ipcacheFreeMemory();
1903 fqdncacheFreeMemory();
1905 clientdbFreeMemory();
1906 httpHeaderCleanModule();
1912 // clear StoreController
1919 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1923 if (IamPrimaryProcess()) {
1924 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1926 safeunlink(Config
.pidFilename
, 0);
1931 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1935 * We used to fclose(debug_log) here if it was set, but then
1936 * we forgot to set it to NULL. That caused some coredumps
1937 * because exit() ends up calling a bunch of destructors and
1938 * such. So rather than forcing the debug_log to close, we'll
1939 * leave it open so that those destructors can write some
1940 * debugging if necessary. The file will be closed anyway when
1941 * the process truly exits.
1944 exit(shutdown_status
);