diff --git a/lib/log/log.c b/lib/log/log.c index 2d1fe74ab..141d02d86 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,10 +18,12 @@ #include "memlock.h" #include "defaults.h" +#include #include #include static FILE *_log_file; +static char _log_file_path[PATH_MAX]; static struct device _log_dev; static struct dm_str_list _log_dev_alias; @@ -52,11 +54,48 @@ void init_log_fn(lvm2_log_fn_t log_fn) _lvm2_log_fn = NULL; } +/* + * Support envvar LVM_LOG_FILE_EPOCH and allow to attach + * extra keyword to openned log file. After this word pid + * and starttime (in kernel units, read from /proc/self/stat + * is automatically attached. + * If command/daemon forks multiple times, it could create multiple + * log files ensure, there are no overwrites. + */ void init_log_file(const char *log_file, int append) { - const char *open_mode = append ? "a" : "w"; + static const char statfile[] = "/proc/self/stat"; + const char *env; + int pid; + long long starttime; + FILE *st; - if (!(_log_file = fopen(log_file, open_mode))) { + _log_file_path[0] = '\0'; + if ((env = getenv("LVM_LOG_FILE_EPOCH"))) { + if (!(st = fopen(statfile, "r"))) + log_sys_error("fopen", statfile); + else if (fscanf(st, "%d %*s %*c %*d %*d %*d %*d " /* tty_nr */ + "%*d %*u %*u %*u %*u " /* mjflt */ + "%*u %*u %*u %*d %*d " /* cstim */ + "%*d %*d %*d %*d " /* itrealvalue */ + "%llu", &pid, &starttime) != 2) { + log_warn("WARNING: Cannot parse content of %s.", statfile); + } else { + if (fclose(st)) + log_sys_debug("fclose", statfile); + + if (dm_snprintf(_log_file_path, sizeof(_log_file_path), + "%s_%s_%d_%lld", log_file, env, pid, starttime) < 0) { + log_warn("WARNING: Debug log file path is too long for epoch."); + _log_file_path[0] = '\0'; + } else { + log_file = _log_file_path; + append = 1; /* force */ + } + } + } + + if (!(_log_file = fopen(log_file, append ? "a" : "w"))) { log_sys_error("fopen", log_file); return; } @@ -64,6 +103,31 @@ void init_log_file(const char *log_file, int append) _log_to_file = 1; } +/* + * Unlink the log file depeding on command's return value + * + * When envvar LVM_LOG_FILE_UNLINK_STATUS is set, compare + * resulting status with this string. + * + * It's possible to specify 2 variants - having it equal to + * a single number or having it different from a single number. + * + * i.e. LVM_LOG_FILE_UNLINK_STATUS="!1" # delete when ret != 1. + */ +void unlink_log_file(int ret) +{ + const char *env; + + if (_log_file_path[0] && + (env = getenv("LVM_LOG_FILE_UNLINK_STATUS")) && + ((env[0] == '!' && atoi(env + 1) != ret) || + (atoi(env) == ret))) { + if (unlink(_log_file_path)) + log_sys_error("unlink", _log_file_path); + _log_file_path[0] = '\0'; + } +} + void init_log_direct(const char *log_file, int append) { int open_flags = append ? 0 : O_TRUNC; diff --git a/lib/log/lvm-logging.h b/lib/log/lvm-logging.h index 145e2a1c9..983da5b38 100644 --- a/lib/log/lvm-logging.h +++ b/lib/log/lvm-logging.h @@ -40,6 +40,7 @@ void init_indent(int indent); void init_msg_prefix(const char *prefix); void init_log_file(const char *log_file, int append); +void unlink_log_file(int ret); void init_log_direct(const char *log_file, int append); void init_log_while_suspended(int log_while_suspended); void init_abort_on_internal_errors(int fatal); diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index f9acd6095..26c48f909 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -1561,6 +1561,8 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) int lvm_return_code(int ret) { + unlink_log_file(ret); + return (ret == ECMD_PROCESSED ? 0 : ret); }