#include <stdio.h>
#include <errno.h>
-#include <stdarg.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#define __USE_GNU /* for *_CLOEXEC */
+
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <lxc/log.h>
+
+#define LXC_LOG_PREFIX_SIZE 32
+#define LXC_LOG_BUFFER_SIZE 512
+
+int lxc_log_fd = 2;
+
+static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
+
+lxc_log_define(lxc_log, lxc);
+
+/*---------------------------------------------------------------------------*/
+static int log_append_logfile(const struct lxc_log_appender *appender,
+ const struct lxc_log_event *event)
+{
+ char buffer[LXC_LOG_BUFFER_SIZE];
+ int n;
+
+ if (lxc_log_fd == -1)
+ return 0;
+
+ n = snprintf(buffer, sizeof(buffer),
+ "%15s %10ld.%03ld %-8s %s - ",
+ log_prefix,
+ event->timestamp.tv_sec,
+ event->timestamp.tv_usec / 1000,
+ lxc_log_priority_to_string(event->priority),
+ event->category);
+
+ n += vsnprintf(buffer + n, sizeof(buffer) - n, event->fmt,
+ event->va);
+
+ if (n >= sizeof(buffer) - 1) {
+ WARN("truncated next event from %d to %d bytes", n,
+ sizeof(buffer));
+ n = sizeof(buffer) - 1;
+ }
+
+ buffer[n] = '\n';
+
+ return write(lxc_log_fd, buffer, n + 1);
+}
+
+static struct lxc_log_appender log_appender_logfile = {
+ .name = "logfile",
+ .append = log_append_logfile,
+ .next = NULL,
+};
+
+static struct lxc_log_category log_root = {
+ .name = "root",
+ .priority = LXC_LOG_PRIORITY_ERROR,
+ .appender = NULL,
+ .parent = NULL,
+};
+
+struct lxc_log_category lxc_log_category_lxc = {
+ .name = "lxc",
+ .priority = LXC_LOG_PRIORITY_ERROR,
+ .appender = &log_appender_logfile,
+ .parent = &log_root
+};
+
+/*---------------------------------------------------------------------------*/
+extern void lxc_log_setprefix(const char *prefix)
+{
+ strncpy(log_prefix, prefix, sizeof(log_prefix));
+ log_prefix[sizeof(log_prefix) - 1] = 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static int log_open(const char *name)
+{
+ int fd;
+ int newfd;
+
+ fd = open(name, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0666);
+ if (fd == -1) {
+ ERROR("failed to open log file \"%s\" : %s", name,
+ strerror(errno));
+ return -1;
+ }
+
+ if (fd > 2)
+ return fd;
+
+ newfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (newfd == -1)
+ ERROR("failed to dup log fd %d : %s", fd, strerror(errno));
+
+ close(fd);
+ return newfd;
+}
+
+/*---------------------------------------------------------------------------*/
+extern int lxc_log_init(const char *file, int priority, const char *prefix)
+{
+ lxc_log_category_lxc.priority = priority;
+
+ if (prefix)
+ lxc_log_setprefix(prefix);
+
+ if (file) {
+ int fd;
+
+ fd = log_open(file);
+ if (fd == -1) {
+ ERROR("failed to initialize log service");
+ return -1;
+ }
+
+ lxc_log_fd = fd;
+ }
+
+ return 0;
+}
-#include <log.h>
#define MAXTIMELEN 47;
#define ERRNO_FORMAT "%d (%s)"
-
#ifndef _log_h
#define _log_h
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <string.h>
+
+/* predefined priorities. */
+enum {
+ LXC_LOG_PRIORITY_TRACE,
+ LXC_LOG_PRIORITY_DEBUG,
+ LXC_LOG_PRIORITY_INFO,
+ LXC_LOG_PRIORITY_NOTICE,
+ LXC_LOG_PRIORITY_WARN,
+ LXC_LOG_PRIORITY_ERROR,
+ LXC_LOG_PRIORITY_CRIT,
+ LXC_LOG_PRIORITY_ALERT,
+ LXC_LOG_PRIORITY_FATAL,
+ LXC_LOG_PRIORITY_NOTSET,
+};
+
+/* location information of the logging event */
+struct lxc_log_locinfo {
+ const char *file;
+ const char *func;
+ int line;
+};
+
+#define LXC_LOG_LOCINFO_INIT \
+ { .file = __FILE__, .func = __func__, .line = __LINE__ }
+
+/* brief logging event object */
+struct lxc_log_event {
+ const char* category;
+ int priority;
+ struct timeval timestamp;
+ struct lxc_log_locinfo *locinfo;
+ const char *fmt;
+ va_list va;
+};
+
+/* log appender object */
+struct lxc_log_appender {
+ const char* name;
+ int (*append)(const struct lxc_log_appender *,
+ const struct lxc_log_event *);
+
+ /*
+ * appenders can be stacked
+ */
+ struct lxc_log_appender *next;
+};
+
+/* log category object */
+struct lxc_log_category {
+ const char *name;
+ int priority;
+ struct lxc_log_appender *appender;
+ const struct lxc_log_category *parent;
+};
+
+/*
+ * Returns true if the chained priority is equal to or higher than
+ * given priority.
+ */
+static inline int
+lxc_log_priority_is_enabled(const struct lxc_log_category* category,
+ int priority)
+{
+ while (category->priority == LXC_LOG_PRIORITY_NOTSET &&
+ category->parent)
+ category = category->parent;
+
+ return priority >= category->priority;
+}
+
+/*
+ * converts a priority to a literal string
+ */
+static inline const char* lxc_log_priority_to_string(int priority)
+{
+ switch (priority) {
+ case LXC_LOG_PRIORITY_TRACE: return "TRACE";
+ case LXC_LOG_PRIORITY_DEBUG: return "DEBUG";
+ case LXC_LOG_PRIORITY_INFO: return "INFO";
+ case LXC_LOG_PRIORITY_NOTICE: return "NOTICE";
+ case LXC_LOG_PRIORITY_WARN: return "WARN";
+ case LXC_LOG_PRIORITY_ERROR: return "ERROR";
+ case LXC_LOG_PRIORITY_CRIT: return "CRIT";
+ case LXC_LOG_PRIORITY_ALERT: return "ALERT";
+ case LXC_LOG_PRIORITY_FATAL: return "FATAL";
+ default:
+ return "NOTSET";
+ }
+}
+/*
+ * converts a literal priority to an int
+ */
+static inline int lxc_log_priority_to_int(const char* name)
+{
+ if (!strcasecmp("TRACE", name)) return LXC_LOG_PRIORITY_TRACE;
+ if (!strcasecmp("DEBUG", name)) return LXC_LOG_PRIORITY_DEBUG;
+ if (!strcasecmp("INFO", name)) return LXC_LOG_PRIORITY_INFO;
+ if (!strcasecmp("NOTICE", name)) return LXC_LOG_PRIORITY_NOTICE;
+ if (!strcasecmp("WARN", name)) return LXC_LOG_PRIORITY_WARN;
+ if (!strcasecmp("ERROR", name)) return LXC_LOG_PRIORITY_ERROR;
+ if (!strcasecmp("CRIT", name)) return LXC_LOG_PRIORITY_CRIT;
+ if (!strcasecmp("ALERT", name)) return LXC_LOG_PRIORITY_ALERT;
+ if (!strcasecmp("FATAL", name)) return LXC_LOG_PRIORITY_FATAL;
+
+ return LXC_LOG_PRIORITY_NOTSET;
+}
+
+static inline void
+__lxc_log_append(const struct lxc_log_appender *appender,
+ const struct lxc_log_event* event)
+{
+ while (appender) {
+ appender->append(appender, event);
+ appender = appender->next;
+ }
+}
+
+static inline void
+__lxc_log(const struct lxc_log_category* category,
+ const struct lxc_log_event* event)
+{
+ while (category) {
+ __lxc_log_append(category->appender, event);
+ category = category->parent;
+ }
+}
+
+/*
+ * Helper macro to define log fonctions.
+ */
+#define lxc_log_priority_define(acategory, PRIORITY) \
+ \
+static inline void LXC_##PRIORITY(struct lxc_log_locinfo *, \
+ const char *, ...) __attribute__ ((format (printf, 2, 3))); \
+ \
+static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo, \
+ const char* format, ...) \
+{ \
+ if (lxc_log_priority_is_enabled(acategory, \
+ LXC_LOG_PRIORITY_##PRIORITY)) { \
+ struct lxc_log_event evt = { \
+ .category = (acategory)->name, \
+ .priority = LXC_LOG_PRIORITY_##PRIORITY, \
+ .fmt = format, \
+ .locinfo = locinfo \
+ }; \
+ \
+ gettimeofday(&evt.timestamp, NULL); \
+ \
+ va_start(evt.va, format); \
+ __lxc_log(acategory, &evt); \
+ va_end(evt.va); \
+ } \
+}
+
+/*
+ * Helper macro to define and use static categories.
+ */
+#define lxc_log_category_define(name, parent) \
+ extern struct lxc_log_category lxc_log_category_##parent; \
+ struct lxc_log_category lxc_log_category_##name = { \
+ #name, \
+ LXC_LOG_PRIORITY_NOTSET, \
+ NULL, \
+ &lxc_log_category_##parent \
+ };
+
+#define lxc_log_define(name, parent) \
+ lxc_log_category_define(name, parent) \
+ \
+ lxc_log_priority_define(&lxc_log_category_##name, TRACE) \
+ lxc_log_priority_define(&lxc_log_category_##name, DEBUG) \
+ lxc_log_priority_define(&lxc_log_category_##name, INFO) \
+ lxc_log_priority_define(&lxc_log_category_##name, NOTICE) \
+ lxc_log_priority_define(&lxc_log_category_##name, WARN) \
+ lxc_log_priority_define(&lxc_log_category_##name, ERROR) \
+ lxc_log_priority_define(&lxc_log_category_##name, CRIT) \
+ lxc_log_priority_define(&lxc_log_category_##name, ALERT) \
+ lxc_log_priority_define(&lxc_log_category_##name, FATAL)
+
+#define lxc_log_category_priority(name) \
+ (lxc_log_priority_to_string(lxc_log_category_##name.priority))
+
+/*
+ * top categories
+ */
+extern struct lxc_log_category lxc_log_category_lxc;
+
+#define TRACE(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_TRACE(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+#define DEBUG(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_DEBUG(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+#define INFO(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_INFO(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+#define NOTICE(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_NOTICE(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+#define WARN(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_WARN(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+#define ERROR(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_ERROR(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+#define CRIT(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_CRIT(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+#define ALERT(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_ALERT(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+#define FATAL(format, ...) do { \
+ struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
+ LXC_FATAL(&locinfo, format, ##__VA_ARGS__); \
+} while (0)
+
+
+
+#define SYSERROR(format, ...) do { \
+ ERROR("%s - " format "\n", strerror(errno), ##__VA_ARGS__); \
+} while (0)
+
+
#define lxc_log(format, level, ...) do { \
fprintf(stderr, "[%s] \t%s:%d - " format "\n", \
level, __FUNCTION__, __LINE__, ##__VA_ARGS__); \