X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2Flxc%2Flog.c;h=d5822c32bbbee5cb62201ccdbe652fa77da4a672;hb=HEAD;hp=e1af6067c925af51f91fbbcaaf17e38b8d8514be;hpb=7d20477698f49fc6b4b72664382665f849643442;p=mirror_lxc.git diff --git a/src/lxc/log.c b/src/lxc/log.c index e1af6067c..cdd11ff1c 100644 --- a/src/lxc/log.c +++ b/src/lxc/log.c @@ -1,72 +1,57 @@ -/* - * lxc: linux Container library - * - * (C) Copyright IBM Corp. 2007, 2008 - * - * Authors: - * Cedric Le Goater - * - * 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 -#include #include +#include #include #include -#include -#include -#include -#include #include -#include - -#include +#include #include - -#include #include +#include +#include +#include +#include +#include + +#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 + +#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;