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"
53 #include "neighbors.h"
54 #include "parser/Tokenizer.h"
56 #include "peer_sourcehash.h"
57 #include "peer_userhash.h"
58 #include "PeerSelectState.h"
59 #include "profiler/Profiler.h"
62 #include "send-announce.h"
63 #include "SquidConfig.h"
65 #include "SquidTime.h"
67 #include "StatCounters.h"
69 #include "store_log.h"
70 #include "StoreFileSystem.h"
80 #include "adaptation/Config.h"
83 #include "adaptation/ecap/Config.h"
86 #include "adaptation/icap/Config.h"
87 #include "adaptation/icap/icap_log.h"
90 #include "auth/Gadgets.h"
93 #include "ClientDelayConfig.h"
96 #include "DelayPools.h"
98 #if USE_LOADABLE_MODULES
99 #include "LoadableModules.h"
102 #include "ssl/certificate_db.h"
105 #include "ssl/context_storage.h"
106 #include "ssl/helper.h"
109 #include "adaptation/icap/Config.h"
112 #include "adaptation/ecap/Config.h"
115 #include "adaptation/Config.h"
118 #include "esi/Module.h"
121 #include "snmp_core.h"
132 #include <sys/wait.h>
135 #if USE_WIN32_SERVICE
138 static int opt_install_service
= FALSE
;
139 static int opt_remove_service
= FALSE
;
140 static int opt_command_line
= FALSE
;
141 void WIN32_svcstatusupdate(DWORD
, DWORD
);
142 void WINAPI
WIN32_svcHandler(DWORD
);
145 static int opt_signal_service
= FALSE
;
146 static char *opt_syslog_facility
= NULL
;
147 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
148 static int configured_once
= 0;
150 static int malloc_debug_level
= 0;
152 static volatile int do_reconfigure
= 0;
153 static volatile int do_rotate
= 0;
154 static volatile int do_shutdown
= 0;
155 static volatile int shutdown_status
= 0;
157 static int RotateSignal
= -1;
158 static int ReconfigureSignal
= -1;
159 static int ShutdownSignal
= -1;
161 static void mainRotate(void);
162 static void mainReconfigureStart(void);
163 static void mainReconfigureFinish(void*);
164 static void mainInitialize(void);
165 static void usage(void);
166 static void mainParseOptions(int argc
, char *argv
[]);
167 static void sendSignal(void);
168 static void serverConnectionsOpen(void);
169 static void serverConnectionsClose(void);
170 static void watch_child(char **);
171 static void setEffectiveUser(void);
172 static void SquidShutdown(void);
173 static void mainSetCwd(void);
174 static int checkRunningPid(void);
177 static const char *squid_start_script
= "squid_start";
181 #include "test_access.c"
184 /** temporary thunk across to the unrefactored store interface */
186 class StoreRootEngine
: public AsyncEngine
190 int checkEvents(int timeout
) {
191 Store::Root().callback();
196 class SignalEngine
: public AsyncEngine
200 virtual int checkEvents(int timeout
);
203 static void StopEventLoop(void *) {
204 if (EventLoop::Running
)
205 EventLoop::Running
->stop();
208 void doShutdown(time_t wait
);
212 SignalEngine::checkEvents(int timeout
)
214 PROF_start(SignalEngine_checkEvents
);
216 if (do_reconfigure
) {
217 mainReconfigureStart();
219 } else if (do_rotate
) {
222 } else if (do_shutdown
) {
223 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
226 BroadcastSignalIfAny(DebugSignal
);
227 BroadcastSignalIfAny(RotateSignal
);
228 BroadcastSignalIfAny(ReconfigureSignal
);
229 BroadcastSignalIfAny(ShutdownSignal
);
231 PROF_stop(SignalEngine_checkEvents
);
236 SignalEngine::doShutdown(time_t wait
)
238 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
239 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
243 #if USE_WIN32_SERVICE
244 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
247 /* run the closure code which can be shared with reconfigure */
248 serverConnectionsClose();
250 /* detach the auth components (only do this on full shutdown) */
251 Auth::Scheme::FreeAll();
254 RunRegisteredHere(RegisteredRunner::startShutdown
);
255 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
262 "Usage: %s [-cdzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
263 #if USE_WIN32_SERVICE
264 "[-ir] [-O CommandLine]"
267 " -h | --help Print help message.\n"
268 " -v | --version Print version details.\n"
270 " -a port Specify HTTP port number (default: %d).\n"
271 " -d level Write debugging to stderr also.\n"
272 " -f file Use given config-file instead of\n"
274 #if USE_WIN32_SERVICE
275 " -i Installs as a Windows Service (see -n option).\n"
277 " -k reconfigure|rotate|shutdown|"
281 "interrupt|kill|debug|check|parse\n"
282 " Parse configuration file, then send signal to \n"
283 " running copy (except -k parse) and exit.\n"
284 " -n name Specify service name to use for service operations\n"
285 " default is: " APP_SHORTNAME
".\n"
286 #if USE_WIN32_SERVICE
287 " -r Removes a Windows Service (see -n option).\n"
289 " -s | -l facility\n"
290 " Enable logging to syslog.\n"
291 " -u port Specify ICP port number (default: %d), disable with 0.\n"
292 " -z Create missing swap directories and then exit.\n"
293 " -C Do not catch fatal signals.\n"
294 " -D OBSOLETE. Scheduled for removal.\n"
295 " -F Don't serve any requests until store is rebuilt.\n"
296 " -N No daemon mode.\n"
297 #if USE_WIN32_SERVICE
299 " Set Windows Service Command line options in Registry.\n"
301 " -R Do not set REUSEADDR on port.\n"
302 " -S Double-check swap during rebuild.\n"
303 " -X Force full debugging.\n"
304 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
305 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
310 * Parse the parameters received via command line interface.
312 * \param argc Number of options received on command line
313 * \param argv List of parameters received on command line
316 mainParseOptions(int argc
, char *argv
[])
321 const char *shortOpStr
=
322 #if USE_WIN32_SERVICE
325 "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?";
328 static struct option squidOptions
[] = {
329 {"help", no_argument
, 0, 'h'},
330 {"version", no_argument
, 0, 'v'},
335 while ((c
= getopt_long(argc
, argv
, shortOpStr
, squidOptions
, &optIndex
)) != -1) {
341 * Unset/disabel global option for catchign signals. opt_catch_signals */
342 opt_catch_signals
= 0;
347 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
348 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
353 * Set global option for foreground rebuild. opt_foreground_rebuild */
354 opt_foreground_rebuild
= 1;
359 * Set global option for 'no_daemon' mode. opt_no_daemon */
363 #if USE_WIN32_SERVICE
367 * Set global option. opt_command_lin and WIN32_Command_Line */
368 opt_command_line
= 1;
369 WIN32_Command_Line
= xstrdup(optarg
);
375 * Unset/disable global option opt_reuseaddr */
381 * Set global option opt_store_doublecheck */
382 opt_store_doublecheck
= 1;
387 * Force full debugging */
388 Debug::parseOptions("rotate=0 ALL,9");
389 Debug::override_X
= 1;
390 sigusr2_handle(SIGUSR2
);
395 * Set global option opt_reload_hit_only */
396 opt_reload_hit_only
= 1;
399 #if USE_WIN32_SERVICE
403 * Set global option opt_install_service (to TRUE) */
404 opt_install_service
= TRUE
;
410 * Add optional HTTP port as given following the option */
411 add_http_port(optarg
);
416 * Set global option Debug::log_stderr to the number given following the option */
417 Debug::log_stderr
= atoi(optarg
);
422 * Load the file given instead of the default squid.conf. */
424 ConfigFile
= xstrdup(optarg
);
429 * Run the administrative action given following the option */
431 /** \li When its an unknown option display the usage help. */
432 if ((int) strlen(optarg
) < 1)
435 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
436 /** \li On reconfigure send SIGHUP. */
437 opt_send_signal
= SIGHUP
;
438 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
439 /** \li On rotate send SIGQUIT or SIGUSR1. */
440 #if defined(_SQUID_LINUX_THREADS_)
441 opt_send_signal
= SIGQUIT
;
443 opt_send_signal
= SIGUSR1
;
446 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
447 /** \li On debug send SIGTRAP or SIGUSR2. */
448 #if defined(_SQUID_LINUX_THREADS_)
449 opt_send_signal
= SIGTRAP
;
451 opt_send_signal
= SIGUSR2
;
454 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
455 /** \li On shutdown send SIGTERM. */
456 opt_send_signal
= SIGTERM
;
457 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
458 /** \li On interrupt send SIGINT. */
459 opt_send_signal
= SIGINT
;
460 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
461 /** \li On kill send SIGKILL. */
462 opt_send_signal
= SIGKILL
;
466 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
467 /** \li On restart send SIGTTIN. (exit and restart by parent) */
468 opt_send_signal
= SIGTTIN
;
472 else if (!strncmp(optarg
, "check", strlen(optarg
)))
473 /** \li On check send 0 / SIGNULL. */
474 opt_send_signal
= 0; /* SIGNULL */
475 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
476 /** \li On parse set global flag to re-parse the config file only. */
477 opt_parse_cfg_only
= 1;
485 * Set global malloc_debug_level to the value given following the option.
486 * if none is given it toggles the xmalloc_trace option on/off */
489 malloc_debug_level
= atoi(optarg
);
491 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
499 * Set global option opt_signal_service (to true).
500 * Stores the additional parameter given in global service_name */
501 if (optarg
&& *optarg
!= '\0') {
502 const SBuf
t(optarg
);
503 ::Parser::Tokenizer
tok(t
);
504 const CharacterSet chr
= CharacterSet::ALPHA
+CharacterSet::DIGIT
;
505 if (!tok
.prefix(service_name
, chr
))
506 fatalf("Expected alphanumeric service name for the -n option but got: %s", optarg
);
508 fatalf("Garbage after alphanumeric service name in the -n option value: %s", optarg
);
509 if (service_name
.length() > 32)
510 fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name
.length());
511 opt_signal_service
= true;
513 fatal("A service name is required for the -n option");
517 #if USE_WIN32_SERVICE
521 * Set global option opt_remove_service (to TRUE) */
522 opt_remove_service
= TRUE
;
530 * Stores the syslog facility name in global opt_syslog_facility
531 * then performs actions for -s option. */
532 xfree(opt_syslog_facility
); // ignore any previous options sent
533 opt_syslog_facility
= xstrdup(optarg
);
537 * Initialize the syslog for output */
540 _db_set_syslog(opt_syslog_facility
);
546 fatal("Logging to syslog not available on this platform");
553 * Store the ICP port number given in global option icpPortNumOverride
554 * ensuring its a positive number. */
555 icpPortNumOverride
= atoi(optarg
);
557 if (icpPortNumOverride
< 0)
558 icpPortNumOverride
= 0;
564 * Display squid version and build information. Then exit. */
565 printf("Squid Cache: Version %s\n" ,version_string
);
566 printf("Service Name: " SQUIDSBUFPH
"\n", SQUIDSBUFPRINT(service_name
));
567 if (strlen(SQUID_BUILD_INFO
))
568 printf("%s\n",SQUID_BUILD_INFO
);
569 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
571 #if USE_WIN32_SERVICE
573 printf("Compiled as Windows System Service.\n");
583 * Set global option Debug::log_stderr and opt_create_swap_dirs */
584 Debug::log_stderr
= 1;
585 opt_create_swap_dirs
= 1;
593 /** \par h,?, or unknown
594 * \copydoc usage() */
612 signal(sig
, rotate_logs
);
622 ReconfigureSignal
= sig
;
626 signal(sig
, reconfigure
);
634 do_shutdown
= sig
== SIGINT
? -1 : 1;
635 ShutdownSignal
= sig
;
642 const pid_t ppid
= getppid();
644 if (!IamMasterProcess() && ppid
> 1) {
645 // notify master that we are shutting down
646 if (kill(ppid
, SIGUSR1
) < 0)
647 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
648 " pid " << ppid
<< ": " << xstrerror());
652 if (!IamMasterProcess() && ppid
> 1) {
653 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
655 if (kill(ppid
, sig
) < 0)
656 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
658 #endif /* KILL_PARENT_OPT */
660 #if SA_RESETHAND == 0
661 signal(SIGTERM
, SIG_DFL
);
663 signal(SIGINT
, SIG_DFL
);
670 serverConnectionsOpen(void)
672 if (IamPrimaryProcess()) {
674 wccpConnectionOpen();
679 wccp2ConnectionOpen();
682 // start various proxying services if we are responsible for them
683 if (IamWorkerProcess()) {
684 clientOpenListenSockets();
703 peerSourceHashInit();
708 serverConnectionsClose(void)
710 assert(shutting_down
|| reconfiguring
);
712 if (IamPrimaryProcess()) {
715 wccpConnectionClose();
719 wccp2ConnectionClose();
722 if (IamWorkerProcess()) {
723 clientConnectionsClose();
724 icpConnectionShutdown();
726 htcpSocketShutdown();
739 mainReconfigureStart(void)
741 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
744 // Initiate asynchronous closing sequence
745 serverConnectionsClose();
752 Ssl::Helper::GetInstance()->Shutdown();
755 if (Ssl::CertValidationHelper::GetInstance())
756 Ssl::CertValidationHelper::GetInstance()->Shutdown();
757 Ssl::TheGlobalContextStorage
.reconfigureStart();
763 externalAclShutdown();
764 storeDirCloseSwapLogs();
771 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
776 mainReconfigureFinish(void *)
778 debugs(1, 3, "finishing reconfiguring");
781 enter_suid(); /* root to read config file */
783 // we may have disabled the need for PURGE
784 if (Config2
.onoff
.enable_purge
)
785 Config2
.onoff
.enable_purge
= 2;
787 // parse the config returns a count of errors encountered.
788 const int oldWorkers
= Config
.workers
;
789 if ( parseConfigFile(ConfigFile
) != 0) {
790 // for now any errors are a fatal condition...
793 if (oldWorkers
!= Config
.workers
) {
794 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
795 oldWorkers
<< " to " << Config
.workers
<<
796 ") requires a full restart. It has been ignored by reconfigure.");
797 Config
.workers
= oldWorkers
;
800 RunRegisteredHere(RegisteredRunner::syncConfig
);
802 if (IamPrimaryProcess())
804 CpuAffinityReconfigure();
806 setUmask(Config
.umask
);
809 _db_init(Debug::cache_log
, Debug::debugOptions
);
810 ipcache_restart(); /* clear stuck entries */
811 fqdncache_restart(); /* sigh, fqdncache too */
813 errorInitialize(); /* reload error pages */
816 #if USE_LOADABLE_MODULES
817 LoadableModulesConfigure(Config
.loadable_module_names
);
821 bool enableAdaptation
= false;
823 Adaptation::Icap::TheConfig
.finalize();
824 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
827 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
828 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
830 Adaptation::Config::Finalize(enableAdaptation
);
839 Ssl::Helper::GetInstance()->Init();
842 if (Ssl::CertValidationHelper::GetInstance())
843 Ssl::CertValidationHelper::GetInstance()->Init();
848 authenticateInit(&Auth::TheConfig
);
852 if (IamPrimaryProcess()) {
863 serverConnectionsOpen();
867 storeDirOpenSwapLogs();
869 mimeInit(Config
.mimeTablePathname
);
875 Config
.ClientDelay
.finalize();
878 if (Config
.onoff
.announce
) {
879 if (!eventFind(start_announce
, NULL
))
880 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
882 if (eventFind(start_announce
, NULL
))
883 eventDelete(start_announce
, NULL
);
886 writePidFile(); /* write PID file */
897 authenticateRotate();
899 externalAclShutdown();
901 _db_rotate_log(); /* cache.log */
902 storeDirWriteCleanLogs(1);
903 storeLogRotate(); /* store.log */
904 accessLogRotate(); /* access.log */
906 icapLogRotate(); /*icap.log*/
911 authenticateInit(&Auth::TheConfig
);
917 setEffectiveUser(void)
920 leave_suid(); /* Run as non privilegied user */
926 if (geteuid() == 0) {
927 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
928 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
929 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
930 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
931 fatal("Don't run Squid as root, set 'cache_effective_user'!");
935 /// changes working directory, providing error reporting
937 mainChangeDir(const char *dir
)
942 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
943 ": " << xstrerror());
947 /// set the working directory.
951 static bool chrooted
= false;
952 if (Config
.chroot_dir
&& !chrooted
) {
955 if (chroot(Config
.chroot_dir
) != 0)
956 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
958 if (!mainChangeDir("/"))
959 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
962 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
963 if (mainChangeDir(Config
.coredump_dir
)) {
964 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
969 /* If we don't have coredump_dir or couldn't cd there, report current dir */
970 char pathbuf
[MAXPATHLEN
];
971 if (getcwd(pathbuf
, MAXPATHLEN
)) {
972 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
974 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
981 /* chroot if configured to run inside chroot */
984 if (opt_catch_signals
) {
985 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
986 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
989 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
990 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
994 if (icpPortNumOverride
!= 1)
995 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
997 _db_init(Debug::cache_log
, Debug::debugOptions
);
999 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1001 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1002 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1005 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1006 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1008 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1011 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1013 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1016 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1020 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1022 if (WIN32_Socks_initialized
)
1023 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1025 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1026 WIN32_IpAddrChangeMonitorInit();
1031 if (!configured_once
)
1032 disk_init(); /* disk_init must go before ipcache_init() */
1043 Ssl::Helper::GetInstance()->Init();
1047 if (!configured_once
)
1048 Ssl::initialize_session_cache();
1050 if (Ssl::CertValidationHelper::GetInstance())
1051 Ssl::CertValidationHelper::GetInstance()->Init();
1056 authenticateInit(&Auth::TheConfig
);
1060 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1062 httpReplyInitModule(); /* must go before accepting replies */
1083 malloc_debug(0, malloc_debug_level
);
1087 if (!configured_once
) {
1088 if (unlinkdNeeded())
1095 mimeInit(Config
.mimeTablePathname
);
1101 FwdState::initModule();
1102 /* register the modules in the cache manager menus */
1104 cbdataRegisterWithCacheManager();
1105 /* These use separate calls so that the comm loops can eventually
1111 // TODO: pconn is a good candidate for new-style registration
1112 // PconnModule::GetInstance()->registerWithCacheManager();
1113 // moved to PconnModule::PconnModule()
1116 if (IamPrimaryProcess()) {
1128 serverConnectionsOpen();
1132 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1134 if (Config
.chroot_dir
)
1137 if (!configured_once
)
1138 writePidFile(); /* write PID file */
1140 #if defined(_SQUID_LINUX_THREADS_)
1142 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1144 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1148 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1150 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1154 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1156 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1158 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1162 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1168 #if USE_LOADABLE_MODULES
1169 LoadableModulesConfigure(Config
.loadable_module_names
);
1173 bool enableAdaptation
= false;
1175 // We can remove this dependency on specific adaptation mechanisms
1176 // if we create a generic Registry of such mechanisms. Should we?
1178 Adaptation::Icap::TheConfig
.finalize();
1179 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1182 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1183 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1185 // must be the last adaptation-related finalize
1186 Adaptation::Config::Finalize(enableAdaptation
);
1194 Config
.ClientDelay
.finalize();
1197 if (!configured_once
) {
1198 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1200 if (Config
.onoff
.announce
)
1201 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1203 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1205 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1209 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1213 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1216 configured_once
= 1;
1219 /// unsafe main routine -- may throw
1220 int SquidMain(int argc
, char **argv
);
1221 /// unsafe main routine wrapper to catch exceptions
1222 static int SquidMainSafe(int argc
, char **argv
);
1224 #if USE_WIN32_SERVICE
1225 /* Entry point for Windows services */
1226 extern "C" void WINAPI
1227 SquidWinSvcMain(int argc
, char **argv
)
1229 SquidMainSafe(argc
, argv
);
1234 main(int argc
, char **argv
)
1236 #if USE_WIN32_SERVICE
1237 SetErrorMode(SEM_NOGPFAULTERRORBOX
);
1238 if ((argc
== 2) && strstr(argv
[1], _WIN_SQUID_SERVICE_OPTION
))
1239 return WIN32_StartService(argc
, argv
);
1241 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_INTERACTIVE
;
1246 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]);
1296 Debug::parseOptions(NULL
);
1299 #if defined(SQUID_MAXFD_LIMIT)
1301 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1302 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1306 /* NOP under non-windows */
1307 int WIN32_init_err
=0;
1308 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1309 return WIN32_init_err
;
1311 /* call mallopt() before anything else */
1314 /* Round up all sizes to a multiple of this */
1315 mallopt(M_GRAIN
, 16);
1319 /* biggest size that is considered a small block */
1320 mallopt(M_MXFAST
, 256);
1324 /* allocate this many small blocks at once */
1325 mallopt(M_NLBLKS
, 32);
1328 #endif /* HAVE_MALLOPT */
1330 squid_srandom(time(NULL
));
1334 squid_start
= current_time
;
1336 failure_notify
= fatal_dump
;
1338 #if USE_WIN32_SERVICE
1340 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1344 mainParseOptions(argc
, argv
);
1346 if (opt_parse_cfg_only
) {
1347 Debug::parseOptions("ALL,1");
1350 #if USE_WIN32_SERVICE
1352 if (opt_install_service
) {
1353 WIN32_InstallService();
1357 if (opt_remove_service
) {
1358 WIN32_RemoveService();
1362 if (opt_command_line
) {
1363 WIN32_SetServiceCommandLine();
1369 /* parse configuration file
1370 * note: in "normal" case this used to be called from mainInitialize() */
1375 ConfigFile
= xstrdup(DefaultConfigFile
);
1377 assert(!configured_once
);
1381 storeFsInit(); /* required for config parsing */
1383 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1386 /* May not be needed for parsing, have not audited for such */
1387 DiskIOModule::SetupAllModules();
1389 /* Shouldn't be needed for config parsing, but have not audited for such */
1390 StoreFileSystem::SetupAllFs();
1392 /* we may want the parsing process to set this up in the future */
1393 Store::Root(new StoreController
);
1394 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1395 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1397 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1399 parse_err
= parseConfigFile(ConfigFile
);
1403 if (opt_parse_cfg_only
|| parse_err
> 0)
1406 setUmask(Config
.umask
);
1407 if (-1 == opt_send_signal
)
1408 if (checkRunningPid())
1423 /* send signal to running copy and exit */
1424 if (opt_send_signal
!= -1) {
1425 /* chroot if configured to run inside chroot */
1427 if (Config
.chroot_dir
) {
1437 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1439 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1440 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1441 RunRegisteredHere(RegisteredRunner::useConfig
);
1444 if (!opt_no_daemon
&& Config
.workers
> 0)
1447 if (opt_create_swap_dirs
) {
1448 /* chroot if configured to run inside chroot */
1452 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1453 Store::Root().create();
1458 if (IamPrimaryProcess())
1464 /* init comm module */
1467 if (opt_no_daemon
) {
1468 /* we have to init fdstat here. */
1469 fd_open(0, FD_LOG
, "stdin");
1470 fd_open(1, FD_LOG
, "stdout");
1471 fd_open(2, FD_LOG
, "stderr");
1474 #if USE_WIN32_SERVICE
1476 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1482 #if USE_WIN32_SERVICE
1484 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1491 SignalEngine signalEngine
;
1493 mainLoop
.registerEngine(&signalEngine
);
1495 /* TODO: stop requiring the singleton here */
1496 mainLoop
.registerEngine(EventScheduler::GetInstance());
1498 StoreRootEngine store_engine
;
1500 mainLoop
.registerEngine(&store_engine
);
1502 CommSelectEngine comm_engine
;
1504 mainLoop
.registerEngine(&comm_engine
);
1506 mainLoop
.setPrimaryEngine(&comm_engine
);
1508 /* use the standard time service */
1509 TimeEngine time_engine
;
1511 mainLoop
.setTimeService(&time_engine
);
1513 if (IamCoordinatorProcess())
1514 AsyncJob::Start(Ipc::Coordinator::Instance());
1515 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1516 AsyncJob::Start(new Ipc::Strand
);
1518 /* at this point we are finished the synchronous startup. */
1523 if (mainLoop
.errcount
== 10)
1524 fatal_dump("Event loop exited with failure.");
1526 /* shutdown squid now */
1539 if (strcmp(Config
.pidFilename
, "none") == 0) {
1540 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1543 pid
= readPidFile();
1546 #if USE_WIN32_SERVICE
1547 if (opt_signal_service
) {
1548 WIN32_sendSignal(opt_send_signal
);
1551 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1552 fprintf(stderr
, "signal to Squid Service:\n");
1553 fprintf(stderr
, "missing -n command line switch.\n");
1559 if (kill(pid
, opt_send_signal
) &&
1560 /* ignore permissions if just running check */
1561 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1562 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1563 fprintf(stderr
, "signal %d to process %d: %s\n",
1564 opt_send_signal
, (int) pid
, xstrerror());
1568 if (opt_send_signal
!= SIGTERM
) {
1569 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1572 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1577 /* signal successfully sent */
1581 #if !_SQUID_WINDOWS_
1583 * This function is run when Squid is in daemon mode, just
1584 * before the parent forks and starts up the child process.
1585 * It can be used for admin-specific tasks, such as notifying
1586 * someone that Squid is (re)started.
1589 mainStartScript(const char *prog
)
1591 char script
[MAXPATHLEN
];
1596 xstrncpy(script
, prog
, MAXPATHLEN
);
1598 if ((t
= strrchr(script
, '/'))) {
1600 sl
= strlen(script
);
1603 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1605 if ((cpid
= fork()) == 0) {
1607 execl(script
, squid_start_script
, (char *)NULL
);
1613 rpid
= wait4(cpid
, &status
, 0, NULL
);
1617 rpid
= waitpid(cpid
, &status
, 0);
1620 } while (rpid
!= cpid
);
1624 #endif /* _SQUID_WINDOWS_ */
1627 checkRunningPid(void)
1629 // master process must start alone, but its kids processes may co-exist
1630 if (!IamMasterProcess())
1638 pid
= readPidFile();
1643 if (kill(pid
, 0) < 0)
1646 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1652 watch_child(char *argv
[])
1654 #if !_SQUID_WINDOWS_
1672 if (!IamMasterProcess())
1675 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1677 if ((pid
= fork()) < 0)
1678 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1683 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1689 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1690 ioctl(i
, TIOCNOTTY
, NULL
);
1697 * RBCOLLINS - if cygwin stackdumps when squid is run without
1698 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1699 * 1.1.3. execvp had a bit overflow error in a loop..
1701 /* Connect stdio to /dev/null in daemon mode */
1702 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1705 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1709 if (Debug::log_stderr
< 0) {
1714 // handle shutdown notifications from kids
1715 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1717 if (Config
.workers
> 128) {
1718 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1720 // but we keep going in hope that user knows best
1724 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1726 // keep [re]starting kids until it is time to quit
1728 mainStartScript(argv
[0]);
1730 // start each kid that needs to be [re]started; once
1731 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1732 Kid
& kid
= TheKids
.get(i
);
1733 if (!kid
.shouldRestart())
1736 if ((pid
= fork()) == 0) {
1738 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1740 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1742 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1746 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1747 kid
.name().termedBuf(), pid
);
1751 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1753 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1757 pid
= wait3(&status
, 0, NULL
);
1761 pid
= waitpid(-1, &status
, 0);
1764 // Loop to collect all stopped kids before we go to sleep below.
1766 Kid
* kid
= TheKids
.find(pid
);
1769 if (kid
->calledExit()) {
1771 "Squid Parent: %s process %d exited with status %d",
1772 kid
->name().termedBuf(),
1773 kid
->getPid(), kid
->exitStatus());
1774 } else if (kid
->signaled()) {
1776 "Squid Parent: %s process %d exited due to signal %d with status %d",
1777 kid
->name().termedBuf(),
1778 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1780 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1781 kid
->name().termedBuf(), kid
->getPid());
1783 if (kid
->hopeless()) {
1784 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1785 " be restarted due to repeated, frequent failures",
1786 kid
->name().termedBuf(), kid
->getPid());
1789 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1792 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1795 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1798 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1800 // XXX: Master process has no main loop and, hence, should not call
1801 // RegisteredRunner::startShutdown which promises a loop iteration.
1802 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1805 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1806 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1810 if (TheKids
.allHopeless()) {
1811 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1818 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1823 #endif /* _SQUID_WINDOWS_ */
1830 /* XXX: This function is called after the main loop has quit, which
1831 * means that no AsyncCalls would be called, including close handlers.
1832 * TODO: We need to close/shut/free everything that needs calls before
1836 #if USE_WIN32_SERVICE
1837 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1840 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1843 Ssl::Helper::GetInstance()->Shutdown();
1846 if (Ssl::CertValidationHelper::GetInstance())
1847 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1850 externalAclShutdown();
1860 wccpConnectionClose();
1864 wccp2ConnectionClose();
1867 releaseServerSockets();
1868 commCloseAllSockets();
1875 DelayPools::FreePools();
1878 authenticateReset();
1880 #if USE_WIN32_SERVICE
1882 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1885 Store::Root().sync(); /* Flush pending object writes/unlinks */
1887 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1889 storeDirWriteCleanLogs(0);
1892 Store::Root().sync(); /* Flush log writes */
1895 Store::Root().sync(); /* Flush log close */
1896 StoreFileSystem::FreeAllFs();
1897 DiskIOModule::FreeAllModules();
1898 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1902 /*stmemFreeMemory(); */
1904 ipcacheFreeMemory();
1905 fqdncacheFreeMemory();
1907 clientdbFreeMemory();
1908 httpHeaderCleanModule();
1914 // clear StoreController
1921 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1925 if (IamPrimaryProcess()) {
1926 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1928 safeunlink(Config
.pidFilename
, 0);
1933 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1937 * We used to fclose(debug_log) here if it was set, but then
1938 * we forgot to set it to NULL. That caused some coredumps
1939 * because exit() ends up calling a bunch of destructors and
1940 * such. So rather than forcing the debug_log to close, we'll
1941 * leave it open so that those destructors can write some
1942 * debugging if necessary. The file will be closed anyway when
1943 * the process truly exits.
1946 exit(shutdown_status
);