]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/log.c
github: Update for main branch
[mirror_lxc.git] / src / lxc / log.c
index e1af6067c925af51f91fbbcaaf17e38b8d8514be..cdd11ff1c084c0cad8bb7f15b702092d0cf38c86 100644 (file)
@@ -1,72 +1,57 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Cedric Le Goater <legoater@free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "config.h"
 
-#define _GNU_SOURCE
-#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
-#include <stdint.h>
-#include <stdio.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <limits.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
 #include <pthread.h>
-#include <time.h>
-
-#include <syslog.h>
+#include <stdint.h>
 #include <stdio.h>
-
-#include <fcntl.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "lxc.h"
 
-#include "log.h"
 #include "caps.h"
+#include "file_utils.h"
+#include "log.h"
+#include "memory_utils.h"
 #include "utils.h"
-#include "lxccontainer.h"
 
-#ifndef HAVE_STRLCPY
-#include "include/strlcpy.h"
+#if !HAVE_STRLCPY
+#include "strlcpy.h"
+#endif
+
+#if HAVE_DLOG
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "LXC"
 #endif
 
 /* We're logging in seconds and nanoseconds. Assuming that the underlying
  * datatype is currently at maximum a 64bit integer, we have a date string that
  * is of maximum length (2^64 - 1) * 2 = (21 + 21) = 42.
  */
-#define LXC_LOG_TIME_SIZE ((LXC_NUMSTRLEN64)*2)
+#define LXC_LOG_TIME_SIZE ((INTTYPE_TO_STRLEN(uint64_t)) * 2)
 
-int lxc_log_fd = -1;
-static int syslog_enable = 0;
-int lxc_quiet_specified;
-int lxc_log_use_global_fd;
+int lxc_log_fd = -EBADF;
+static bool wants_syslog = false;
+static int lxc_quiet_specified;
+bool lxc_log_use_global_fd = false;
 static int lxc_loglevel_specified;
 
 static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
 static char *log_fname = NULL;
 static char *log_vmname = NULL;
 
-lxc_log_define(lxc_log, lxc);
+lxc_log_define(log, lxc);
 
 static int lxc_log_priority_to_syslog(int priority)
 {
@@ -95,51 +80,87 @@ static int lxc_log_priority_to_syslog(int priority)
        return LOG_NOTICE;
 }
 
-/*---------------------------------------------------------------------------*/
-static int log_append_syslog(const struct lxc_log_appender *appender,
-                            struct lxc_log_event *event)
+static const char *lxc_log_get_container_name(void)
 {
-       char *msg;
-       int rc, len;
-       va_list args;
-       const char *log_container_name = log_vmname;
+#ifndef NO_LXC_CONF
+       if (current_config && !log_vmname)
+               return current_config->name;
+#endif
+
+       return log_vmname;
+}
+
+int lxc_log_get_fd(void)
+{
+       int fd_log = -EBADF;
 
 #ifndef NO_LXC_CONF
-       if (current_config && !log_container_name)
-               log_container_name = current_config->name;
+       if (current_config && !lxc_log_use_global_fd)
+               fd_log = current_config->logfd;
 #endif
+       if (fd_log < 0)
+               fd_log = lxc_log_fd;
 
-       if (!syslog_enable)
-               return 0;
+       return fd_log;
+}
+
+static char *lxc_log_get_va_msg(struct lxc_log_event *event)
+{
+       __do_free char *msg = NULL;
+       int rc, len;
+       va_list args;
+
+       if (!event)
+               return ret_set_errno(NULL, EINVAL);
 
        va_copy(args, *event->vap);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
        len = vsnprintf(NULL, 0, event->fmt, args) + 1;
+#pragma GCC diagnostic pop
        va_end(args);
 
        msg = malloc(len * sizeof(char));
-       if (msg == NULL)
-               return 0;
+       if (!msg)
+               return ret_set_errno(NULL, ENOMEM);
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
        rc = vsnprintf(msg, len, event->fmt, *event->vap);
-       if (rc == -1 || rc >= len) {
-               free(msg);
+#pragma GCC diagnostic pop
+       if (rc < 0 || rc >= len)
+               return ret_set_errno(NULL, EIO);
+
+       return move_ptr(msg);
+}
+
+static int log_append_syslog(const struct lxc_log_appender *appender,
+                            struct lxc_log_event *event)
+{
+       __do_free char *msg = NULL;
+       const char *log_container_name;
+
+       if (!wants_syslog)
+               return 0;
+
+       log_container_name = lxc_log_get_container_name();
+
+       msg = lxc_log_get_va_msg(event);
+       if (!msg)
                return 0;
-       }
 
        syslog(lxc_log_priority_to_syslog(event->priority),
-               "%s%s %s - %s:%s:%d - %s" ,
-               log_container_name ? log_container_name : "",
-               log_container_name ? ":" : "",
-               event->category,
-               event->locinfo->file, event->locinfo->func,
-               event->locinfo->line,
-               msg);
-       free(msg);
+              "%s%s %s - %s:%s:%d - %s" ,
+              log_container_name ? log_container_name : "",
+              log_container_name ? ":" : "",
+              event->category,
+              event->locinfo->file, event->locinfo->func,
+              event->locinfo->line,
+              msg);
 
        return 0;
 }
 
-/*---------------------------------------------------------------------------*/
 static int log_append_stderr(const struct lxc_log_appender *appender,
                             struct lxc_log_event *event)
 {
@@ -148,33 +169,31 @@ static int log_append_stderr(const struct lxc_log_appender *appender,
        if (event->priority < LXC_LOG_LEVEL_ERROR)
                return 0;
 
-       log_container_name = log_vmname;
-
-#ifndef NO_LXC_CONF
-       if (current_config && !log_container_name)
-               log_container_name = current_config->name;
-#endif
+       log_container_name = lxc_log_get_container_name();
 
        fprintf(stderr, "%s: %s%s", log_prefix,
-               log_container_name ? log_container_name : "",
-               log_container_name ? ": " : "");
+               log_container_name ? log_container_name : "",
+               log_container_name ? ": " : "");
        fprintf(stderr, "%s: %s: %d ", event->locinfo->file,
-               event->locinfo->func, event->locinfo->line);
+               event->locinfo->func, event->locinfo->line);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
        vfprintf(stderr, event->fmt, *event->vap);
+#pragma GCC diagnostic pop
        fprintf(stderr, "\n");
 
        return 0;
 }
 
-/*---------------------------------------------------------------------------*/
-int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time)
+static int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time)
 {
        int64_t epoch_to_days, z, era, doe, yoe, year, doy, mp, day, month,
            d_in_s, hours, h_in_s, minutes, seconds;
-       char nanosec[LXC_NUMSTRLEN64];
+       char nanosec[INTTYPE_TO_STRLEN(int64_t)];
        int ret;
 
-       /* See https://howardhinnant.github.io/date_algorithms.html for an
+       /*
+        * See https://howardhinnant.github.io/date_algorithms.html for an
         * explanation of the algorithm used here.
         */
 
@@ -184,17 +203,20 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time
        /* Shift the Epoch from 1970-01-01 to 0000-03-01. */
        z = epoch_to_days + 719468;
 
-       /* compute the era from the serial date by simply dividing by the number
+       /*
+        * Compute the era from the serial date by simply dividing by the number
         * of days in an era (146097).
         */
        era = (z >= 0 ? z : z - 146096) / 146097;
 
-       /* The day-of-era (doe) can then be found by subtracting the era number
+       /*
+        * The day-of-era (doe) can then be found by subtracting the era number
         * times the number of days per era, from the serial date.
         */
        doe = (z - era * 146097);
 
-       /* From the day-of-era (doe), the year-of-era (yoe, range [0, 399]) can
+       /*
+        * From the day-of-era (doe), the year-of-era (yoe, range [0, 399]) can
         * be computed.
         */
        yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
@@ -202,7 +224,8 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time
        /* Given year-of-era, and era, one can now compute the year. */
        year = yoe + era * 400;
 
-       /* Also the day-of-year, again with the year beginning on Mar. 1, can be
+       /*
+        * Also the day-of-year, again with the year beginning on Mar. 1, can be
         * computed from the day-of-era and year-of-era.
         */
        doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
@@ -210,25 +233,30 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time
        /* Given day-of-year, find the month number. */
        mp = (5 * doy + 2) / 153;
 
-       /* From day-of-year and month-of-year we can now easily compute
+       /*
+        * From day-of-year and month-of-year we can now easily compute
         * day-of-month.
         */
        day = doy - (153 * mp + 2) / 5 + 1;
 
-       /* Transform the month number from the [0, 11] / [Mar, Feb] system to
+       /*
+        * Transform the month number from the [0, 11] / [Mar, Feb] system to
         * the civil system: [1, 12] to find the correct month.
         */
        month = mp + (mp < 10 ? 3 : -9);
 
-       /* The algorithm assumes that a year begins on 1 March, so add 1 before
-        * that. */
+       /*
+        * The algorithm assumes that a year begins on 1 March, so add 1 before
+        * that.
+        */
        if (month < 3)
                year++;
 
        /* Transform days in the epoch to seconds. */
        d_in_s = epoch_to_days * 86400;
 
-       /* To find the current hour simply substract the Epoch_to_days from the
+       /*
+        * To find the current hour simply substract the Epoch_to_days from the
         * total Epoch and divide by the number of seconds in an hour.
         */
        hours = (time->tv_sec - d_in_s) / 3600;
@@ -236,36 +264,40 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time
        /* Transform hours to seconds. */
        h_in_s = hours * 3600;
 
-       /* Calculate minutes by substracting the seconds for all days in the
+       /*
+        * Calculate minutes by subtracting the seconds for all days in the
         * epoch and for all hours in the epoch and divide by the number of
         * minutes in an hour.
         */
        minutes = (time->tv_sec - d_in_s - h_in_s) / 60;
 
-       /* Calculate the seconds by substracting the seconds for all days in the
+       /*
+        * Calculate the seconds by subtracting the seconds for all days in the
         * epoch, hours in the epoch and minutes in the epoch.
         */
        seconds = (time->tv_sec - d_in_s - h_in_s - (minutes * 60));
 
        /* Make string from nanoseconds. */
-       ret = snprintf(nanosec, LXC_NUMSTRLEN64, "%"PRId64, (int64_t)time->tv_nsec);
-       if (ret < 0 || ret >= LXC_NUMSTRLEN64)
-               return -1;
+       ret = strnprintf(nanosec, sizeof(nanosec), "%"PRId64, (int64_t)time->tv_nsec);
+       if (ret < 0)
+               return ret_errno(EIO);
 
-       /* Create final timestamp for the log and shorten nanoseconds to 3
+       /*
+        * Create final timestamp for the log and shorten nanoseconds to 3
         * digit precision.
         */
-       ret = snprintf(buf, bufsize,
+       ret = strnprintf(buf, bufsize,
                       "%" PRId64 "%02" PRId64 "%02" PRId64 "%02" PRId64
                       "%02" PRId64 "%02" PRId64 ".%.3s",
                       year, month, day, hours, minutes, seconds, nanosec);
-       if (ret < 0 || (size_t)ret >= bufsize)
-               return -1;
+       if (ret < 0)
+               return ret_errno(EIO);
 
        return 0;
 }
 
-/* This function needs to make extra sure that it is thread-safe. We had some
+/*
+ * This function needs to make extra sure that it is thread-safe. We had some
  * problems with that before. This especially involves time-conversion
  * functions. I don't want to find any localtime() or gmtime() functions or
  * relatives in here. Not even localtime_r() or gmtime_r() or relatives. They
@@ -274,7 +306,7 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time
  * think you are, you __will__ cause trouble using them.
  * (As a short example how this can cause trouble: LXD uses forkstart to fork
  * off a new process that runs the container. At the same time the go runtime
- * LXD relies on does its own multi-threading thing which we can't controll. The
+ * LXD relies on does its own multi-threading thing which we can't control. The
  * fork()ing + threading then seems to mess with the locking states in these
  * time functions causing deadlocks.)
  * The current solution is to be good old unix people and use the Epoch as our
@@ -288,47 +320,52 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time
 static int log_append_logfile(const struct lxc_log_appender *appender,
                              struct lxc_log_event *event)
 {
+       int fd_to_use = -EBADF;
        char buffer[LXC_LOG_BUFFER_SIZE];
        char date_time[LXC_LOG_TIME_SIZE];
-       int n, ret;
-       int fd_to_use = -1;
-       const char *log_container_name = log_vmname;
+       int n;
+       ssize_t ret;
+       const char *log_container_name;
 
 #ifndef NO_LXC_CONF
-       if (current_config) {
-               if (!lxc_log_use_global_fd)
-                       fd_to_use = current_config->logfd;
-
-               if (!log_container_name)
-                       log_container_name = current_config->name;
-       }
+       if (current_config && !lxc_log_use_global_fd)
+               fd_to_use = current_config->logfd;
 #endif
 
-       if (fd_to_use == -1)
+       log_container_name = lxc_log_get_container_name();
+
+       if (fd_to_use < 0)
                fd_to_use = lxc_log_fd;
 
-       if (fd_to_use == -1)
+       if (fd_to_use < 0)
                return 0;
 
-       if (lxc_unix_epoch_to_utc(date_time, LXC_LOG_TIME_SIZE, &event->timestamp) < 0)
-               return 0;
+       ret = lxc_unix_epoch_to_utc(date_time, LXC_LOG_TIME_SIZE, &event->timestamp);
+       if (ret)
+               return ret;
 
+       /*
+        * We allow truncation here which is why we use snprintf() directly
+        * instead of strnprintf().
+        */
        n = snprintf(buffer, sizeof(buffer),
-                       "%s%s%s %s %-8s %s - %s:%s:%d - ",
-                       log_prefix,
-                       log_container_name ? " " : "",
-                       log_container_name ? log_container_name : "",
-                       date_time,
-                       lxc_log_priority_to_string(event->priority),
-                       event->category,
-                       event->locinfo->file, event->locinfo->func,
-                       event->locinfo->line);
-
+                    "%s%s%s %s %-8s %s - %s:%s:%d - ",
+                    log_prefix,
+                    log_container_name ? " " : "",
+                    log_container_name ? log_container_name : "",
+                    date_time,
+                    lxc_log_priority_to_string(event->priority),
+                    event->category,
+                    event->locinfo->file, event->locinfo->func,
+                    event->locinfo->line);
        if (n < 0)
-               return n;
+               return ret_errno(EIO);
 
-       if ((size_t)n < (sizeof(buffer) - 1)) {
+       if ((size_t)n < STRARRAYLEN(buffer)) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
                ret = vsnprintf(buffer + n, sizeof(buffer) - n, event->fmt, *event->vap);
+#pragma GCC diagnostic pop
                if (ret < 0)
                        return 0;
 
@@ -336,13 +373,66 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
        }
 
        if ((size_t)n >= sizeof(buffer))
-               n = sizeof(buffer) - 1;
+               n = STRARRAYLEN(buffer);
 
        buffer[n] = '\n';
 
-       return write(fd_to_use, buffer, n + 1);
+       return lxc_write_nointr(fd_to_use, buffer, n + 1);
 }
 
+#if HAVE_DLOG
+static int log_append_dlog(const struct lxc_log_appender *appender,
+                            struct lxc_log_event *event)
+{
+       __do_free char *msg = NULL;
+       const char *log_container_name;
+
+       log_container_name = lxc_log_get_container_name();
+       msg = lxc_log_get_va_msg(event);
+
+       switch (event->priority) {
+       case LXC_LOG_LEVEL_TRACE:
+       case LXC_LOG_LEVEL_DEBUG:
+               print_log(DLOG_DEBUG, LOG_TAG, "%s: %s(%d) > [%s] %s",
+                         event->locinfo->file, event->locinfo->func, event->locinfo->line,
+                         log_container_name ? log_container_name : "-",
+                         msg ? msg : "-");
+               break;
+       case LXC_LOG_LEVEL_INFO:
+               print_log(DLOG_INFO, LOG_TAG, "%s: %s(%d) > [%s] %s",
+                         event->locinfo->file, event->locinfo->func, event->locinfo->line,
+                         log_container_name ? log_container_name : "-",
+                         msg ? msg : "-");
+               break;
+       case LXC_LOG_LEVEL_NOTICE:
+       case LXC_LOG_LEVEL_WARN:
+               print_log(DLOG_WARN, LOG_TAG, "%s: %s(%d) > [%s] %s",
+                         event->locinfo->file, event->locinfo->func, event->locinfo->line,
+                         log_container_name ? log_container_name : "-",
+                         msg ? msg : "-");
+               break;
+       case LXC_LOG_LEVEL_ERROR:
+               print_log(DLOG_ERROR, LOG_TAG, "%s: %s(%d) > [%s] %s",
+                         event->locinfo->file, event->locinfo->func, event->locinfo->line,
+                         log_container_name ? log_container_name : "-",
+                         msg ? msg : "-");
+               break;
+       case LXC_LOG_LEVEL_CRIT:
+       case LXC_LOG_LEVEL_ALERT:
+       case LXC_LOG_LEVEL_FATAL:
+               print_log(DLOG_FATAL, LOG_TAG, "%s: %s(%d) > [%s] %s",
+                         event->locinfo->file, event->locinfo->func, event->locinfo->line,
+                         log_container_name ? log_container_name : "-",
+                         msg ? msg : "-");
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+#endif
+
 static struct lxc_log_appender log_appender_syslog = {
        .name           = "syslog",
        .append         = log_append_syslog,
@@ -361,6 +451,14 @@ static struct lxc_log_appender log_appender_logfile = {
        .next           = NULL,
 };
 
+#if HAVE_DLOG
+static struct lxc_log_appender log_appender_dlog = {
+       .name           = "dlog",
+       .append         = log_append_dlog,
+       .next           = NULL,
+};
+#endif
+
 static struct lxc_log_category log_root = {
        .name           = "root",
        .priority       = LXC_LOG_LEVEL_ERROR,
@@ -368,68 +466,79 @@ static struct lxc_log_category log_root = {
        .parent         = NULL,
 };
 
+#if HAVE_DLOG
+struct lxc_log_category lxc_log_category_lxc = {
+       .name           = "lxc",
+       .priority       = LXC_LOG_LEVEL_TRACE,
+       .appender       = &log_appender_dlog,
+       .parent         = &log_root
+};
+#else
 struct lxc_log_category lxc_log_category_lxc = {
        .name           = "lxc",
        .priority       = LXC_LOG_LEVEL_ERROR,
        .appender       = &log_appender_logfile,
        .parent         = &log_root
 };
+#endif
 
-/*---------------------------------------------------------------------------*/
 static int build_dir(const char *name)
 {
-       int ret;
-       char *e, *n, *p;
+       __do_free char *n = NULL;
+       char *e, *p;
 
-       /* Make copy of string since we'll be modifying it. */
+       if (is_empty_string(name))
+               return ret_errno(EINVAL);
+
+       /* Make copy of the string since we'll be modifying it. */
        n = strdup(name);
-       if (!n) {
-               ERROR("Out of memory while creating directory '%s'", name);
-               return -1;
-       }
+       if (!n)
+               return ret_errno(ENOMEM);
 
        e = &n[strlen(n)];
-       for (p = n+1; p < e; p++) {
+       for (p = n + 1; p < e; p++) {
+               int ret;
+
                if (*p != '/')
                        continue;
                *p = '\0';
 
-               if (access(n, F_OK)) {
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+               ret = lxc_unpriv(mkdir(n, 0755));
+#else
+               if (RUN_ON_OSS_FUZZ || is_in_comm("fuzz-lxc-") > 0)
+                       ret = errno = EEXIST;
+               else
                        ret = lxc_unpriv(mkdir(n, 0755));
-                       if (ret && errno != EEXIST) {
-                               SYSERROR("Failed to create directory '%s'", n);
-                               free(n);
-                               return -1;
-                       }
-               }
+#endif /*!FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
                *p = '/';
+               if (ret && errno != EEXIST)
+                       return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", n);
        }
 
-       free(n);
        return 0;
 }
 
-/*---------------------------------------------------------------------------*/
 static int log_open(const char *name)
 {
-       int fd;
-       int newfd;
-
-       fd = lxc_unpriv(open(name, O_CREAT | O_WRONLY |
-                            O_APPEND | O_CLOEXEC, 0666));
-       if (fd == -1) {
-               SYSERROR("Failed to open log file \"%s\"", name);
-               return -1;
-       }
+       int newfd = -EBADF;
+       __do_close int fd = -EBADF;
 
-       if (fd > 2)
-               return fd;
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+       fd = lxc_unpriv(open(name, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0660));
+#else
+       if (!RUN_ON_OSS_FUZZ && is_in_comm("fuzz-lxc-") <= 0)
+               fd = lxc_unpriv(open(name, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0660));
+#endif /* !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
+       if (fd < 0)
+               return log_error_errno(-errno, errno, "Failed to open log file \"%s\"", name);
 
-       newfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-       if (newfd == -1)
-               SYSERROR("Failed to dup log fd %d", fd);
+       if (fd > 2)
+               return move_fd(fd);
 
-       close(fd);
+       newfd = fcntl(fd, F_DUPFD_CLOEXEC, STDERR_FILENO);
+       if (newfd < 0)
+               return log_error_errno(-errno, errno, "Failed to dup log fd %d", fd);
        return newfd;
 }
 
@@ -441,16 +550,18 @@ static int log_open(const char *name)
  */
 static char *build_log_path(const char *name, const char *lxcpath)
 {
-       char *p;
-       int len, ret, use_dir;
+       __do_free char *p = NULL;
+       int ret;
+       size_t len;
+       bool use_dir;
 
        if (!name)
-               return NULL;
+               return ret_set_errno(NULL, EINVAL);
 
 #if USE_CONFIGPATH_LOGS
-       use_dir = 1;
+       use_dir = true;
 #else
-       use_dir = 0;
+       use_dir = false;
 #endif
 
        /*
@@ -463,7 +574,7 @@ static char *build_log_path(const char *name, const char *lxcpath)
         */
        len = strlen(name) + 6; /* 6 == '/' + '.log' + '\0' */
        if (lxcpath)
-               use_dir = 1;
+               use_dir = true;
        else
                lxcpath = LOGPATH;
 
@@ -474,35 +585,16 @@ static char *build_log_path(const char *name, const char *lxcpath)
 
        p = malloc(len);
        if (!p)
-               return p;
+               return ret_set_errno(NULL, ENOMEM);
 
        if (use_dir)
-               ret = snprintf(p, len, "%s/%s/%s.log", lxcpath, name, name);
+               ret = strnprintf(p, len, "%s/%s/%s.log", lxcpath, name, name);
        else
-               ret = snprintf(p, len, "%s/%s.log", lxcpath, name);
-       if (ret < 0 || ret >= len) {
-               free(p);
-               return NULL;
-       }
-
-       return p;
-}
+               ret = strnprintf(p, len, "%s/%s.log", lxcpath, name);
+       if (ret < 0)
+               return ret_set_errno(NULL, EIO);
 
-extern void lxc_log_close(void)
-{
-       closelog();
-
-       free(log_vmname);
-       log_vmname = NULL;
-
-       if (lxc_log_fd == -1)
-               return;
-
-       close(lxc_log_fd);
-       lxc_log_fd = -1;
-
-       free(log_fname);
-       log_fname = NULL;
+       return move_ptr(p);
 }
 
 /*
@@ -516,15 +608,15 @@ extern void lxc_log_close(void)
 static int __lxc_log_set_file(const char *fname, int create_dirs)
 {
        /* we are overriding the default. */
-       if (lxc_log_fd != -1)
+       if (lxc_log_fd >= 0)
                lxc_log_close();
 
-       if (!fname)
-               return -1;
+       if (is_empty_string(fname))
+               return ret_errno(EINVAL);
 
        if (strlen(fname) == 0) {
                log_fname = NULL;
-               return 0;
+               return ret_errno(EINVAL);
        }
 
 #if USE_CONFIGPATH_LOGS
@@ -533,14 +625,12 @@ static int __lxc_log_set_file(const char *fname, int create_dirs)
         */
        if (create_dirs)
 #endif
-       if (build_dir(fname)) {
-               SYSERROR("Failed to create dir for log file \"%s\"", fname);
-               return -1;
-       }
+       if (build_dir(fname))
+               return log_error_errno(-errno, errno, "Failed to create dir for log file \"%s\"", fname);
 
        lxc_log_fd = log_open(fname);
-       if (lxc_log_fd == -1)
-               return -1;
+       if (lxc_log_fd < 0)
+               return lxc_log_fd;
 
        log_fname = strdup(fname);
        return 0;
@@ -548,66 +638,30 @@ static int __lxc_log_set_file(const char *fname, int create_dirs)
 
 static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_dirs)
 {
-       char *logfile;
-       int ret;
+       __do_free char *logfile = NULL;
 
        logfile = build_log_path(name, lxcpath);
-       if (!logfile) {
-               ERROR("Could not build log path");
-               return -1;
-       }
-       ret = __lxc_log_set_file(logfile, create_dirs);
-       free(logfile);
-       return ret;
-}
+       if (!logfile)
+               return log_error_errno(-errno, errno, "Could not build log path");
 
-extern int lxc_log_syslog(int facility)
-{
-       struct lxc_log_appender *appender;
-
-       openlog(log_prefix, LOG_PID, facility);
-       if (!lxc_log_category_lxc.appender) {
-               lxc_log_category_lxc.appender = &log_appender_syslog;
-               return 0;
-       }
-
-       appender = lxc_log_category_lxc.appender;
-       /* Check if syslog was already added, to avoid creating a loop */
-       while (appender) {
-               if (appender == &log_appender_syslog) {
-                       /* not an error: openlog re-opened the connection */
-                       return 0;
-               }
-               appender = appender->next;
-       }
-
-       appender = lxc_log_category_lxc.appender;
-       while (appender->next != NULL)
-               appender = appender->next;
-       appender->next = &log_appender_syslog;
-
-       return 0;
-}
-
-extern void lxc_log_enable_syslog(void)
-{
-       syslog_enable = 1;
+       return __lxc_log_set_file(logfile, create_dirs);
 }
 
 /*
  * lxc_log_init:
  * Called from lxc front-end programs (like lxc-create, lxc-start) to
- * initalize the log defaults.
+ * initialize the log defaults.
  */
-extern int lxc_log_init(struct lxc_log *log)
+int lxc_log_init(struct lxc_log *log)
 {
-       int lxc_priority = LXC_LOG_LEVEL_ERROR;
        int ret;
+       int lxc_priority = LXC_LOG_LEVEL_ERROR;
 
-       if (lxc_log_fd != -1) {
-               WARN("lxc_log_init called with log already initialized");
-               return 0;
-       }
+       if (!log)
+               return ret_errno(EINVAL);
+
+       if (lxc_log_fd >= 0)
+               return log_warn_errno(0, EOPNOTSUPP, "Log already initialized");
 
        if (log->level)
                lxc_priority = lxc_log_priority_to_int(log->level);
@@ -617,10 +671,9 @@ extern int lxc_log_init(struct lxc_log *log)
                lxc_loglevel_specified = 1;
        }
 
-       if (!lxc_quiet_specified) {
+       if (!lxc_quiet_specified)
                if (!log->quiet)
                        lxc_log_category_lxc.appender->next = &log_appender_stderr;
-       }
 
        if (log->prefix)
                lxc_log_set_prefix(log->prefix);
@@ -629,10 +682,14 @@ extern int lxc_log_init(struct lxc_log *log)
                log_vmname = strdup(log->name);
 
        if (log->file) {
-               if (strcmp(log->file, "none") == 0)
+               if (strequal(log->file, "none"))
                        return 0;
+
                ret = __lxc_log_set_file(log->file, 1);
-               lxc_log_use_global_fd = 1;
+               if (ret < 0)
+                       return log_error_errno(-1, errno, "Failed to enable logfile");
+
+               lxc_log_use_global_fd = true;
        } else {
                /* if no name was specified, there nothing to do */
                if (!log->name)
@@ -644,7 +701,7 @@ extern int lxc_log_init(struct lxc_log *log)
                        log->lxcpath = LOGPATH;
 
                /* try LOGPATH if lxcpath is the default for the privileged containers */
-               if (!geteuid() && strcmp(LXCPATH, log->lxcpath) == 0)
+               if (!geteuid() && strequal(LXCPATH, log->lxcpath))
                        ret = _lxc_log_set_file(log->name, NULL, 0);
 
                /* try in lxcpath */
@@ -665,36 +722,97 @@ extern int lxc_log_init(struct lxc_log *log)
                ret = 0;
        }
 
+       if (lxc_log_fd >= 0) {
+               lxc_log_category_lxc.appender = &log_appender_logfile;
+               lxc_log_category_lxc.appender->next = &log_appender_stderr;
+       }
+
        return ret;
 }
 
+void lxc_log_close(void)
+{
+       closelog();
+
+       free_disarm(log_vmname);
+
+       close_prot_errno_disarm(lxc_log_fd);
+
+       free_disarm(log_fname);
+}
+
+int lxc_log_syslog(int facility)
+{
+       struct lxc_log_appender *appender;
+
+       openlog(log_prefix, LOG_PID, facility);
+       if (!lxc_log_category_lxc.appender) {
+               lxc_log_category_lxc.appender = &log_appender_syslog;
+               return 0;
+       }
+
+       appender = lxc_log_category_lxc.appender;
+       /* Check if syslog was already added, to avoid creating a loop */
+       while (appender) {
+               /* not an error: openlog re-opened the connection */
+               if (appender == &log_appender_syslog)
+                       return 0;
+               appender = appender->next;
+       }
+
+       appender = lxc_log_category_lxc.appender;
+       while (appender->next != NULL)
+               appender = appender->next;
+       appender->next = &log_appender_syslog;
+
+       return 0;
+}
+
+void lxc_log_syslog_enable(void)
+{
+       wants_syslog = true;
+}
+
+void lxc_log_syslog_disable(void)
+{
+       wants_syslog = false;
+}
+
 /*
  * This is called when we read a lxc.log.level entry in a lxc.conf file.  This
  * happens after processing command line arguments, which override the .conf
  * settings.  So only set the level if previously unset.
  */
-extern int lxc_log_set_level(int *dest, int level)
+int lxc_log_set_level(int *dest, int level)
 {
-       if (level < 0 || level >= LXC_LOG_LEVEL_NOTSET) {
-               ERROR("Invalid log priority %d", level);
-               return -1;
-       }
+       if (level < 0 || level >= LXC_LOG_LEVEL_NOTSET)
+               return log_error_errno(-EINVAL, EINVAL, "Invalid log priority %d", level);
 
        *dest = level;
        return 0;
 }
 
-extern int lxc_log_get_level(void)
+int lxc_log_get_level(void)
 {
-       return lxc_log_category_lxc.priority;
+       int level = LXC_LOG_LEVEL_NOTSET;
+
+#ifndef NO_LXC_CONF
+       if (current_config)
+               level = current_config->loglevel;
+#endif
+       if (level == LXC_LOG_LEVEL_NOTSET)
+               level = lxc_log_category_lxc.priority;
+
+       return level;
 }
 
-extern bool lxc_log_has_valid_level(void)
+bool lxc_log_has_valid_level(void)
 {
-       int log_level = lxc_log_get_level();
+       int log_level;
 
+       log_level = lxc_log_get_level();
        if (log_level < 0 || log_level >= LXC_LOG_LEVEL_NOTSET)
-               return false;
+               return ret_set_errno(false, EINVAL);
 
        return true;
 }
@@ -704,42 +822,40 @@ extern bool lxc_log_has_valid_level(void)
  * happens after processing command line arguments, which override the .conf
  * settings.  So only set the file if previously unset.
  */
-extern int lxc_log_set_file(int *fd, const char *fname)
+int lxc_log_set_file(int *fd, const char *fname)
 {
-       if (*fd != -1) {
-               close(*fd);
-               *fd = -1;
-       }
+       if (*fd >= 0)
+               close_prot_errno_disarm(*fd);
 
-       if (build_dir(fname)) {
-               SYSERROR("Failed to create dir for log file \"%s\"", fname);
-               return -1;
-       }
+       if (is_empty_string(fname))
+               return ret_errno(EINVAL);
 
-       *fd = log_open(fname);
-       if (*fd == -1)
+       if (build_dir(fname))
                return -errno;
 
+       *fd = log_open(fname);
+       if (*fd < 0)
+               return -errno;
        return 0;
 }
 
-extern const char *lxc_log_get_file(void)
+inline const char *lxc_log_get_file(void)
 {
        return log_fname;
 }
 
-extern void lxc_log_set_prefix(const char *prefix)
+inline void lxc_log_set_prefix(const char *prefix)
 {
-       /* We don't care if thte prefix is truncated. */
+       /* We don't care if the prefix is truncated. */
        (void)strlcpy(log_prefix, prefix, sizeof(log_prefix));
 }
 
-extern const char *lxc_log_get_prefix(void)
+inline const char *lxc_log_get_prefix(void)
 {
        return log_prefix;
 }
 
-extern void lxc_log_options_no_override()
+inline void lxc_log_options_no_override(void)
 {
        lxc_quiet_specified = 1;
        lxc_loglevel_specified = 1;