bugfix: hostname was not requeried on HUP
authorRainer Gerhards <rgerhards@adiscon.com>
Wed, 11 Apr 2012 09:18:41 +0000 (11:18 +0200)
committerRainer Gerhards <rgerhards@adiscon.com>
Wed, 11 Apr 2012 09:18:41 +0000 (11:18 +0200)
Thanks to Marius Tomaschewski for reporting this bug.

ChangeLog
doc/rsyslog_conf_global.html
doc/v5compatibility.html
runtime/glbl.c
tools/syslogd.c

index de33a6c..31f5fe9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,8 @@
 ---------------------------------------------------------------------------
+Version 5.8.11  [V5-stable] 2012-04-??
+- bugfix: hostname was not requeried on HUP
+  Thanks to Marius Tomaschewski for reporting this bug.
+---------------------------------------------------------------------------
 Version 5.8.10  [V5-stable] 2012-04-05
 - bugfix: segfault on startup if $actionqueuefilename was missing for disk
   queue config
index 21786a7..83eb876 100644 (file)
@@ -152,15 +152,6 @@ our paper on <a href="multi_ruleset.html">using multiple rule sets in rsyslog</a
 <li><a href="rsconf1_gssforwardservicename.html">$GssForwardServiceName</a></li>
 <li><a href="rsconf1_gsslistenservicename.html">$GssListenServiceName</a></li>
 <li><a href="rsconf1_gssmode.html">$GssMode</a></li>
-<li>$HUPisRestart [on/<b>off</b>] - if set to on, a HUP is a full daemon restart. This means any queued messages are discarded (depending
-on queue configuration, of course) all modules are unloaded and reloaded. This mode keeps compatible with sysklogd, but is
-not recommended for use with rsyslog. To do a full restart, simply stop and start the daemon. The default (since 4.5.1) is "off".
-If it is set to "off", a HUP will only close open files. This is a much quicker action and usually
-the only one that is needed e.g. for log rotation. <b>Restart-type HUPs (value "on") are depricated</b> 
-and will go away in rsyslog v5. So it is a good idea to change anything that needs it, now.
-Usually that should not be a big issue, as the restart-type HUP can easily be replaced by
-something along the lines of &quot;/etc/init.d/rsyslog restart&quot;.
-</li>
 <li><a href="rsconf1_includeconfig.html">$IncludeConfig</a></li><li>MainMsgQueueCheckpointInterval &lt;number&gt;</li>
 <li><b>$LocalHostName</b> [name] - this directive permits to overwrite the system
 hostname with the one specified in the directive. If the directive is given
index cc875b7..fc4289c 100644 (file)
@@ -16,6 +16,7 @@ available. This processing was redundant and had a lot a drawbacks.
 For details, please see the
 <a href="v4compatibility.html">rsyslog v4 compatibility notes</a> which elaborate
 on the reasons and the (few) things you may need to change.
+<p>Please note that starting with 5.8.11 HUP will also requery the local hostname.
 <h2>Queue on-disk format</h2>
 <p>The queue information file format has been changed. When upgrading from v4 to
 v5, make sure that the queue is emptied and no on-disk structure present. We did
index dea5a17..b6dc728 100644 (file)
@@ -69,10 +69,10 @@ static int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records
 static int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */
 static int bDisableDNS = 0; /* don't look up IP addresses of remote messages */
 static prop_t *propLocalHostName = NULL;/* our hostname as FQDN - read-only after startup */
-static uchar *LocalHostName = NULL;/* our hostname  - read-only after startup */
+static uchar *LocalHostName = NULL;/* our hostname  - read-only after startup, except HUP */
 static uchar *LocalHostNameOverride = NULL;/* user-overridden hostname - read-only after startup */
-static uchar *LocalFQDNName = NULL;/* our hostname as FQDN - read-only after startup */
-static uchar *LocalDomain;     /* our local domain name  - read-only after startup */
+static uchar *LocalFQDNName = NULL;/* our hostname as FQDN - read-only after startup, except HUP */
+static uchar *LocalDomain = NULL;/* our local domain name  - read-only after startup, except HUP */
 static char **StripDomains = NULL;/* these domains may be stripped before writing logs  - r/o after s.u., never touched by init */
 static char **LocalHosts = NULL;/* these hosts are logged with their hostname  - read-only after startup, never touched by init */
 static uchar *pszDfltNetstrmDrvr = NULL; /* module name of default netstream driver */
@@ -115,15 +115,12 @@ SIMP_PROP(DefPFFamily, iDefPFFamily, int) /* note that in the future we may chec
 SIMP_PROP(DropMalPTRMsgs, bDropMalPTRMsgs, int)
 SIMP_PROP(Option_DisallowWarning, option_DisallowWarning, int)
 SIMP_PROP(DisableDNS, bDisableDNS, int)
-SIMP_PROP(LocalDomain, LocalDomain, uchar*)
 SIMP_PROP(StripDomains, StripDomains, char**)
 SIMP_PROP(LocalHosts, LocalHosts, char**)
 #ifdef USE_UNLIMITED_SELECT
 SIMP_PROP(FdSetSize, iFdSetSize, int)
 #endif
 
-SIMP_PROP_SET(LocalFQDNName, LocalFQDNName, uchar*)
-SIMP_PROP_SET(LocalHostName, LocalHostName, uchar*)
 SIMP_PROP_SET(DfltNetstrmDrvr, pszDfltNetstrmDrvr, uchar*) /* TODO: use custom function which frees existing value */
 SIMP_PROP_SET(DfltNetstrmDrvrCAF, pszDfltNetstrmDrvrCAF, uchar*) /* TODO: use custom function which frees existing value */
 SIMP_PROP_SET(DfltNetstrmDrvrKeyFile, pszDfltNetstrmDrvrKeyFile, uchar*) /* TODO: use custom function which frees existing value */
@@ -202,6 +199,19 @@ finalize_it:
        RETiRet;
 }
 
+/* set our local hostname. Free previous hostname, if it was already set.
+ * Note that we do now do this in a thread
+ * "once in a lifetime" action which can not be undone. -- gerhards, 2009-07-20
+ */
+static rsRetVal
+SetLocalHostName(uchar *newname)
+{
+       free(LocalHostName);
+       LocalHostName = newname;
+       return RS_RET_OK;
+}
+
+
 /* return our local hostname. if it is not set, "[localhost]" is returned
  */
 static uchar*
@@ -227,6 +237,26 @@ done:
 }
 
 
+/* set our local domain name. Free previous domain, if it was already set.
+ */
+static rsRetVal
+SetLocalDomain(uchar *newname)
+{
+       free(LocalDomain);
+       LocalDomain = newname;
+       return RS_RET_OK;
+}
+
+
+/* return our local hostname. if it is not set, "[localhost]" is returned
+ */
+static uchar*
+GetLocalDomain(void)
+{
+       return LocalDomain;
+}
+
+
 /* generate the local hostname property. This must be done after the hostname info
  * has been set as well as PreserveFQDN.
  * rgerhards, 2009-06-30
@@ -271,6 +301,14 @@ GetLocalHostNameProp(void)
 }
 
 
+static rsRetVal
+SetLocalFQDNName(uchar *newname)
+{
+       free(LocalFQDNName);
+       LocalFQDNName = newname;
+       return RS_RET_OK;
+}
+
 /* return the current localhost name as FQDN (requires FQDN to be set) 
  * TODO: we should set the FQDN ourselfs in here!
  */
@@ -373,30 +411,18 @@ ENDobjQueryInterface(glbl)
  */
 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
 {
-       if(pszDfltNetstrmDrvr != NULL) {
-               free(pszDfltNetstrmDrvr);
-               pszDfltNetstrmDrvr = NULL;
-       }
-       if(pszDfltNetstrmDrvrCAF != NULL) {
-               free(pszDfltNetstrmDrvrCAF);
-               pszDfltNetstrmDrvrCAF = NULL;
-       }
-       if(pszDfltNetstrmDrvrKeyFile != NULL) {
-               free(pszDfltNetstrmDrvrKeyFile);
-               pszDfltNetstrmDrvrKeyFile = NULL;
-       }
-       if(pszDfltNetstrmDrvrCertFile != NULL) {
-               free(pszDfltNetstrmDrvrCertFile);
-               pszDfltNetstrmDrvrCertFile = NULL;
-       }
-       if(LocalHostNameOverride != NULL) {
-               free(LocalHostNameOverride);
-               LocalHostNameOverride = NULL;
-       }
-       if(pszWorkDir != NULL) {
-               free(pszWorkDir);
-               pszWorkDir = NULL;
-       }
+       free(pszDfltNetstrmDrvr);
+       pszDfltNetstrmDrvr = NULL;
+       free(pszDfltNetstrmDrvrCAF);
+       pszDfltNetstrmDrvrCAF = NULL;
+       free(pszDfltNetstrmDrvrKeyFile);
+       pszDfltNetstrmDrvrKeyFile = NULL;
+       free(pszDfltNetstrmDrvrCertFile);
+       pszDfltNetstrmDrvrCertFile = NULL;
+       free(LocalHostNameOverride);
+       LocalHostNameOverride = NULL;
+       free(pszWorkDir);
+       pszWorkDir = NULL;
        bDropMalPTRMsgs = 0;
        bOptimizeUniProc = 1;
        bPreserveFQDN = 0;
@@ -437,21 +463,14 @@ ENDObjClassInit(glbl)
  * rgerhards, 2008-04-17
  */
 BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */
-       if(pszDfltNetstrmDrvr != NULL)
-               free(pszDfltNetstrmDrvr);
-       if(pszDfltNetstrmDrvrCAF != NULL)
-               free(pszDfltNetstrmDrvrCAF);
-       if(pszDfltNetstrmDrvrKeyFile != NULL)
-               free(pszDfltNetstrmDrvrKeyFile);
-       if(pszDfltNetstrmDrvrCertFile != NULL)
-               free(pszDfltNetstrmDrvrCertFile);
-       if(pszWorkDir != NULL)
-               free(pszWorkDir);
-       if(LocalHostName != NULL)
-               free(LocalHostName);
+       free(pszDfltNetstrmDrvr);
+       free(pszDfltNetstrmDrvrCAF);
+       free(pszDfltNetstrmDrvrKeyFile);
+       free(pszDfltNetstrmDrvrCertFile);
+       free(pszWorkDir);
+       free(LocalHostName);
        free(LocalHostNameOverride);
-       if(LocalFQDNName != NULL)
-               free(LocalFQDNName);
+       free(LocalFQDNName);
        objRelease(prop, CORE_COMPONENT);
        DESTROY_ATOMIC_HELPER_MUT(mutTerminateInputs);
 ENDObjClassExit(glbl)
index 0b7bbc9..183decb 100644 (file)
@@ -154,6 +154,7 @@ DEFobjCurrIf(net) /* TODO: make go away! */
 
 /* forward definitions */
 static rsRetVal GlobalClassExit(void);
+static rsRetVal queryLocalHostname(void);
 
 
 #ifndef _PATH_LOGCONF 
@@ -1897,6 +1898,11 @@ DEFFUNC_llExecFunc(doHUPActions)
  * is *NOT* the sighup handler. The signal is recorded by the handler, that record
  * detected inside the mainloop and then this function is called to do the
  * real work. -- rgerhards, 2008-10-22
+ * Note: there is a VERY slim chance of a data race when the hostname is reset.
+ * We prefer to take this risk rather than sync all accesses, because to the best
+ * of my analysis it can not really hurt (the actual property is reference-counted)
+ * but the sync would require some extra CPU for *each* message processed.
+ * rgerhards, 2012-04-11
  */
 static inline void
 doHUP(void)
@@ -1912,6 +1918,7 @@ doHUP(void)
                logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0);
        }
 
+       queryLocalHostname(); /* re-read our name */
        ruleset.IterateAllActions(doHUPActions, NULL);
 }
 
@@ -2329,6 +2336,90 @@ GlobalClassExit(void)
 }
 
 
+/* query our host and domain names - we need to do this early as we may emit
+ * rgerhards, 2012-04-11
+ */
+static rsRetVal
+queryLocalHostname(void)
+{
+       uchar *LocalHostName;
+       uchar *LocalDomain;
+       uchar *LocalFQDNName;
+       uchar *p;
+       struct hostent *hent;
+       DEFiRet;
+
+       net.getLocalHostname(&LocalFQDNName);
+       CHKmalloc(LocalHostName = (uchar*) strdup((char*)LocalFQDNName));
+       glbl.SetLocalFQDNName(LocalFQDNName); /* set the FQDN before we modify it */
+       if((p = (uchar*)strchr((char*)LocalHostName, '.'))) {
+               *p++ = '\0';
+               LocalDomain = p;
+       } else {
+               LocalDomain = (uchar*)"";
+
+               /* It's not clearly defined whether gethostname()
+                * should return the simple hostname or the fqdn. A
+                * good piece of software should be aware of both and
+                * we want to distribute good software.  Joey
+                *
+                * Good software also always checks its return values...
+                * If syslogd starts up before DNS is up & /etc/hosts
+                * doesn't have LocalHostName listed, gethostbyname will
+                * return NULL.
+                */
+               /* TODO: gethostbyname() is not thread-safe, but replacing it is
+                * not urgent as we do not run on multiple threads here. rgerhards, 2007-09-25
+                */
+               hent = gethostbyname((char*)LocalHostName);
+               if(hent) {
+                       int i = 0;
+
+                       if(hent->h_aliases) {
+                               size_t hnlen;
+
+                               hnlen = strlen((char *) LocalHostName);
+
+                               for (i = 0; hent->h_aliases[i]; i++) {
+                                       if (!strncmp(hent->h_aliases[i], (char *) LocalHostName, hnlen)
+                                           && hent->h_aliases[i][hnlen] == '.') {
+                                               /* found a matching hostname */
+                                               break;
+                                       }
+                               }
+                       }
+
+                       free(LocalHostName);
+                       if(hent->h_aliases && hent->h_aliases[i]) {
+                               CHKmalloc(LocalHostName = (uchar*)strdup(hent->h_aliases[i]));
+                       } else {
+                               CHKmalloc(LocalHostName = (uchar*)strdup(hent->h_name));
+                       }
+
+                       if((p = (uchar*)strchr((char*)LocalHostName, '.')))
+                       {
+                               *p++ = '\0';
+                               LocalDomain = p;
+                       }
+               }
+       }
+
+       /* Convert to lower case to recognize the correct domain laterly */
+       for(p = LocalDomain ; *p ; p++)
+               *p = (char)tolower((int)*p);
+
+       /* we now have our hostname and can set it inside the global vars.
+        * TODO: think if all of this would better be a runtime function
+        * rgerhards, 2008-04-17
+        */
+       glbl.SetLocalHostName(LocalHostName);
+       glbl.SetLocalDomain(LocalDomain);
+       glbl.GenerateLocalHostNameProperty(); /* must be redone after conf processing, FQDN setting may have changed */
+finalize_it:
+       RETiRet;
+}
+
+
 /* some support for command line option parsing. Any non-trivial options must be
  * buffered until the complete command line has been parsed. This is necessary to
  * prevent dependencies between the options. That, in turn, means we need to have
@@ -2530,9 +2621,7 @@ int realMain(int argc, char **argv)
 {
        DEFiRet;
 
-       register uchar *p;
        int ch;
-       struct hostent *hent;
        extern int optind;
        extern char *optarg;
        int bEOptionWasGiven = 0;
@@ -2541,9 +2630,6 @@ int realMain(int argc, char **argv)
        int bChDirRoot = 1; /* change the current working directory to "/"? */
        char *arg;      /* for command line option processing */
        uchar legacyConfLine[80];
-       uchar *LocalHostName;
-       uchar *LocalDomain;
-       uchar *LocalFQDNName;
        char cwdbuf[128]; /* buffer to obtain/display current working directory */
 
        /* first, parse the command line options. We do not carry out any actual work, just
@@ -2651,7 +2737,7 @@ int realMain(int argc, char **argv)
 
        /* we need to create the inputName property (only once during our lifetime) */
        CHKiRet(prop.Construct(&pInternalInputName));
-       CHKiRet(prop.SetString(pInternalInputName, UCHAR_CONSTANT("rsyslogd"), sizeof("rsyslgod") - 1));
+       CHKiRet(prop.SetString(pInternalInputName, UCHAR_CONSTANT("rsyslogd"), sizeof("rsyslogd") - 1));
        CHKiRet(prop.ConstructFinalize(pInternalInputName));
 
        CHKiRet(prop.Construct(&pLocalHostIP));
@@ -2661,72 +2747,7 @@ int realMain(int argc, char **argv)
        /* get our host and domain names - we need to do this early as we may emit
         * error log messages, which need the correct hostname. -- rgerhards, 2008-04-04
         */
-       net.getLocalHostname(&LocalFQDNName);
-       CHKmalloc(LocalHostName = (uchar*) strdup((char*)LocalFQDNName));
-       glbl.SetLocalFQDNName(LocalFQDNName); /* set the FQDN before we modify it */
-       if((p = (uchar*)strchr((char*)LocalHostName, '.'))) {
-               *p++ = '\0';
-               LocalDomain = p;
-       } else {
-               LocalDomain = (uchar*)"";
-
-               /* It's not clearly defined whether gethostname()
-                * should return the simple hostname or the fqdn. A
-                * good piece of software should be aware of both and
-                * we want to distribute good software.  Joey
-                *
-                * Good software also always checks its return values...
-                * If syslogd starts up before DNS is up & /etc/hosts
-                * doesn't have LocalHostName listed, gethostbyname will
-                * return NULL.
-                */
-               /* TODO: gethostbyname() is not thread-safe, but replacing it is
-                * not urgent as we do not run on multiple threads here. rgerhards, 2007-09-25
-                */
-               hent = gethostbyname((char*)LocalHostName);
-               if(hent) {
-                       int i = 0;
-
-                       if(hent->h_aliases) {
-                               size_t hnlen;
-
-                               hnlen = strlen((char *) LocalHostName);
-
-                               for (i = 0; hent->h_aliases[i]; i++) {
-                                       if (!strncmp(hent->h_aliases[i], (char *) LocalHostName, hnlen)
-                                           && hent->h_aliases[i][hnlen] == '.') {
-                                               /* found a matching hostname */
-                                               break;
-                                       }
-                               }
-                       }
-
-                       free(LocalHostName);
-                       if(hent->h_aliases && hent->h_aliases[i]) {
-                               CHKmalloc(LocalHostName = (uchar*)strdup(hent->h_aliases[i]));
-                       } else {
-                               CHKmalloc(LocalHostName = (uchar*)strdup(hent->h_name));
-                       }
-
-                       if((p = (uchar*)strchr((char*)LocalHostName, '.')))
-                       {
-                               *p++ = '\0';
-                               LocalDomain = p;
-                       }
-               }
-       }
-
-       /* Convert to lower case to recognize the correct domain laterly */
-       for(p = LocalDomain ; *p ; p++)
-               *p = (char)tolower((int)*p);
-
-       /* we now have our hostname and can set it inside the global vars.
-        * TODO: think if all of this would better be a runtime function
-        * rgerhards, 2008-04-17
-        */
-       glbl.SetLocalHostName(LocalHostName);
-       glbl.SetLocalDomain(LocalDomain);
-       glbl.GenerateLocalHostNameProperty(); /* must be redone after conf processing, FQDN setting may have changed */
+       queryLocalHostname();
 
        /* initialize the objects */
        if((iRet = modInitIminternal()) != RS_RET_OK) {