cfg.mk | 2 +-
src/util/virlog.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 98 insertions(+), 18 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index cf3f36c..2e3af1a 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -1160,7 +1160,7 @@ _src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon|loggin
exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
(^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
-exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/virutil\.c$$
+exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/vir(log|util)\.c$$
exclude_file_name_regexp--sc_prohibit_internal_functions = \
^src/(util/(viralloc|virutil|virfile)\.[hc]|esx/esx_vi\.c)$$
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 627f4cb..34e7f2a 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -39,6 +39,7 @@
#if HAVE_SYS_UN_H
# include <sys/un.h>
#endif
+#include <netdb.h>
#include "virerror.h"
#include "virlog.h"
@@ -94,7 +95,7 @@ static int virLogNbFilters;
* after filtering, multiple output can be used simultaneously
*/
struct _virLogOutput {
- bool logVersion;
+ bool logInitMessage;
void *data;
virLogOutputFunc f;
virLogCloseFunc c;
@@ -402,7 +403,7 @@ virLogDefineOutput(virLogOutputFunc f,
goto cleanup;
}
ret = virLogNbOutputs++;
- virLogOutputs[ret].logVersion = true;
+ virLogOutputs[ret].logInitMessage = true;
virLogOutputs[ret].f = f;
virLogOutputs[ret].c = c;
virLogOutputs[ret].data = data;
@@ -452,6 +453,73 @@ virLogVersionString(const char **rawmsg,
return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, VIR_LOG_VERSION_STRING);
}
+/* Similar to virGetHostname() but avoids use of error
+ * reporting APIs or logging APIs, to prevent recursion
+ */
+static int
+virLogHostnameString(const char **rawmsg,
+ char **msg)
+{
+ int r;
+ char hostname[HOST_NAME_MAX+1];
+ struct addrinfo hints, *info;
+ char *result = NULL;
+
+ *rawmsg = *msg = NULL;
+ r = gethostname(hostname, sizeof(hostname));
+ if (r == -1)
+ return -1;
+ NUL_TERMINATE(hostname);
+
+ if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) {
+ /* in this case, gethostname returned localhost (meaning we can't
+ * do any further canonicalization), or it returned an FQDN (and
+ * we don't need to do any further canonicalization). Return the
+ * string as-is; it's up to callers to check whether "localhost"
+ * is allowed.
+ */
+ ignore_value(VIR_STRDUP_QUIET(result, hostname));
+ goto cleanup;
+ }
+
+ /* otherwise, it's a shortened, non-localhost, hostname. Attempt to
+ * canonicalize the hostname by running it through getaddrinfo
+ */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME|AI_CANONIDN;
+ hints.ai_family = AF_UNSPEC;
+ r = getaddrinfo(hostname, NULL, &hints, &info);
+ if (r != 0) {
+ ignore_value(VIR_STRDUP_QUIET(result, hostname));
+ goto cleanup;
+ }
+
+ /* Tell static analyzers about getaddrinfo semantics. */
+ sa_assert(info);
+
+ if (info->ai_canonname == NULL ||
+ STRPREFIX(info->ai_canonname, "localhost"))
+ /* in this case, we tried to canonicalize and we ended up back with
+ * localhost. Ignore the canonicalized name and just return the
+ * original hostname
+ */
+ ignore_value(VIR_STRDUP_QUIET(result, hostname));
+ else
+ /* Caller frees this string. */
+ ignore_value(VIR_STRDUP_QUIET(result, info->ai_canonname));
+
+ freeaddrinfo(info);
+
+ cleanup:
+ if (virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, result) < 0) {
+ VIR_FREE(result);
+ return -1;
+ }
+ *rawmsg = result;
+ return 0;
+}
+
static void
virLogSourceUpdate(virLogSourcePtr source)
@@ -533,7 +601,7 @@ virLogVMessage(virLogSourcePtr source,
const char *fmt,
va_list vargs)
{
- static bool logVersionStderr = true;
+ static bool logInitMessageStderr = true;
char *str = NULL;
char *msg = NULL;
char timestamp[VIR_TIME_STRING_BUFLEN];
@@ -583,16 +651,22 @@ virLogVMessage(virLogSourcePtr source,
*/
for (i = 0; i < virLogNbOutputs; i++) {
if (priority >= virLogOutputs[i].priority) {
- if (virLogOutputs[i].logVersion) {
- const char *rawver;
- char *ver = NULL;
- if (virLogVersionString(&rawver, &ver) >= 0)
+ if (virLogOutputs[i].logInitMessage) {
+ const char *rawinitmsg;
+ char *initmsg = NULL;
+ if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
+ virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
+ __FILE__, __LINE__, __func__,
+ timestamp, NULL, 0, rawinitmsg, initmsg,
+ virLogOutputs[i].data);
+ VIR_FREE(initmsg);
+ if (virLogHostnameString(&rawinitmsg, &initmsg) >= 0)
virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
__FILE__, __LINE__, __func__,
- timestamp, NULL, 0, rawver, ver,
+ timestamp, NULL, 0, rawinitmsg, initmsg,
virLogOutputs[i].data);
- VIR_FREE(ver);
- virLogOutputs[i].logVersion = false;
+ VIR_FREE(initmsg);
+ virLogOutputs[i].logInitMessage = false;
}
virLogOutputs[i].f(source, priority,
filename, linenr, funcname,
@@ -601,16 +675,22 @@ virLogVMessage(virLogSourcePtr source,
}
}
if (virLogNbOutputs == 0) {
- if (logVersionStderr) {
- const char *rawver;
- char *ver = NULL;
- if (virLogVersionString(&rawver, &ver) >= 0)
+ if (logInitMessageStderr) {
+ const char *rawinitmsg;
+ char *initmsg = NULL;
+ if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
+ virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
+ __FILE__, __LINE__, __func__,
+ timestamp, NULL, 0, rawinitmsg, initmsg,
+ (void *) STDERR_FILENO);
+ VIR_FREE(initmsg);
+ if (virLogHostnameString(&rawinitmsg, &initmsg) >= 0)
virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
__FILE__, __LINE__, __func__,
- timestamp, NULL, 0, rawver, ver,
+ timestamp, NULL, 0, rawinitmsg, initmsg,
(void *) STDERR_FILENO);
- VIR_FREE(ver);
- logVersionStderr = false;
+ VIR_FREE(initmsg);
+ logInitMessageStderr = false;
}
virLogOutputToFd(source, priority,
filename, linenr, funcname,