#include "log.h"
#include "caps.h"
+#include "utils.h"
#define LXC_LOG_PREFIX_SIZE 32
#define LXC_LOG_BUFFER_SIZE 512
int lxc_log_fd = -1;
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
+static char *log_fname = NULL;
+/* command line values for logfile or logpriority should always override
+ * values from the configuration file or defaults
+ */
+static int lxc_logfile_specified = 0;
static int lxc_loglevel_specified = 0;
-// if logfile was specifed on command line, it won't be overridden by lxc.logfile
-static int lxc_log_specified = 0;
lxc_log_define(lxc_log, lxc);
};
/*---------------------------------------------------------------------------*/
-extern void lxc_log_setprefix(const char *prefix)
-{
- strncpy(log_prefix, prefix, sizeof(log_prefix));
- log_prefix[sizeof(log_prefix) - 1] = 0;
-}
-
static int build_dir(const char *name)
{
char *n = strdup(name); // because we'll be modifying it
return newfd;
}
-static char *build_log_path(const char *name)
+/*
+ * Build the path to the log file
+ * @name : the name of the container
+ * @lxcpath : the lxcpath to use as a basename or NULL to use LOGPATH
+ * Returns malloced path on sucess, or NULL on failure
+ */
+static char *build_log_path(const char *name, const char *lxcpath)
{
char *p;
int len, ret;
/*
- * '$logpath' + '/' + '$name' + '.log' + '\0'
- * or
+ * If USE_CONFIGPATH_LOGS is true the resulting path will be:
* '$logpath' + '/' + '$name' + '/' + '$name' + '.log' + '\0'
- * sizeof(LOGPATH) includes its \0
+ *
+ * If USE_CONFIGPATH_LOGS is false the resulting path will be:
+ * '$logpath' + '/' + '$name' + '.log' + '\0'
*/
- len = sizeof(LOGPATH) + strlen(name) + 6;
+ len = strlen(name) + 6; /* 6 == '/' + '.log' + '\0' */
+ if (!lxcpath)
+ lxcpath = LOGPATH;
#if USE_CONFIGPATH_LOGS
- len += strlen(name) + 1; /* add "/$container_name/" */
+ len += strlen(lxcpath) + 1 + strlen(name) + 1; /* add "/$container_name/" */
+#else
+ len += strlen(lxcpath) + 1;
#endif
p = malloc(len);
if (!p)
return p;
#if USE_CONFIGPATH_LOGS
- ret = snprintf(p, len, "%s/%s/%s.log", LOGPATH, name, name);
+ ret = snprintf(p, len, "%s/%s/%s.log", lxcpath, name, name);
#else
- ret = snprintf(p, len, "%s/%s.log", LOGPATH, name);
+ ret = snprintf(p, len, "%s/%s.log", lxcpath, name);
#endif
if (ret < 0 || ret >= len) {
free(p);
return p;
}
-int do_lxc_log_set_file(const char *fname, int from_default);
+/*
+ * This can be called:
+ * 1. when a program calls lxc_log_init with no logfile parameter (in which
+ * case the default is used). In this case lxc.logfile can override this.
+ * 2. when a program calls lxc_log_init with a logfile parameter. In this
+ * case we don't want lxc.logfile to override this.
+ * 3. When a lxc.logfile entry is found in config file.
+ */
+static int __lxc_log_set_file(const char *fname, int create_dirs)
+{
+ if (lxc_log_fd != -1) {
+ // we are overriding the default.
+ close(lxc_log_fd);
+ free(log_fname);
+ }
+
+#if USE_CONFIGPATH_LOGS
+ // we don't build_dir for the default if the default is
+ // i.e. /var/lib/lxc/$container/$container.log
+ if (create_dirs)
+#endif
+ if (build_dir(fname)) {
+ ERROR("failed to create dir for log file \"%s\" : %s", fname,
+ strerror(errno));
+ return -1;
+ }
+
+ lxc_log_fd = log_open(fname);
+ if (lxc_log_fd == -1)
+ return -1;
+
+ log_fname = strdup(fname);
+ return 0;
+}
+
+static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_dirs)
+{
+ char *logfile;
+ int ret;
+
+ 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;
+}
-/*---------------------------------------------------------------------------*/
extern int lxc_log_init(const char *name, const char *file,
- const char *priority, const char *prefix, int quiet)
+ const char *priority, const char *prefix, int quiet,
+ const char *lxcpath)
{
int lxc_priority = LXC_LOG_PRIORITY_ERROR;
int ret;
- char *tmpfile = NULL;
- int want_lxc_log_specified = 0;
- if (lxc_log_fd != -1)
+ if (lxc_log_fd != -1) {
+ WARN("lxc_log_init called with log already initialized");
return 0;
+ }
if (priority) {
lxc_loglevel_specified = 1;
lxc_log_category_lxc.appender->next = &log_appender_stderr;
if (prefix)
- lxc_log_setprefix(prefix);
-
- if (file && strcmp(file, "none") == 0) {
- return 0;
- }
+ lxc_log_set_prefix(prefix);
- if (!file) {
- tmpfile = build_log_path(name);
- if (!tmpfile) {
- ERROR("could not build log path");
- return -1;
- }
+ if (file) {
+ lxc_logfile_specified = 1;
+ if (strcmp(file, "none") == 0)
+ return 0;
+ ret = __lxc_log_set_file(file, 1);
} else {
- want_lxc_log_specified = 1;
- }
+ ret = -1;
+
+ /* try LOGPATH if lxcpath is the default */
+ if (strcmp(lxcpath, default_lxc_path()) == 0)
+ ret = _lxc_log_set_file(name, NULL, 0);
- ret = do_lxc_log_set_file(tmpfile ? tmpfile : file, !want_lxc_log_specified);
+ /* try in lxcpath */
+ if (ret < 0)
+ ret = _lxc_log_set_file(name, lxcpath, 1);
+
+ /* try LOGPATH in case its writable by the caller */
+ if (ret < 0)
+ ret = _lxc_log_set_file(name, NULL, 0);
+ }
- if (want_lxc_log_specified)
- lxc_log_specified = 1;
/*
- * If !want_lxc_log_specified, that is, if the user did not request
- * this logpath, then ignore failures and continue logging to console
+ * If !file, that is, if the user did not request this logpath, then
+ * ignore failures and continue logging to console
*/
- if (!want_lxc_log_specified && ret != 0) {
+ if (!file && ret != 0) {
INFO("Ignoring failure to open default logfile.");
ret = 0;
}
- if (tmpfile)
- free(tmpfile);
-
return ret;
}
return 0;
}
-char *log_fname; // default to NULL, set in lxc_log_set_file.
+extern int lxc_log_get_level(void)
+{
+ if (!lxc_loglevel_specified)
+ return LXC_LOG_PRIORITY_NOTSET;
+ return lxc_log_category_lxc.priority;
+}
+
/*
- * This can be called:
- * 1. when a program calls lxc_log_init with no logfile parameter (in which
- * case the default is used). In this case lxc.logfile can override this.
- * 2. when a program calls lxc_log_init with a logfile parameter. In this
- * case we don't want lxc.logfile to override this.
- * 3. When a lxc.logfile entry is found in config file.
+ * This is called when we read a lxc.logfile entry in a lxc.conf file. This
+ * happens after processing command line arguments, which override the .conf
+ * settings. So only set the file if previously unset.
*/
-int do_lxc_log_set_file(const char *fname, int from_default)
+extern int lxc_log_set_file(const char *fname)
{
- if (lxc_log_specified) {
- INFO("lxc.logfile overridden by command line");
+ if (lxc_logfile_specified)
return 0;
- }
- if (lxc_log_fd != -1) {
- // we are overriding the default.
- close(lxc_log_fd);
- free(log_fname);
- }
-
-#if USE_CONFIGPATH_LOGS
- // we don't build_dir for the default if the default is
- // i.e. /var/lib/lxc/$container/$container.log
- if (!from_default)
-#endif
- if (build_dir(fname)) {
- ERROR("failed to create dir for log file \"%s\" : %s", fname,
- strerror(errno));
- return -1;
- }
-
- lxc_log_fd = log_open(fname);
- if (lxc_log_fd == -1)
- return -1;
-
- log_fname = strdup(fname);
- return 0;
+ return __lxc_log_set_file(fname, 0);
}
-extern int lxc_log_set_file(const char *fname)
+extern const char *lxc_log_get_file(void)
{
- return do_lxc_log_set_file(fname, 0);
+ return log_fname;
}
-extern int lxc_log_get_level(void)
+extern void lxc_log_set_prefix(const char *prefix)
{
- if (!lxc_loglevel_specified)
- return LXC_LOG_PRIORITY_NOTSET;
- return lxc_log_category_lxc.priority;
+ strncpy(log_prefix, prefix, sizeof(log_prefix));
+ log_prefix[sizeof(log_prefix) - 1] = 0;
}
-extern const char *lxc_log_get_file(void)
+extern const char *lxc_log_get_prefix(void)
{
- return log_fname;
+ return log_prefix;
}