]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/main.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / main.cc
index c529051a84e17a1eb3a84f2497b046a1e4b3b5f5..84358522db401982b4fa39d9a750e40bbfdef520 100644 (file)
@@ -1,35 +1,13 @@
 /*
- * DEBUG: section 01    Startup and Main Loop
- * AUTHOR: Harvest Derived
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
  *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
+/* DEBUG: section 01    Startup and Main Loop */
+
 #include "squid.h"
 #include "AccessLogEntry.h"
 #include "acl/Acl.h"
@@ -53,9 +31,9 @@
 #include "ExternalACL.h"
 #include "fd.h"
 #include "format/Token.h"
-#include "forward.h"
-#include "fs/Module.h"
 #include "fqdncache.h"
+#include "fs/Module.h"
+#include "FwdState.h"
 #include "globals.h"
 #include "htcp.h"
 #include "HttpHeader.h"
 #include "icmp/net_db.h"
 #include "ICP.h"
 #include "ident/Ident.h"
-#include "ipcache.h"
+#include "ip/tools.h"
 #include "ipc/Coordinator.h"
 #include "ipc/Kids.h"
 #include "ipc/Strand.h"
-#include "ip/tools.h"
-#include "Mem.h"
-#include "MemPool.h"
+#include "ipcache.h"
 #include "mime.h"
 #include "neighbors.h"
+#include "parser/Tokenizer.h"
 #include "pconn.h"
-#include "PeerSelectState.h"
 #include "peer_sourcehash.h"
 #include "peer_userhash.h"
+#include "PeerSelectState.h"
 #include "profiler/Profiler.h"
 #include "redirect.h"
 #include "refresh.h"
 #include "send-announce.h"
-#include "store_log.h"
-#include "tools.h"
 #include "SquidConfig.h"
 #include "SquidDns.h"
 #include "SquidTime.h"
 #include "stat.h"
 #include "StatCounters.h"
-#include "StoreFileSystem.h"
 #include "Store.h"
+#include "store_log.h"
+#include "StoreFileSystem.h"
 #include "SwapDir.h"
+#include "tools.h"
 #include "unlinkd.h"
 #include "URL.h"
 #include "wccp.h"
 #include "LoadableModules.h"
 #endif
 #if USE_SSL_CRTD
-#include "ssl/helper.h"
 #include "ssl/certificate_db.h"
 #endif
-#if USE_SSL
+#if USE_OPENSSL
 #include "ssl/context_storage.h"
+#include "ssl/helper.h"
 #endif
 #if ICAP_CLIENT
 #include "adaptation/icap/Config.h"
 #include "snmp_core.h"
 #endif
 
+#include <cerrno>
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
 #if HAVE_PATHS_H
 #include <paths.h>
 #endif
 #if HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
-#if HAVE_ERRNO_H
-#include <errno.h>
-#endif
 
 #if USE_WIN32_SERVICE
-#include "squid_windows.h"
 #include <process.h>
 
 static int opt_install_service = FALSE;
 static int opt_remove_service = FALSE;
-static int opt_signal_service = FALSE;
 static int opt_command_line = FALSE;
-extern void WIN32_svcstatusupdate(DWORD, DWORD);
+void WIN32_svcstatusupdate(DWORD, DWORD);
 void WINAPI WIN32_svcHandler(DWORD);
-
-#endif
-
-#if !defined(SQUID_BUILD_INFO)
-#define SQUID_BUILD_INFO ""
 #endif
 
+static int opt_signal_service = FALSE;
 static char *opt_syslog_facility = NULL;
-static int icpPortNumOverride = 1;     /* Want to detect "-u 0" */
+static int icpPortNumOverride = 1;  /* Want to detect "-u 0" */
 static int configured_once = 0;
 #if MALLOC_DBG
 static int malloc_debug_level = 0;
@@ -195,15 +167,11 @@ static void serverConnectionsOpen(void);
 static void serverConnectionsClose(void);
 static void watch_child(char **);
 static void setEffectiveUser(void);
-#if MEM_GEN_TRACE
-extern void log_trace_done();
-extern void log_trace_init(char *);
-#endif
 static void SquidShutdown(void);
 static void mainSetCwd(void);
 static int checkRunningPid(void);
 
-#if !_SQUID_MSWIN_
+#if !_SQUID_WINDOWS_
 static const char *squid_start_script = "squid_start";
 #endif
 
@@ -217,7 +185,7 @@ class StoreRootEngine : public AsyncEngine
 {
 
 public:
-    int checkEvents(int timeout) {
+    int checkEvents(int) {
         Store::Root().callback();
         return EVENT_IDLE;
     };
@@ -227,21 +195,19 @@ class SignalEngine: public AsyncEngine
 {
 
 public:
-    SignalEngine(EventLoop &evtLoop) : loop(evtLoop) {}
     virtual int checkEvents(int timeout);
 
 private:
-    static void StopEventLoop(void * data) {
-        static_cast<SignalEngine *>(data)->loop.stop();
+    static void StopEventLoop(void *) {
+        if (EventLoop::Running)
+            EventLoop::Running->stop();
     }
 
     void doShutdown(time_t wait);
-
-    EventLoop &loop;
 };
 
 int
-SignalEngine::checkEvents(int timeout)
+SignalEngine::checkEvents(int)
 {
     PROF_start(SignalEngine_checkEvents);
 
@@ -282,6 +248,8 @@ SignalEngine::doShutdown(time_t wait)
     /* detach the auth components (only do this on full shutdown) */
     Auth::Scheme::FreeAll();
 #endif
+
+    RunRegisteredHere(RegisteredRunner::startShutdown);
     eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
 }
 
@@ -289,32 +257,37 @@ static void
 usage(void)
 {
     fprintf(stderr,
+            "Usage: %s [-cdzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
 #if USE_WIN32_SERVICE
-            "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
-#else
-            "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
+            "[-ir] [-O CommandLine]"
 #endif
+            "\n"
+            "    -h | --help       Print help message.\n"
+            "    -v | --version    Print version details.\n"
+            "\n"
             "       -a port   Specify HTTP port number (default: %d).\n"
             "       -d level  Write debugging to stderr also.\n"
             "       -f file   Use given config-file instead of\n"
             "                 %s\n"
-            "       -h        Print help message.\n"
 #if USE_WIN32_SERVICE
             "       -i        Installs as a Windows Service (see -n option).\n"
 #endif
-            "       -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
+            "       -k reconfigure|rotate|shutdown|"
+#ifdef SIGTTIN
+            "restart|"
+#endif
+            "interrupt|kill|debug|check|parse\n"
             "                 Parse configuration file, then send signal to \n"
             "                 running copy (except -k parse) and exit.\n"
+            "       -n name   Specify service name to use for service operations\n"
+            "                 default is: " APP_SHORTNAME ".\n"
 #if USE_WIN32_SERVICE
-            "       -n name   Specify Windows Service name to use for service operations\n"
-            "                 default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
             "       -r        Removes a Windows Service (see -n option).\n"
 #endif
             "       -s | -l facility\n"
             "                 Enable logging to syslog.\n"
             "       -u port   Specify ICP port number (default: %d), disable with 0.\n"
-            "       -v        Print version.\n"
-            "       -z        Create swap directories\n"
+            "       -z        Create missing swap directories and then exit.\n"
             "       -C        Do not catch fatal signals.\n"
             "       -D        OBSOLETE. Scheduled for removal.\n"
             "       -F        Don't serve any requests until store is rebuilt.\n"
@@ -334,21 +307,30 @@ usage(void)
 /**
  * Parse the parameters received via command line interface.
  *
- \param argc   Number of options received on command line
- \param argv   List of parameters received on command line
\param argc   Number of options received on command line
\param argv   List of parameters received on command line
  */
 static void
 mainParseOptions(int argc, char *argv[])
 {
-    extern char *optarg;
-    int c;
+    int optIndex = 0;
 
+    // short options
+    const char *shortOpStr =
 #if USE_WIN32_SERVICE
-    while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
-#else
-    while ((c = getopt(argc, argv, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
+        "O:Vir"
 #endif
-    {
+        "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?";
+
+    // long options
+    static struct option squidOptions[] = {
+        {"help",    no_argument, 0, 'h'},
+        {"version", no_argument, 0, 'v'},
+        {0, 0, 0, 0}
+    };
+
+    int c;
+    while ((c = getopt_long(argc, argv, shortOpStr, squidOptions, &optIndex)) != -1) {
 
         switch (c) {
 
@@ -429,7 +411,7 @@ mainParseOptions(int argc, char *argv[])
 
         case 'd':
             /** \par d
-             * Set global option Debug::log_stderr to the number given follwoign the option */
+             * Set global option Debug::log_stderr to the number given following the option */
             Debug::log_stderr = atoi(optarg);
             break;
 
@@ -487,7 +469,7 @@ mainParseOptions(int argc, char *argv[])
 
             else if (!strncmp(optarg, "check", strlen(optarg)))
                 /** \li On check send 0 / SIGNULL. */
-                opt_send_signal = 0;   /* SIGNULL */
+                opt_send_signal = 0;    /* SIGNULL */
             else if (!strncmp(optarg, "parse", strlen(optarg)))
                 /** \li On parse set global flag to re-parse the config file only. */
                 opt_parse_cfg_only = 1;
@@ -507,29 +489,31 @@ mainParseOptions(int argc, char *argv[])
                 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
 #endif
 
-            } else {
-#if XMALLOC_TRACE
-                xmalloc_trace = !xmalloc_trace;
-#else
-                fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
-#endif
             }
             break;
 
-#if USE_WIN32_SERVICE
-
         case 'n':
             /** \par n
-             * Set global option opt_signal_service (to TRUE).
-             * Stores the additional parameter given in global WIN32_Service_name */
-            xfree(WIN32_Service_name);
-
-            WIN32_Service_name = xstrdup(optarg);
-
-            opt_signal_service = TRUE;
-
+             * Set global option opt_signal_service (to true).
+             * Stores the additional parameter given in global service_name */
+            if (optarg && *optarg != '\0') {
+                const SBuf t(optarg);
+                ::Parser::Tokenizer tok(t);
+                const CharacterSet chr = CharacterSet::ALPHA+CharacterSet::DIGIT;
+                if (!tok.prefix(service_name, chr))
+                    fatalf("Expected alphanumeric service name for the -n option but got: %s", optarg);
+                if (!tok.atEnd())
+                    fatalf("Garbage after alphanumeric service name in the -n option value: %s", optarg);
+                if (service_name.length() > 32)
+                    fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name.length());
+                opt_signal_service = true;
+            } else {
+                fatal("A service name is required for the -n option");
+            }
             break;
 
+#if USE_WIN32_SERVICE
+
         case 'r':
             /** \par r
              * Set global option opt_remove_service (to TRUE) */
@@ -543,6 +527,7 @@ mainParseOptions(int argc, char *argv[])
             /** \par l
              * Stores the syslog facility name in global opt_syslog_facility
              * then performs actions for -s option. */
+            xfree(opt_syslog_facility); // ignore any previous options sent
             opt_syslog_facility = xstrdup(optarg);
 
         case 's':
@@ -576,6 +561,7 @@ mainParseOptions(int argc, char *argv[])
             /** \par v
              * Display squid version and build information. Then exit. */
             printf("Squid Cache: Version %s\n" ,version_string);
+            printf("Service Name: " SQUIDSBUFPH "\n", SQUIDSBUFPRINT(service_name));
             if (strlen(SQUID_BUILD_INFO))
                 printf("%s\n",SQUID_BUILD_INFO);
             printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS);
@@ -588,7 +574,7 @@ mainParseOptions(int argc, char *argv[])
 
             exit(0);
 
-            /* NOTREACHED */
+        /* NOTREACHED */
 
         case 'z':
             /** \par z
@@ -618,7 +604,7 @@ rotate_logs(int sig)
 {
     do_rotate = 1;
     RotateSignal = sig;
-#if !_SQUID_MSWIN_
+#if !_SQUID_WINDOWS_
 #if !HAVE_SIGACTION
 
     signal(sig, rotate_logs);
@@ -632,7 +618,7 @@ reconfigure(int sig)
 {
     do_reconfigure = 1;
     ReconfigureSignal = sig;
-#if !_SQUID_MSWIN_
+#if !_SQUID_WINDOWS_
 #if !HAVE_SIGACTION
 
     signal(sig, reconfigure);
@@ -645,13 +631,12 @@ shut_down(int sig)
 {
     do_shutdown = sig == SIGINT ? -1 : 1;
     ShutdownSignal = sig;
-#ifdef SIGTTIN
-
+#if defined(SIGTTIN)
     if (SIGTTIN == sig)
         shutdown_status = 1;
-
 #endif
 
+#if !_SQUID_WINDOWS_
     const pid_t ppid = getppid();
 
     if (!IamMasterProcess() && ppid > 1) {
@@ -661,17 +646,15 @@ shut_down(int sig)
                    " pid " << ppid << ": " << xstrerror());
     }
 
-#if !_SQUID_MSWIN_
 #if KILL_PARENT_OPT
-
     if (!IamMasterProcess() && ppid > 1) {
         debugs(1, DBG_IMPORTANT, "Killing master process, pid " << ppid);
 
         if (kill(ppid, sig) < 0)
             debugs(1, DBG_IMPORTANT, "kill " << ppid << ": " << xstrerror());
     }
-
 #endif /* KILL_PARENT_OPT */
+
 #if SA_RESETHAND == 0
     signal(SIGTERM, SIG_DFL);
 
@@ -705,7 +688,6 @@ serverConnectionsOpen(void)
         snmpOpenPorts();
 #endif
 
-        clientdbInit();
         icmpEngine.Open();
         netdbInit();
         asnInit();
@@ -736,7 +718,7 @@ serverConnectionsClose(void)
 #endif
     }
     if (IamWorkerProcess()) {
-        clientHttpConnectionsClose();
+        clientConnectionsClose();
         icpConnectionShutdown();
 #if USE_HTCP
         htcpSocketShutdown();
@@ -767,7 +749,9 @@ mainReconfigureStart(void)
 #if USE_SSL_CRTD
     Ssl::Helper::GetInstance()->Shutdown();
 #endif
-#if USE_SSL
+#if USE_OPENSSL
+    if (Ssl::CertValidationHelper::GetInstance())
+        Ssl::CertValidationHelper::GetInstance()->Shutdown();
     Ssl::TheGlobalContextStorage.reconfigureStart();
 #endif
     redirectShutdown();
@@ -792,7 +776,7 @@ mainReconfigureFinish(void *)
     debugs(1, 3, "finishing reconfiguring");
 
     errorClean();
-    enter_suid();              /* root to read config file */
+    enter_suid();       /* root to read config file */
 
     // we may have disabled the need for PURGE
     if (Config2.onoff.enable_purge)
@@ -807,10 +791,12 @@ mainReconfigureFinish(void *)
     if (oldWorkers != Config.workers) {
         debugs(1, DBG_CRITICAL, "WARNING: Changing 'workers' (from " <<
                oldWorkers << " to " << Config.workers <<
-               ") is not supported and ignored");
+               ") requires a full restart. It has been ignored by reconfigure.");
         Config.workers = oldWorkers;
     }
 
+    RunRegisteredHere(RegisteredRunner::syncConfig);
+
     if (IamPrimaryProcess())
         CpuAffinityCheck();
     CpuAffinityReconfigure();
@@ -819,10 +805,10 @@ mainReconfigureFinish(void *)
     Mem::Report();
     setEffectiveUser();
     _db_init(Debug::cache_log, Debug::debugOptions);
-    ipcache_restart();         /* clear stuck entries */
-    fqdncache_restart();       /* sigh, fqdncache too */
+    ipcache_restart();      /* clear stuck entries */
+    fqdncache_restart();    /* sigh, fqdncache too */
     parseEtcHosts();
-    errorInitialize();         /* reload error pages */
+    errorInitialize();      /* reload error pages */
     accessLogInit();
 
 #if USE_LOADABLE_MODULES
@@ -850,6 +836,10 @@ mainReconfigureFinish(void *)
 #if USE_SSL_CRTD
     Ssl::Helper::GetInstance()->Init();
 #endif
+#if USE_OPENSSL
+    if (Ssl::CertValidationHelper::GetInstance())
+        Ssl::CertValidationHelper::GetInstance()->Init();
+#endif
 
     redirectInit();
 #if USE_AUTH
@@ -891,7 +881,7 @@ mainReconfigureFinish(void *)
             eventDelete(start_announce, NULL);
     }
 
-    writePidFile();            /* write PID file */
+    writePidFile();     /* write PID file */
 
     reconfiguring = 0;
 }
@@ -900,26 +890,20 @@ static void
 mainRotate(void)
 {
     icmpEngine.Close();
-#if USE_DNSHELPER
-    dnsShutdown();
-#endif
     redirectShutdown();
 #if USE_AUTH
     authenticateRotate();
 #endif
     externalAclShutdown();
 
-    _db_rotate_log();          /* cache.log */
+    _db_rotate_log();       /* cache.log */
     storeDirWriteCleanLogs(1);
-    storeLogRotate();          /* store.log */
-    accessLogRotate();         /* access.log */
+    storeLogRotate();       /* store.log */
+    accessLogRotate();      /* access.log */
 #if ICAP_CLIENT
     icapLogRotate();               /*icap.log*/
 #endif
     icmpEngine.Open();
-#if USE_DNSHELPER
-    dnsInit();
-#endif
     redirectInit();
 #if USE_AUTH
     authenticateInit(&Auth::TheConfig);
@@ -931,7 +915,7 @@ static void
 setEffectiveUser(void)
 {
     keepCapabilities();
-    leave_suid();              /* Run as non privilegied user */
+    leave_suid();       /* Run as non privilegied user */
 #if _SQUID_OS2_
 
     return;
@@ -946,23 +930,42 @@ setEffectiveUser(void)
     }
 }
 
+/// changes working directory, providing error reporting
+static bool
+mainChangeDir(const char *dir)
+{
+    if (chdir(dir) == 0)
+        return true;
+
+    debugs(50, DBG_CRITICAL, "cannot change current directory to " << dir <<
+           ": " << xstrerror());
+    return false;
+}
+
+/// set the working directory.
 static void
 mainSetCwd(void)
 {
-    char pathbuf[MAXPATHLEN];
+    static bool chrooted = false;
+    if (Config.chroot_dir && !chrooted) {
+        chrooted = true;
+
+        if (chroot(Config.chroot_dir) != 0)
+            fatalf("chroot to %s failed: %s", Config.chroot_dir, xstrerror());
+
+        if (!mainChangeDir("/"))
+            fatalf("chdir to / after chroot to %s failed", Config.chroot_dir);
+    }
 
-    if (Config.coredump_dir) {
-        if (0 == strcmp("none", Config.coredump_dir)) {
-            (void) 0;
-        } else if (chdir(Config.coredump_dir) == 0) {
+    if (Config.coredump_dir && strcmp("none", Config.coredump_dir) != 0) {
+        if (mainChangeDir(Config.coredump_dir)) {
             debugs(0, DBG_IMPORTANT, "Set Current Directory to " << Config.coredump_dir);
             return;
-        } else {
-            debugs(50, DBG_CRITICAL, "chdir: " << Config.coredump_dir << ": " << xstrerror());
         }
     }
 
     /* If we don't have coredump_dir or couldn't cd there, report current dir */
+    char pathbuf[MAXPATHLEN];
     if (getcwd(pathbuf, MAXPATHLEN)) {
         debugs(0, DBG_IMPORTANT, "Current Directory is " << pathbuf);
     } else {
@@ -974,10 +977,7 @@ static void
 mainInitialize(void)
 {
     /* chroot if configured to run inside chroot */
-
-    if (Config.chroot_dir && (chroot(Config.chroot_dir) != 0 || chdir("/") != 0)) {
-        fatal("failed to chroot");
-    }
+    mainSetCwd();
 
     if (opt_catch_signals) {
         squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
@@ -996,17 +996,11 @@ mainInitialize(void)
 
     fd_open(fileno(debug_log), FD_LOG, Debug::cache_log);
 
-#if MEM_GEN_TRACE
-
-    log_trace_init("/tmp/squid.alloc");
-
-#endif
-
     debugs(1, DBG_CRITICAL, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
+    debugs(1, DBG_CRITICAL, "Service Name: " << service_name);
 
 #if _SQUID_WINDOWS_
     if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
-        debugs(1, DBG_CRITICAL, "Running as " << WIN32_Service_name << " Windows System Service on " << WIN32_OS_string);
         debugs(1, DBG_CRITICAL, "Service command line is: " << WIN32_Service_Command_Line);
     } else
         debugs(1, DBG_CRITICAL, "Running on " << WIN32_OS_string);
@@ -1019,7 +1013,7 @@ mainInitialize(void)
     setSystemLimits();
     debugs(1, DBG_IMPORTANT, "With " << Squid_MaxFD << " file descriptors available");
 
-#if _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
 
     debugs(1, DBG_IMPORTANT, "With " << _getmaxstdio() << " CRT stdio descriptors available");
 
@@ -1033,7 +1027,7 @@ mainInitialize(void)
 #endif
 
     if (!configured_once)
-        disk_init();           /* disk_init must go before ipcache_init() */
+        disk_init();        /* disk_init must go before ipcache_init() */
 
     ipcache_init();
 
@@ -1047,15 +1041,23 @@ mainInitialize(void)
     Ssl::Helper::GetInstance()->Init();
 #endif
 
+#if USE_OPENSSL
+    if (!configured_once)
+        Ssl::initialize_session_cache();
+
+    if (Ssl::CertValidationHelper::GetInstance())
+        Ssl::CertValidationHelper::GetInstance()->Init();
+#endif
+
     redirectInit();
 #if USE_AUTH
     authenticateInit(&Auth::TheConfig);
 #endif
     externalAclInit();
 
-    httpHeaderInitModule();    /* must go before any header processing (e.g. the one in errorInitialize) */
+    httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
 
-    httpReplyInitModule();     /* must go before accepting replies */
+    httpReplyInitModule();  /* must go before accepting replies */
 
     errorInitialize();
 
@@ -1088,8 +1090,6 @@ mainInitialize(void)
         statInit();
         storeInit();
         mainSetCwd();
-        /* after this point we want to see the mallinfo() output */
-        do_mallinfo = 1;
         mimeInit(Config.mimeTablePathname);
         refreshInit();
 #if USE_DELAY_POOLS
@@ -1133,7 +1133,7 @@ mainInitialize(void)
         no_suid();
 
     if (!configured_once)
-        writePidFile();                /* write PID file */
+        writePidFile();     /* write PID file */
 
 #if defined(_SQUID_LINUX_THREADS_)
 
@@ -1220,19 +1220,29 @@ int SquidMain(int argc, char **argv);
 static int SquidMainSafe(int argc, char **argv);
 
 #if USE_WIN32_SERVICE
-/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
+/* Entry point for Windows services */
 extern "C" void WINAPI
 SquidWinSvcMain(int argc, char **argv)
 {
     SquidMainSafe(argc, argv);
 }
-#else
+#endif
+
 int
 main(int argc, char **argv)
 {
+#if USE_WIN32_SERVICE
+    SetErrorMode(SEM_NOGPFAULTERRORBOX);
+    if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION))
+        return WIN32_StartService(argc, argv);
+    else {
+        WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
+        opt_no_daemon = 1;
+    }
+#endif
+
     return SquidMainSafe(argc, argv);
 }
-#endif
 
 static int
 SquidMainSafe(int argc, char **argv)
@@ -1281,10 +1291,6 @@ SquidMain(int argc, char **argv)
 {
     ConfigureCurrentKid(argv[0]);
 
-#if HAVE_SBRK
-    sbrk_start = sbrk(0);
-#endif
-
     Debug::parseOptions(NULL);
     debug_log = stderr;
 
@@ -1370,7 +1376,7 @@ SquidMain(int argc, char **argv)
 
         Mem::Init();
 
-        storeFsInit();         /* required for config parsing */
+        storeFsInit();      /* required for config parsing */
 
         /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
         Fs::Init();
@@ -1415,11 +1421,8 @@ SquidMain(int argc, char **argv)
     /* send signal to running copy and exit */
     if (opt_send_signal != -1) {
         /* chroot if configured to run inside chroot */
-
+        mainSetCwd();
         if (Config.chroot_dir) {
-            if (chroot(Config.chroot_dir))
-                fatal("failed to chroot");
-
             no_suid();
         } else {
             leave_suid();
@@ -1431,9 +1434,9 @@ SquidMain(int argc, char **argv)
 
     debugs(1,2, HERE << "Doing post-config initialization\n");
     leave_suid();
-    ActivateRegistered(rrFinalizeConfig);
-    ActivateRegistered(rrClaimMemoryNeeds);
-    ActivateRegistered(rrAfterConfig);
+    RunRegisteredHere(RegisteredRunner::finalizeConfig);
+    RunRegisteredHere(RegisteredRunner::claimMemoryNeeds);
+    RunRegisteredHere(RegisteredRunner::useConfig);
     enter_suid();
 
     if (!opt_no_daemon && Config.workers > 0)
@@ -1441,13 +1444,10 @@ SquidMain(int argc, char **argv)
 
     if (opt_create_swap_dirs) {
         /* chroot if configured to run inside chroot */
-
-        if (Config.chroot_dir && chroot(Config.chroot_dir)) {
-            fatal("failed to chroot");
-        }
+        mainSetCwd();
 
         setEffectiveUser();
-        debugs(0, DBG_CRITICAL, "Creating Swap Directories");
+        debugs(0, DBG_CRITICAL, "Creating missing swap directories");
         Store::Root().create();
 
         return 0;
@@ -1486,7 +1486,7 @@ SquidMain(int argc, char **argv)
     /* main loop */
     EventLoop mainLoop;
 
-    SignalEngine signalEngine(mainLoop);
+    SignalEngine signalEngine;
 
     mainLoop.registerEngine(&signalEngine);
 
@@ -1576,7 +1576,7 @@ sendSignal(void)
     exit(0);
 }
 
-#if !_SQUID_MSWIN_
+#if !_SQUID_WINDOWS_
 /*
  * This function is run when Squid is in daemon mode, just
  * before the parent forks and starts up the child process.
@@ -1619,7 +1619,7 @@ mainStartScript(const char *prog)
     }
 }
 
-#endif /* _SQUID_MSWIN_ */
+#endif /* _SQUID_WINDOWS_ */
 
 static int
 checkRunningPid(void)
@@ -1649,7 +1649,7 @@ checkRunningPid(void)
 static void
 watch_child(char *argv[])
 {
-#if !_SQUID_MSWIN_
+#if !_SQUID_WINDOWS_
     char *prog;
 #if _SQUID_NEXT_
 
@@ -1795,9 +1795,9 @@ watch_child(char *argv[])
 
         if (!TheKids.someRunning() && !TheKids.shouldRestartSome()) {
             leave_suid();
-            DeactivateRegistered(rrAfterConfig);
-            DeactivateRegistered(rrClaimMemoryNeeds);
-            DeactivateRegistered(rrFinalizeConfig);
+            // XXX: Master process has no main loop and, hence, should not call
+            // RegisteredRunner::startShutdown which promises a loop iteration.
+            RunRegisteredHere(RegisteredRunner::finishShutdown);
             enter_suid();
 
             if (TheKids.someSignaled(SIGINT) || TheKids.someSignaled(SIGTERM)) {
@@ -1818,7 +1818,7 @@ watch_child(char *argv[])
     }
 
     /* NOTREACHED */
-#endif /* _SQUID_MSWIN_ */
+#endif /* _SQUID_WINDOWS_ */
 
 }
 
@@ -1839,6 +1839,10 @@ SquidShutdown()
     dnsShutdown();
 #if USE_SSL_CRTD
     Ssl::Helper::GetInstance()->Shutdown();
+#endif
+#if USE_OPENSSL
+    if (Ssl::CertValidationHelper::GetInstance())
+        Ssl::CertValidationHelper::GetInstance()->Shutdown();
 #endif
     redirectShutdown();
     externalAclShutdown();
@@ -1878,20 +1882,17 @@ SquidShutdown()
 
     Store::Root().sync(); /* Flush pending object writes/unlinks */
 
-    unlinkdClose();      /* after sync/flush. NOP if !USE_UNLINKD */
+    unlinkdClose();   /* after sync/flush. NOP if !USE_UNLINKD */
 
     storeDirWriteCleanLogs(0);
     PrintRusage();
     dumpMallocStats();
-    Store::Root().sync();              /* Flush log writes */
+    Store::Root().sync();       /* Flush log writes */
     storeLogClose();
     accessLogClose();
-    Store::Root().sync();              /* Flush log close */
+    Store::Root().sync();       /* Flush log close */
     StoreFileSystem::FreeAllFs();
     DiskIOModule::FreeAllModules();
-    DeactivateRegistered(rrAfterConfig);
-    DeactivateRegistered(rrClaimMemoryNeeds);
-    DeactivateRegistered(rrFinalizeConfig);
 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
 
     configFreeMemory();
@@ -1907,15 +1908,6 @@ SquidShutdown()
     eventFreeMemory();
     mimeFreeMemory();
     errorClean();
-#endif
-#if !XMALLOC_TRACE
-
-    if (opt_no_daemon) {
-        file_close(0);
-        file_close(1);
-        file_close(2);
-    }
-
 #endif
     // clear StoreController
     Store::Root(NULL);
@@ -1924,20 +1916,9 @@ SquidShutdown()
 
     comm_exit();
 
-    memClean();
-
-#if XMALLOC_TRACE
+    RunRegisteredHere(RegisteredRunner::finishShutdown);
 
-    xmalloc_find_leaks();
-
-    debugs(1, DBG_CRITICAL, "Memory used after shutdown: " << xmalloc_total);
-
-#endif
-#if MEM_GEN_TRACE
-
-    log_trace_done();
-
-#endif
+    memClean();
 
     if (IamPrimaryProcess()) {
         if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {