]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/main.cc
Bug #2063: Hide debugging messages before cache.log is opened
[thirdparty/squid.git] / src / main.cc
index 42c2bfebd88c07e2d93d6b2504ee0a37e7384f26..1873745afb6a906eb667c7db66e57be0f917c3cf 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.cc,v 1.390 2004/03/01 01:37:34 adrian Exp $
+ * $Id: main.cc,v 1.453 2007/12/29 18:20:22 hno Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
 #include "squid.h"
 #include "AccessLogEntry.h"
 #include "authenticate.h"
+#include "CacheManager.h"
+#include "ConfigParser.h"
+#include "errorpage.h"
+#include "event.h"
+#include "EventLoop.h"
+#include "ExternalACL.h"
 #include "Store.h"
 #include "ICP.h"
 #include "HttpReply.h"
+#include "pconn.h"
 #include "Mem.h"
 #include "ACLASN.h"
 #include "ACL.h"
 #include "htcp.h"
 #include "StoreFileSystem.h"
+#include "DiskIO/DiskIOModule.h"
 #include "comm.h"
+#if USE_EPOLL
+#include "comm_epoll.h"
+#endif
+#if USE_KQUEUE
+#include "comm_kqueue.h"
+#endif
+#if USE_POLL
+#include "comm_poll.h"
+#endif
+#if USE_SELECT
+#include "comm_select.h"
+#endif
+#if USE_SELECT_WIN32
+#include "comm_select.h"
+#endif
+#include "SquidTime.h"
+#include "SwapDir.h"
+#include "forward.h"
+#include "MemPool.h"
+#include "ICMPSquid.h"
 
 #if USE_WIN32_SERVICE
 
@@ -63,8 +91,8 @@ void WINAPI WIN32_svcHandler(DWORD);
 /* for error reporting from xmalloc and friends */
 SQUIDCEXTERN void (*failure_notify) (const char *);
 
-static int opt_send_signal = -1;
 static int opt_parse_cfg_only = 0;
+static char *opt_syslog_facility = NULL;
 static int icpPortNumOverride = 1;     /* Want to detect "-u 0" */
 static int configured_once = 0;
 #if MALLOC_DBG
@@ -73,6 +101,7 @@ static int malloc_debug_level = 0;
 static volatile int do_reconfigure = 0;
 static volatile int do_rotate = 0;
 static volatile int do_shutdown = 0;
+static volatile int shutdown_status = 0;
 
 static void mainRotate(void);
 static void mainReconfigure(void);
@@ -87,10 +116,12 @@ static void setEffectiveUser(void);
 extern void log_trace_done();
 extern void log_trace_init(char *);
 #endif
-static EVH SquidShutdown;
+static void SquidShutdown(void);
 static void mainSetCwd(void);
 static int checkRunningPid(void);
 
+static CacheManager manager;
+
 #ifndef _SQUID_MSWIN_
 static const char *squid_start_script = "squid_start";
 #endif
@@ -99,14 +130,78 @@ static const char *squid_start_script = "squid_start";
 #include "test_access.c"
 #endif
 
+/* temporary thunk across to the unrefactored store interface */
+
+class StoreRootEngine : public AsyncEngine
+{
+
+public:
+    int checkEvents(int timeout)
+    {
+        Store::Root().callback();
+        return EVENT_IDLE;
+    };
+};
+
+class SignalDispatcher : public CompletionDispatcher
+{
+
+public:
+    SignalDispatcher(EventLoop &loop) : loop(loop), events_dispatched(false) {}
+
+    void addEventLoop(EventLoop * loop);
+    virtual bool dispatch();
+
+private:
+    static void StopEventLoop(void * data)
+    {
+        static_cast<SignalDispatcher *>(data)->loop.stop();
+    }
+
+    EventLoop &loop;
+    bool events_dispatched;
+};
+
+bool
+SignalDispatcher::dispatch()
+{
+    PROF_start(SignalDispatcher_dispatch);
+
+    if (do_reconfigure) {
+        mainReconfigure();
+        do_reconfigure = 0;
+    } else if (do_rotate) {
+        mainRotate();
+        do_rotate = 0;
+    } else if (do_shutdown) {
+        time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
+        debugs(1, 1, "Preparing for shutdown after " << statCounter.client_http.requests << " requests");
+        debugs(1, 1, "Waiting " << wait << " seconds for active connections to finish");
+        do_shutdown = 0;
+        shutting_down = 1;
+#if USE_WIN32_SERVICE
+
+        WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
+#endif
+
+        serverConnectionsClose();
+        eventAdd("SquidShutdown", StopEventLoop, this, (double) (wait + 1), 1, false);
+    }
+
+    bool result = events_dispatched;
+    events_dispatched = false;
+    PROF_stop(SignalDispatcher_dispatch);
+    return result;
+}
+
 static void
 usage(void)
 {
     fprintf(stderr,
 #if USE_WIN32_SERVICE
-            "Usage: %s [-dhirsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
+            "Usage: %s [-cdhirvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
 #else
-            "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n"
+            "Usage: %s [-cdhvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
 #endif
             "       -a port   Specify HTTP port number (default: %d).\n"
             "       -d level  Write debugging to stderr also.\n"
@@ -124,7 +219,8 @@ usage(void)
             "                 default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
             "       -r        Removes a Windows Service (see -n option).\n"
 #endif
-            "       -s        Enable logging to syslog.\n"
+            "       -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"
@@ -153,10 +249,10 @@ mainParseOptions(int argc, char *argv[])
 
 #if USE_WIN32_SERVICE
 
-    while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsu:vz?")) != -1)
+    while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
 #else
 
-    while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1)
+    while ((c = getopt(argc, argv, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
 #endif
 
     {
@@ -195,27 +291,11 @@ mainParseOptions(int argc, char *argv[])
             opt_store_doublecheck = 1;
             break;
 
-        case 'V':
-
-            if (Config.Sockaddr.http)
-                Config.Sockaddr.http->vhost = 1;
-
-#if USE_SSL
-
-            else if (Config.Sockaddr.https)
-                Config.Sockaddr.https->http.vhost = 1;
-
-#endif
-
-            else
-                fatal("No http_port specified\n");
-
-            break;
-
         case 'X':
             /* force full debugging */
+            Debug::parseOptions("debug_options ALL,9");
+            Config.onoff.debug_override_X = 1;
             sigusr2_handle(SIGUSR2);
-
             break;
 
         case 'Y':
@@ -255,6 +335,7 @@ mainParseOptions(int argc, char *argv[])
             break;
 
         case 'k':
+
             if ((int) strlen(optarg) < 1)
                 usage();
 
@@ -288,6 +369,14 @@ mainParseOptions(int argc, char *argv[])
                 opt_send_signal = SIGINT;
             else if (!strncmp(optarg, "kill", strlen(optarg)))
                 opt_send_signal = SIGKILL;
+
+#ifdef SIGTTIN
+
+            else if (!strncmp(optarg, "restart", strlen(optarg)))
+                opt_send_signal = SIGTTIN;      /* exit and restart by parent */
+
+#endif
+
             else if (!strncmp(optarg, "check", strlen(optarg)))
                 opt_send_signal = 0;   /* SIGNULL */
             else if (!strncmp(optarg, "parse", strlen(optarg)))
@@ -301,12 +390,9 @@ mainParseOptions(int argc, char *argv[])
             if (optarg) {
 #if MALLOC_DBG
                 malloc_debug_level = atoi(optarg);
-                /* NOTREACHED */
-                break;
 #else
 
                 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
-                /* NOTREACHED */
 #endif
 
             } else {
@@ -319,6 +405,9 @@ mainParseOptions(int argc, char *argv[])
 
             }
 
+            break;
+            /* NOTREACHED */
+
 #if USE_WIN32_SERVICE
 
         case 'n':
@@ -337,10 +426,13 @@ mainParseOptions(int argc, char *argv[])
 
 #endif
 
+        case 'l':
+            opt_syslog_facility = xstrdup(optarg);
+
         case 's':
 #if HAVE_SYSLOG
 
-            opt_syslog_enable = 1;
+            _db_set_syslog(opt_syslog_facility);
 
             break;
 
@@ -373,6 +465,8 @@ mainParseOptions(int argc, char *argv[])
             /* NOTREACHED */
 
         case 'z':
+            opt_debug_stderr = 1;
+
             opt_create_swap_dirs = 1;
 
             break;
@@ -418,14 +512,20 @@ void
 shut_down(int sig)
 {
     do_shutdown = sig == SIGINT ? -1 : 1;
+#ifdef SIGTTIN
+
+    if (SIGTTIN == sig)
+        shutdown_status = 1;
+
+#endif
 #ifndef _SQUID_MSWIN_
 #ifdef KILL_PARENT_OPT
 
     if (getppid() > 1) {
-        debug(1, 1) ("Killing RunCache, pid %d\n", getppid());
+        debugs(1, 1, "Killing RunCache, pid " << getppid());
 
         if (kill(getppid(), sig) < 0)
-            debug(1, 1) ("kill %d: %s\n", getppid(), xstrerror());
+            debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
     }
 
 #endif
@@ -456,8 +556,13 @@ serverConnectionsOpen(void)
     wccpConnectionOpen();
 #endif
 
+#if USE_WCCPv2
+
+    wccp2ConnectionOpen();
+#endif
+
     clientdbInit();
-    icmpOpen();
+    icmpEngine.Open();
     netdbInit();
     asnInit();
     ACL::Initialize();
@@ -479,14 +584,18 @@ serverConnectionsClose(void)
     htcpSocketShutdown();
 #endif
 
-    icmpClose();
+    icmpEngine.Close();
 #ifdef SQUID_SNMP
 
     snmpConnectionShutdown();
 #endif
 #if USE_WCCP
 
-    wccpConnectionShutdown();
+    wccpConnectionClose();
+#endif
+#if USE_WCCPv2
+
+    wccp2ConnectionClose();
 #endif
 
     asnFreeMemory();
@@ -495,7 +604,7 @@ serverConnectionsClose(void)
 static void
 mainReconfigure(void)
 {
-    debug(1, 1) ("Reconfiguring Squid Cache (version %s)...\n", version_string);
+    debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string << ")...");
     reconfiguring = 1;
     /* Already called serverConnectionsClose and ipcacheShutdownServers() */
     serverConnectionsClose();
@@ -508,10 +617,6 @@ mainReconfigure(void)
 
     snmpConnectionClose();
 #endif
-#if USE_WCCP
-
-    wccpConnectionClose();
-#endif
 #if USE_DNSSERVERS
 
     dnsShutdown();
@@ -530,7 +635,7 @@ mainReconfigure(void)
     refererCloseLog();
     errorClean();
     enter_suid();              /* root to read config file */
-    parseConfigFile(ConfigFile);
+    parseConfigFile(ConfigFile, manager);
     setEffectiveUser();
     _db_init(Config.Log.log, Config.debugOptions);
     ipcache_restart();         /* clear stuck entries */
@@ -557,20 +662,39 @@ mainReconfigure(void)
 
     wccpInit();
 #endif
+#if USE_WCCPv2
+
+    wccp2Init();
+#endif
 
     serverConnectionsOpen();
+
     neighbors_init();
+    neighborsRegisterWithCacheManager(manager);
+
     storeDirOpenSwapLogs();
+
     mimeInit(Config.mimeTablePathname);
+
+    if (Config.onoff.announce) {
+        if (!eventFind(start_announce, NULL))
+            eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
+    } else {
+        if (eventFind(start_announce, NULL))
+            eventDelete(start_announce, NULL);
+    }
+
     writePidFile();            /* write PID file */
-    debug(1, 1) ("Ready to serve requests.\n");
+
+    debugs(1, 1, "Ready to serve requests.");
+
     reconfiguring = 0;
 }
 
 static void
 mainRotate(void)
 {
-    icmpClose();
+    icmpEngine.Close();
 #if USE_DNSSERVERS
 
     dnsShutdown();
@@ -590,7 +714,7 @@ mainRotate(void)
     fwdLogRotate();
 #endif
 
-    icmpOpen();
+    icmpEngine.Open();
 #if USE_DNSSERVERS
 
     dnsInit();
@@ -604,6 +728,7 @@ mainRotate(void)
 static void
 setEffectiveUser(void)
 {
+    keepCapabilities();
     leave_suid();              /* Run as non privilegied user */
 #ifdef _SQUID_OS2_
 
@@ -611,10 +736,10 @@ setEffectiveUser(void)
 #endif
 
     if (geteuid() == 0) {
-        debug(0, 0) ("Squid is not safe to run as root!  If you must\n");
-        debug(0, 0) ("start Squid as root, then you must configure\n");
-        debug(0, 0) ("it to run as a non-priveledged user with the\n");
-        debug(0, 0) ("'cache_effective_user' option in the config file.\n");
+        debugs(0, 0, "Squid is not safe to run as root!  If you must");
+        debugs(0, 0, "start Squid as root, then you must configure");
+        debugs(0, 0, "it to run as a non-priveledged user with the");
+        debugs(0, 0, "'cache_effective_user' option in the config file.");
         fatal("Don't run Squid as root, set 'cache_effective_user'!");
     }
 }
@@ -628,18 +753,18 @@ mainSetCwd(void)
         if (0 == strcmp("none", Config.coredump_dir)) {
             (void) 0;
         } else if (chdir(Config.coredump_dir) == 0) {
-            debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
+            debugs(0, 1, "Set Current Directory to " << Config.coredump_dir);
             return;
         } else {
-            debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
+            debugs(50, 0, "chdir: " << Config.coredump_dir << ": " << xstrerror());
         }
     }
 
     /* If we don't have coredump_dir or couldn't cd there, report current dir */
     if (getcwd(pathbuf, MAXPATHLEN)) {
-        debug(0, 1) ("Current Directory is %s\n", pathbuf);
+        debugs(0, 1, "Current Directory is " << pathbuf);
     } else {
-        debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
+        debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
     }
 }
 
@@ -652,7 +777,7 @@ mainInitialize(void)
 {
     /* chroot if configured to run inside chroot */
 
-    if (Config.chroot_dir && chroot(Config.chroot_dir)) {
+    if (Config.chroot_dir && (chroot(Config.chroot_dir) != 0 || chdir("/") != 0)) {
         fatal("failed to chroot");
     }
 
@@ -679,30 +804,28 @@ mainInitialize(void)
 
 #endif
 
-    debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
-                 version_string,
-                 CONFIG_HOST_TYPE);
+    debugs(1, 0, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
 
 #ifdef _SQUID_WIN32_
 
     if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
-        debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string);
-        debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line);
+        debugs(1, 0, "Running as " << WIN32_Service_name << " Windows System Service on " << WIN32_OS_string);
+        debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line);
     } else
-        debug(1, 0) ("Running on %s\n",WIN32_OS_string);
+        debugs(1, 0, "Running on " << WIN32_OS_string);
 
 #endif
 
-    debug(1, 1) ("Process ID %d\n", (int) getpid());
+    debugs(1, 1, "Process ID " << getpid());
 
-    debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
+    debugs(1, 1, "With " << Squid_MaxFD << " file descriptors available");
 
 #ifdef _SQUID_MSWIN_
 
-    debug(1, 1) ("With %d CRT stdio descriptors available\n", _getmaxstdio());
+    debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
 
     if (WIN32_Socks_initialized)
-        debug(1, 1)("Windows sockets initialized\n");
+        debugs(1, 1, "Windows sockets initialized");
 
 #endif
 
@@ -765,32 +888,110 @@ mainInitialize(void)
 #endif
 
         urlInitialize();
-        cachemgrInit();
         statInit();
         storeInit();
         mainSetCwd();
         /* after this point we want to see the mallinfo() output */
         do_mallinfo = 1;
         mimeInit(Config.mimeTablePathname);
-        pconnInit();
         refreshInit();
 #if DELAY_POOLS
 
         DelayPools::Init();
 #endif
 
-        fwdInit();
+        FwdState::initModule();
+        /* register the modules in the cache manager menus */
+        accessLogRegisterWithCacheManager(manager);
+        asnRegisterWithCacheManager(manager);
+        authenticateRegisterWithCacheManager(&Config.authConfiguration, manager);
+#if USE_CARP
+
+        carpRegisterWithCacheManager(manager);
+#endif
+
+        cbdataRegisterWithCacheManager(manager);
+        /* These use separate calls so that the comm loops can eventually
+         * coexist.
+         */
+#ifdef USE_EPOLL
+
+        commEPollRegisterWithCacheManager(manager);
+#endif
+#ifdef USE_KQUEUE
+
+        commKQueueRegisterWithCacheManager(manager);
+#endif
+#ifdef USE_POLL
+
+        commPollRegisterWithCacheManager(manager);
+#endif
+#ifdef USE_SELECT
+
+        commSelectRegisterWithCacheManager(manager);
+#endif
+
+        clientdbRegisterWithCacheManager(manager);
+#if DELAY_POOLS
+
+        DelayPools::RegisterWithCacheManager(manager);
+#endif
+
+        DiskIOModule::RegisterAllModulesWithCacheManager(manager);
+#if USE_DNSSERVERS
+
+        dnsRegisterWithCacheManager(manager);
+#endif
+
+        eventInit(manager);
+        externalAclRegisterWithCacheManager(manager);
+        fqdncacheRegisterWithCacheManager(manager);
+        FwdState::RegisterWithCacheManager(manager);
+        httpHeaderRegisterWithCacheManager(manager);
+#if !USE_DNSSERVERS
+
+        idnsRegisterWithCacheManager(manager);
+#endif
+
+        ipcacheRegisterWithCacheManager(manager);
+        Mem::RegisterWithCacheManager(manager);
+        netdbRegisterWitHCacheManager(manager);
+        PconnModule::GetInstance()->registerWithCacheManager(manager);
+        redirectRegisterWithCacheManager(manager);
+        refreshRegisterWithCacheManager(manager);
+        statRegisterWithCacheManager(manager);
+        storeDigestRegisterWithCacheManager(manager);
+        StoreFileSystem::RegisterAllFsWithCacheManager(manager);
+        storeRegisterWithCacheManager(manager);
+        storeLogRegisterWithCacheManager(manager);
+#if DEBUGSTRINGS
+
+        StringRegistry::Instance().registerWithCacheManager(manager);
+#endif
+
+#if    USE_XPROF_STATS
+
+        xprofRegisterWithCacheManager(manager);
+#endif
+
     }
 
 #if USE_WCCP
     wccpInit();
 
+#endif
+#if USE_WCCPv2
+
+    wccp2Init();
+
 #endif
 
     serverConnectionsOpen();
 
     neighbors_init();
 
+    neighborsRegisterWithCacheManager(manager);
+
     if (Config.chroot_dir)
         no_suid();
 
@@ -817,12 +1018,18 @@ mainInitialize(void)
 
     squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
 
+#ifdef SIGTTIN
+
+    squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+
+#endif
+
     memCheckInit();
 
-    debug(1, 1) ("Ready to serve requests.\n");
+    debugs(1, 1, "Ready to serve requests.");
 
     if (!configured_once) {
-        eventAdd("storeMaintain", storeMaintainSwapSpace, NULL, 1.0, 1);
+        eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
 
         if (Config.onoff.announce)
             eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
@@ -848,41 +1055,43 @@ mainInitialize(void)
 #if USE_WIN32_SERVICE
 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
 extern "C" void WINAPI
-    SquidMain(int argc, char **argv)
+    SquidWinSvcMain(int argc, char **argv)
+{
+    SquidMain(argc, argv);
+}
+
+int
+SquidMain(int argc, char **argv)
 #else
 int
 main(int argc, char **argv)
 #endif
 {
-    int errcount = 0;
-    int n;                     /* # of GC'd objects */
     mode_t oldmask;
+#ifdef _SQUID_WIN32_
+
+    int WIN32_init_err;
+#endif
 
 #if HAVE_SBRK
 
     sbrk_start = sbrk(0);
 #endif
 
+    Debug::parseOptions(NULL);
     debug_log = stderr;
 
-    if (FD_SETSIZE < Squid_MaxFD)
-        Squid_MaxFD = FD_SETSIZE;
+#if defined(SQUID_MAXFD_LIMIT)
 
-#ifdef _SQUID_WIN32_
-#ifdef USE_WIN32_SERVICE
+    if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
+        Squid_MaxFD = SQUID_MAXFD_LIMIT;
 
-    if (WIN32_Subsystem_Init(&argc, &argv))
-        return;
+#endif
 
-#else
+#ifdef _SQUID_WIN32_
 
-    {
-        int WIN32_init_err;
-
-        if ((WIN32_init_err = WIN32_Subsystem_Init()))
-            return WIN32_init_err;
-    }
-#endif
+    if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
+        return WIN32_init_err;
 
 #endif
 
@@ -916,18 +1125,6 @@ main(int argc, char **argv)
     if (oldmask)
         umask(oldmask);
 
-    memset(&local_addr, '\0', sizeof(struct in_addr));
-
-    safe_inet_addr(localhost, &local_addr);
-
-    memset(&any_addr, '\0', sizeof(struct in_addr));
-
-    safe_inet_addr("0.0.0.0", &any_addr);
-
-    memset(&no_addr, '\0', sizeof(struct in_addr));
-
-    safe_inet_addr("255.255.255.255", &no_addr);
-
     squid_srandom(time(NULL));
 
     getCurrentTime();
@@ -946,19 +1143,22 @@ main(int argc, char **argv)
 
 #if USE_WIN32_SERVICE
 
-    if (opt_install_service) {
+    if (opt_install_service)
+    {
         WIN32_InstallService();
-        return;
+        return 0;
     }
 
-    if (opt_remove_service) {
+    if (opt_remove_service)
+    {
         WIN32_RemoveService();
-        return;
+        return 0;
     }
 
-    if (opt_command_line) {
+    if (opt_command_line)
+    {
         WIN32_SetServiceCommandLine();
-        return;
+        return 0;
     }
 
 #endif
@@ -973,38 +1173,24 @@ main(int argc, char **argv)
 
         assert(!configured_once);
 
-#if USE_LEAKFINDER
-
-        leakInit();
-
-#endif
-
         Mem::Init();
 
-        cbdataInit();
-
-        eventInit();           /* eventInit() is required for config parsing */
-
         storeFsInit();         /* required for config parsing */
 
+        /* May not be needed for parsing, have not audited for such */
+        DiskIOModule::SetupAllModules();
+
         /* Shouldn't be needed for config parsing, but have not audited for such */
         StoreFileSystem::SetupAllFs();
 
-        authenticateSchemeInit();      /* required for config parsign */
+        /* we may want the parsing process to set this up in the future */
+        Store::Root(new StoreController);
 
-        parse_err = parseConfigFile(ConfigFile);
+        parse_err = parseConfigFile(ConfigFile, manager);
 
         if (opt_parse_cfg_only)
-#if USE_WIN32_SERVICE
-
-            return;
-
-#else
 
             return parse_err;
-
-#endif
-
     }
     if (-1 == opt_send_signal)
         if (checkRunningPid())
@@ -1025,18 +1211,25 @@ main(int argc, char **argv)
 #endif
 
     /* send signal to running copy and exit */
-    if (opt_send_signal != -1) {
+    if (opt_send_signal != -1)
+    {
         /* chroot if configured to run inside chroot */
 
-        if (Config.chroot_dir && chroot(Config.chroot_dir)) {
-            fatal("failed to chroot");
+        if (Config.chroot_dir) {
+            if (chroot(Config.chroot_dir))
+                fatal("failed to chroot");
+
+            no_suid();
+        } else {
+            leave_suid();
         }
 
         sendSignal();
         /* NOTREACHED */
     }
 
-    if (opt_create_swap_dirs) {
+    if (opt_create_swap_dirs)
+    {
         /* chroot if configured to run inside chroot */
 
         if (Config.chroot_dir && chroot(Config.chroot_dir)) {
@@ -1044,16 +1237,10 @@ main(int argc, char **argv)
         }
 
         setEffectiveUser();
-        debug(0, 0) ("Creating Swap Directories\n");
-        storeCreateSwapDirectories();
-#if USE_WIN32_SERVICE
-
-        return;
-#else
+        debugs(0, 0, "Creating Swap Directories");
+        Store::Root().create();
 
         return 0;
-#endif
-
     }
 
     if (!opt_no_daemon)
@@ -1061,16 +1248,13 @@ main(int argc, char **argv)
 
     setMaxFD();
 
-    if (opt_catch_signals)
-        for (n = Squid_MaxFD; n > 2; n--)
-            close(n);
-
     /* init comm module */
     comm_init();
 
     comm_select_init();
 
-    if (opt_no_daemon) {
+    if (opt_no_daemon)
+    {
         /* we have to init fdstat here. */
         fd_open(0, FD_LOG, "stdin");
         fd_open(1, FD_LOG, "stdout");
@@ -1092,95 +1276,47 @@ main(int argc, char **argv)
 #endif
 
     /* main loop */
+    EventLoop mainLoop;
 
-    for (;;) {
-        if (do_reconfigure) {
-            mainReconfigure();
-            do_reconfigure = 0;
-#if defined(_SQUID_MSWIN_) && defined(_DEBUG)
-
-        } else if (do_debug) {
-            do_debug = 0;
-            __asm int 3;
-#endif
-
-        } else if (do_rotate) {
-            mainRotate();
-            do_rotate = 0;
-        } else if (do_shutdown) {
-            time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
-            debug(1, 1) ("Preparing for shutdown after %d requests\n",
-                         statCounter.client_http.requests);
-            debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
-                         (int) wait);
-            do_shutdown = 0;
-            shutting_down = 1;
-#if USE_WIN32_SERVICE
-
-            WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
-#endif
+    SignalDispatcher signal_dispatcher(mainLoop);
 
-            serverConnectionsClose();
-            eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
-        }
+    mainLoop.registerDispatcher(&signal_dispatcher);
 
-        eventRun();
-        int loop_delay = eventNextTime();
+    /* TODO: stop requiring the singleton here */
+    mainLoop.registerDispatcher(EventDispatcher::GetInstance());
 
-        if (loop_delay < 0)
-            loop_delay = 0;
+    /* TODO: stop requiring the singleton here */
+    mainLoop.registerEngine(EventScheduler::GetInstance());
 
-        /* Attempt any pending storedir IO */
-        storeDirCallback();
+    StoreRootEngine store_engine;
 
-        comm_calliocallback();
+    mainLoop.registerEngine(&store_engine);
 
-        /* and again to deal with indirectly queued events
-         * resulting from the first call. These are usually
-         * callbacks and should be dealt with immediately.
-         */
-        if (comm_iocallbackpending())
-            comm_calliocallback();
+    CommDispatcher comm_dispatcher;
 
-        switch (comm_select(loop_delay)) {
+    mainLoop.registerDispatcher(&comm_dispatcher);
 
-        case COMM_OK:
-            errcount = 0;      /* reset if successful */
-            break;
-
-        case COMM_ERROR:
-            errcount++;
-            debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
+    CommSelectEngine comm_engine;
 
-            if (errcount == 10)
-                fatal_dump("Select Loop failed!");
+    mainLoop.registerEngine(&comm_engine);
 
-            break;
+    mainLoop.setPrimaryEngine(&comm_engine);
 
-        case COMM_TIMEOUT:
-            break;
+    /* use the standard time service */
+    TimeEngine time_engine;
 
-        case COMM_SHUTDOWN:
-            SquidShutdown(NULL);
+    mainLoop.setTimeService(&time_engine);
 
-            break;
+    mainLoop.run();
 
-        default:
-            fatal_dump("MAIN: Internal error -- this should never happen.");
+    if (mainLoop.errcount == 10)
+        fatal_dump("Event loop exited with failure.");
 
-            break;
-        }
-    }
+    /* shutdown squid now */
+    SquidShutdown();
 
     /* NOTREACHED */
-#if USE_WIN32_SERVICE
-    return;
-
-#else
-
     return 0;
-
-#endif
 }
 
 static void
@@ -1188,6 +1324,11 @@ sendSignal(void)
 {
     pid_t pid;
     debug_log = stderr;
+
+    if (strcmp(Config.pidFilename, "none") == 0) {
+        debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
+    }
+
     pid = readPidFile();
 
     if (pid > 1) {
@@ -1253,8 +1394,8 @@ mainStartScript(const char *prog)
 
     if ((cpid = fork()) == 0) {
         /* child */
-        execl(script, squid_start_script, 0);
-        _exit(0);
+        execl(script, squid_start_script, (char *)NULL);
+        _exit(-1);
     } else {
         do {
 #ifdef _SQUID_NEXT_
@@ -1276,7 +1417,10 @@ static int
 checkRunningPid(void)
 {
     pid_t pid;
-    debug_log = stderr;
+
+    if (!debug_log)
+        debug_log = stderr;
+
     pid = readPidFile();
 
     if (pid < 2)
@@ -1307,7 +1451,11 @@ watch_child(char *argv[])
 #endif
 
     pid_t pid;
+#ifdef TIOCNOTTY
+
     int i;
+#endif
+
     int nullfd;
 
     if (*(argv[0]) == '(')
@@ -1334,17 +1482,16 @@ watch_child(char *argv[])
 
 #endif
 
-
     /*
      * RBCOLLINS - if cygwin stackdumps when squid is run without
      * -N, check the cygwin1.dll version, it needs to be AT LEAST
      * 1.1.3.  execvp had a bit overflow error in a loop..
      */
     /* Connect stdio to /dev/null in daemon mode */
-    nullfd = open("/dev/null", O_RDWR | O_TEXT);
+    nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
 
     if (nullfd < 0)
-        fatalf("/dev/null: %s\n", xstrerror());
+        fatalf(_PATH_DEVNULL " %s\n", xstrerror());
 
     dup2(nullfd, 0);
 
@@ -1353,10 +1500,6 @@ watch_child(char *argv[])
         dup2(nullfd, 2);
     }
 
-    /* Close all else */
-    for (i = 3; i < Squid_MaxFD; i++)
-        close(i);
-
     for (;;) {
         mainStartScript(argv[0]);
 
@@ -1396,8 +1539,8 @@ watch_child(char *argv[])
                    pid, WEXITSTATUS(status));
         } else if (WIFSIGNALED(status)) {
             syslog(LOG_NOTICE,
-                   "Squid Parent: child process %d exited due to signal %d",
-                   pid, WTERMSIG(status));
+                   "Squid Parent: child process %d exited due to signal %d with status %d",
+                   pid, WTERMSIG(status), WEXITSTATUS(status));
         } else {
             syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
         }
@@ -1423,6 +1566,12 @@ watch_child(char *argv[])
                 exit(0);
                 break;
 
+            case SIGINT:
+            case SIGTERM:
+               syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
+                exit(1);
+                break;
+
             default:
                 break;
             }
@@ -1434,16 +1583,17 @@ watch_child(char *argv[])
 
     /* NOTREACHED */
 #endif /* _SQUID_MSWIN_ */
+
 }
 
 static void
-SquidShutdown(void *unused)
+SquidShutdown()
 {
 #if USE_WIN32_SERVICE
     WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
 #endif
 
-    debug(1, 1) ("Shutting down...\n");
+    debugs(1, 1, "Shutting down...");
 #if USE_DNSSERVERS
 
     dnsShutdown();
@@ -1467,6 +1617,10 @@ SquidShutdown(void *unused)
 
     wccpConnectionClose();
 #endif
+#if USE_WCCPv2
+
+    wccp2ConnectionClose();
+#endif
 
     releaseServerSockets();
     commCloseAllSockets();
@@ -1476,20 +1630,21 @@ SquidShutdown(void *unused)
 #endif
 
     authenticateShutdown();
-#if USE_UNLINKD
-
-    unlinkdClose();
-#endif
 #if USE_WIN32_SERVICE
 
     WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
 #endif
 
-    storeDirSync();            /* Flush pending object writes/unlinks */
+    Store::Root().sync(); /* Flush pending object writes/unlinks */
+#if USE_UNLINKD
+
+    unlinkdClose();      /* after sync/flush */
+#endif
+
     storeDirWriteCleanLogs(0);
     PrintRusage();
     dumpMallocStats();
-    storeDirSync();            /* Flush log writes */
+    Store::Root().sync();              /* Flush log writes */
     storeLogClose();
     accessLogClose();
     useragentLogClose();
@@ -1499,9 +1654,10 @@ SquidShutdown(void *unused)
     fwdUninit();
 #endif
 
-    storeDirSync();            /* Flush log close */
+    Store::Root().sync();              /* Flush log close */
     StoreFileSystem::FreeAllFs();
-#if PURIFY || XMALLOC_TRACE
+    DiskIOModule::FreeAllModules();
+#if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
 
     configFreeMemory();
     storeFreeMemory();
@@ -1528,7 +1684,7 @@ SquidShutdown(void *unused)
 #endif
     fdDumpOpen();
 
-    fdFreeMemory();
+    comm_exit();
 
     memClean();
 
@@ -1536,7 +1692,7 @@ SquidShutdown(void *unused)
 
     xmalloc_find_leaks();
 
-    debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
+    debugs(1, 0, "Memory used after shutdown: " << xmalloc_total);
 
 #endif
 #if MEM_GEN_TRACE
@@ -1551,11 +1707,19 @@ SquidShutdown(void *unused)
         leave_suid();
     }
 
-    debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
-                 version_string);
+    debugs(1, 1, "Squid Cache (Version " << version_string << "): Exiting normally.");
 
-    if (debug_log)
-        fclose(debug_log);
+    /*
+     * DPW 2006-10-23
+     * We used to fclose(debug_log) here if it was set, but then
+     * we forgot to set it to NULL.  That caused some coredumps
+     * because exit() ends up calling a bunch of destructors and
+     * such.   So rather than forcing the debug_log to close, we'll
+     * leave it open so that those destructors can write some
+     * debugging if necessary.  The file will be closed anyway when
+     * the process truly exits.
+     */
 
-    exit(0);
+    exit(shutdown_status);
 }
+