diff options
author | Shuai Fan <shuai900217@126.com> | 2013-06-19 11:59:08 +0800 |
---|---|---|
committer | Tanu Kaskinen <tanu.kaskinen@linux.intel.com> | 2013-06-20 16:34:57 +0300 |
commit | b0bf132f8f643dcafda9d52c76543fafaf93f3a0 (patch) | |
tree | 818cf20ba9780cf3da8be7538dbc7906c9e2e044 | |
parent | e05c12f28b4bc8e4d7c5ba47f4bdb51243f9f252 (diff) |
cli, log: Improve the set-log-target functionality
Add a new log target 'newfile:PATH', and refactoring 'pa_log_target_type'.
Signed-off-by: Shuai Fan <shuai900217@126.com>
-rw-r--r-- | man/pulse-cli-syntax.5.xml.in | 2 | ||||
-rw-r--r-- | src/daemon/daemon-conf.c | 83 | ||||
-rw-r--r-- | src/daemon/daemon-conf.h | 3 | ||||
-rw-r--r-- | src/daemon/main.c | 16 | ||||
-rw-r--r-- | src/pulsecore/cli-command.c | 45 | ||||
-rw-r--r-- | src/pulsecore/log.c | 143 | ||||
-rw-r--r-- | src/pulsecore/log.h | 27 |
7 files changed, 211 insertions, 108 deletions
diff --git a/man/pulse-cli-syntax.5.xml.in b/man/pulse-cli-syntax.5.xml.in index 92c713461..b150b67e6 100644 --- a/man/pulse-cli-syntax.5.xml.in +++ b/man/pulse-cli-syntax.5.xml.in @@ -263,7 +263,7 @@ USA. <option> <p><opt>set-log-target</opt> <arg>target</arg></p> - <optdesc><p>Change the log target (null, auto, syslog, stderr, file:PATH).</p></optdesc> + <optdesc><p>Change the log target (null, auto, syslog, stderr, file:PATH, newfile:PATH).</p></optdesc> </option> <option> diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index f1e5476a9..4cc348571 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -73,12 +73,11 @@ static const pa_daemon_conf default_conf = { .flat_volumes = TRUE, .exit_idle_time = 20, .scache_idle_time = 20, - .auto_log_target = 1, .script_commands = NULL, .dl_search_path = NULL, .load_default_script_file = TRUE, .default_script_file = NULL, - .log_target = PA_LOG_SYSLOG, + .log_target = NULL, .log_level = PA_LOG_NOTICE, .log_backtrace = 0, .log_meta = FALSE, @@ -167,77 +166,31 @@ pa_daemon_conf *pa_daemon_conf_new(void) { void pa_daemon_conf_free(pa_daemon_conf *c) { pa_assert(c); - pa_log_set_fd(-1); - pa_xfree(c->script_commands); pa_xfree(c->dl_search_path); pa_xfree(c->default_script_file); + + if (c->log_target) + pa_log_target_free(c->log_target); + pa_xfree(c->config_file); pa_xfree(c); } -#define PA_LOG_MAX_SUFFIX_NUMBER 100 - int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) { + pa_log_target *log_target = NULL; + pa_assert(c); pa_assert(string); - if (pa_streq(string, "auto")) - c->auto_log_target = 1; - else if (pa_streq(string, "syslog")) { - c->auto_log_target = 0; - c->log_target = PA_LOG_SYSLOG; - } else if (pa_streq(string, "stderr")) { - c->auto_log_target = 0; - c->log_target = PA_LOG_STDERR; - } else if (pa_startswith(string, "file:")) { - char file_path[512]; - int log_fd; - - pa_strlcpy(file_path, string + 5, sizeof(file_path)); - - /* Open target file with user rights */ - if ((log_fd = open(file_path, O_RDWR|O_TRUNC|O_CREAT, S_IRUSR | S_IWUSR)) >= 0) { - c->auto_log_target = 0; - c->log_target = PA_LOG_FD; - pa_log_set_fd(log_fd); - } else { - printf("Failed to open target file %s, error : %s\n", file_path, pa_cstrerror(errno)); - return -1; - } - } else if (pa_startswith(string, "newfile:")) { - char file_path[512]; - int log_fd; - int version = 0; - int left_size; - char *p; - - pa_strlcpy(file_path, string + 8, sizeof(file_path)); - - left_size = sizeof(file_path) - strlen(file_path); - p = file_path + strlen(file_path); - - do { - memset(p, 0, left_size); - - if (version > 0) - pa_snprintf(p, left_size, ".%d", version); - } while (++version <= PA_LOG_MAX_SUFFIX_NUMBER && - (log_fd = open(file_path, O_RDWR|O_TRUNC|O_CREAT|O_EXCL, S_IRUSR | S_IWUSR)) < 0); - - if (version > PA_LOG_MAX_SUFFIX_NUMBER) { - memset(p, 0, left_size); - printf("Tried to open target files '%s', '%s.1', '%s.2' ... '%s.%d', but all failed.\n", - file_path, file_path, file_path, file_path, PA_LOG_MAX_SUFFIX_NUMBER - 1); + if (!pa_streq(string, "auto")) { + log_target = pa_log_parse_target(string); + + if (!log_target) return -1; - } else { - printf("Opened target file %s\n", file_path); - c->auto_log_target = 0; - c->log_target = PA_LOG_FD; - pa_log_set_fd(log_fd); - } - } else - return -1; + } + + c->log_target = log_target; return 0; } @@ -755,6 +708,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf *s; char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + char *log_target = NULL; pa_assert(c); @@ -765,6 +719,9 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_assert(c->log_level < PA_LOG_LEVEL_MAX); + if (c->log_target) + log_target = pa_log_target_to_string(c->log_target); + pa_strbuf_printf(s, "daemonize = %s\n", pa_yes_no(c->daemonize)); pa_strbuf_printf(s, "fail = %s\n", pa_yes_no(c->fail)); pa_strbuf_printf(s, "high-priority = %s\n", pa_yes_no(c->high_priority)); @@ -787,7 +744,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "dl-search-path = %s\n", pa_strempty(c->dl_search_path)); pa_strbuf_printf(s, "default-script-file = %s\n", pa_strempty(pa_daemon_conf_get_default_script_file(c))); pa_strbuf_printf(s, "load-default-script-file = %s\n", pa_yes_no(c->load_default_script_file)); - pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); + pa_strbuf_printf(s, "log-target = %s\n", pa_strempty(log_target)); pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); pa_strbuf_printf(s, "enable-remixing = %s\n", pa_yes_no(!c->disable_remixing)); @@ -846,5 +803,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { #endif #endif + pa_xfree(log_target); + return pa_strbuf_tostring_free(s); } diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index faf25405f..067ff21b5 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -80,12 +80,11 @@ typedef struct pa_daemon_conf { pa_server_type_t local_server_type; int exit_idle_time, scache_idle_time, - auto_log_target, realtime_priority, nice_level, resample_method; char *script_commands, *dl_search_path, *default_script_file; - pa_log_target_t log_target; + pa_log_target *log_target; pa_log_level_t log_level; unsigned log_backtrace; char *config_file; diff --git a/src/daemon/main.c b/src/daemon/main.c index c18524ffb..9bb852cbd 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -499,8 +499,14 @@ int main(int argc, char *argv[]) { goto finish; } + if (conf->log_target) + pa_log_set_target(conf->log_target); + else { + pa_log_target target = { .type = PA_LOG_STDERR, .file = NULL }; + pa_log_set_target(&target); + } + pa_log_set_level(conf->log_level); - pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target); if (conf->log_meta) pa_log_set_flags(PA_LOG_PRINT_META, PA_LOG_SET); if (conf->log_time) @@ -810,8 +816,10 @@ int main(int argc, char *argv[]) { daemon_pipe[0] = -1; #endif - if (conf->auto_log_target) - pa_log_set_target(PA_LOG_SYSLOG); + if (!conf->log_target) { + pa_log_target target = { .type = PA_LOG_SYSLOG, .file = NULL }; + pa_log_set_target(&target); + } #ifdef HAVE_SETSID if (setsid() < 0) { @@ -1042,7 +1050,7 @@ int main(int argc, char *argv[]) { c->cpu_info.cpu_type = PA_CPU_X86; if (pa_cpu_init_arm(&(c->cpu_info.flags.arm))) c->cpu_info.cpu_type = PA_CPU_ARM; - pa_cpu_init_orc(c->cpu_info); + pa_cpu_init_orc(c->cpu_info); } pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0); diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index f5489d6ea..e374694e0 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -188,7 +188,7 @@ static const struct command commands[] = { { "kill-client", pa_cli_command_kill_client, "Kill a client (args: index)", 2}, { "kill-sink-input", pa_cli_command_kill_sink_input, "Kill a sink input (args: index)", 2}, { "kill-source-output", pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2}, - { "set-log-target", pa_cli_command_log_target, "Change the log target (args: null,auto,syslog,stderr,file:PATH)", 2}, + { "set-log-target", pa_cli_command_log_target, "Change the log target (args: null|auto|syslog|stderr|file:PATH|newfile:PATH)", 2}, { "set-log-level", pa_cli_command_log_level, "Change the log level (args: numeric level)", 2}, { "set-log-meta", pa_cli_command_log_meta, "Show source code location in log messages (args: bool)", 2}, { "set-log-time", pa_cli_command_log_time, "Show timestamps in log messages (args: bool)", 2}, @@ -1501,6 +1501,7 @@ static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, p static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { const char *m; + pa_log_target *log_target = NULL; pa_core_assert_ref(c); pa_assert(t); @@ -1508,34 +1509,30 @@ static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf pa_assert(fail); if (!(m = pa_tokenizer_get(t, 1))) { - pa_strbuf_puts(buf, "You need to specify a log target (null,auto,syslog,stderr,file:PATH).\n"); - return -1; - } - - if (pa_streq(m, "null")) - pa_log_set_target(PA_LOG_NULL); - else if (pa_streq(m, "syslog")) - pa_log_set_target(PA_LOG_SYSLOG); - else if (pa_streq(m, "stderr") || pa_streq(m, "auto")) { - /* 'auto' is actually the effect with 'stderr' */ - pa_log_set_target(PA_LOG_STDERR); - } else if (pa_startswith(m, "file:")) { - const char *file_path = m + 5; - int log_fd; - - /* Open target file with user rights */ - if ((log_fd = open(file_path, O_RDWR|O_TRUNC|O_CREAT, S_IRUSR | S_IWUSR)) >= 0) { - pa_log_set_target(PA_LOG_FD); - pa_log_set_fd(log_fd); - } else { - pa_strbuf_printf(buf, "Failed to open target file %s, error : %s\n", file_path, pa_cstrerror(errno)); + pa_strbuf_puts(buf, "You need to specify a log target (null|auto|syslog|stderr|file:PATH|newfile:PATH).\n"); + return -1; + } + + /* 'auto' is actually the effect with 'stderr' */ + if (pa_streq(m, "auto")) + log_target = pa_log_target_new(PA_LOG_STDERR, NULL); + else { + log_target = pa_log_parse_target(m); + + if (!log_target) { + pa_strbuf_puts(buf, "Invalid log target.\n"); return -1; } - } else { - pa_strbuf_puts(buf, "You need to specify a log target (null,auto,syslog,stderr,file:PATH).\n"); + } + + if (pa_log_set_target(log_target) < 0) { + pa_strbuf_puts(buf, "Failed to set log target.\n"); + pa_log_target_free(log_target); return -1; } + pa_log_target_free(log_target); + return 0; } diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 8eaef54e8..1c0209790 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -29,6 +29,7 @@ #include <unistd.h> #include <string.h> #include <errno.h> +#include <fcntl.h> #ifdef HAVE_EXECINFO_H #include <execinfo.h> @@ -47,9 +48,11 @@ #include <pulsecore/macro.h> #include <pulsecore/core-util.h> +#include <pulsecore/core-error.h> #include <pulsecore/once.h> #include <pulsecore/ratelimit.h> #include <pulsecore/thread.h> +#include <pulsecore/i18n.h> #include "log.h" @@ -63,9 +66,11 @@ #define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE" #define ENV_LOG_BACKTRACE_SKIP "PULSE_LOG_BACKTRACE_SKIP" #define ENV_LOG_NO_RATELIMIT "PULSE_LOG_NO_RATE_LIMIT" +#define LOG_MAX_SUFFIX_NUMBER 99 static char *ident = NULL; /* in local charset format */ -static pa_log_target_t target = PA_LOG_STDERR, target_override; +static pa_log_target target = { PA_LOG_STDERR, NULL }; +static pa_log_target_type_t target_override; static pa_bool_t target_override_set = FALSE; static pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_LOG_ERROR; static unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0; @@ -113,10 +118,65 @@ void pa_log_set_level(pa_log_level_t l) { maximum_level = l; } -void pa_log_set_target(pa_log_target_t t) { - pa_assert(t < PA_LOG_TARGET_MAX); +int pa_log_set_target(pa_log_target *t) { + int fd = -1; + int old_fd; + + pa_assert(t); + + switch (t->type) { + case PA_LOG_STDERR: + case PA_LOG_SYSLOG: + case PA_LOG_NULL: + break; + case PA_LOG_FILE: + if ((fd = pa_open_cloexec(t->file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { + pa_log(_("Failed to open target file '%s'."), t->file); + return -1; + } + break; + case PA_LOG_NEWFILE: { + char *file_path; + char *p; + unsigned version; + + file_path = pa_sprintf_malloc("%s.xx", t->file); + p = file_path + strlen(t->file); + + for (version = 0; version <= LOG_MAX_SUFFIX_NUMBER; version++) { + memset(p, 0, 3); /* Overwrite the ".xx" part in file_path with zero bytes. */ + + if (version > 0) + pa_snprintf(p, 4, ".%u", version); /* Why 4? ".xx" + termitating zero byte. */ - target = t; + if ((fd = pa_open_cloexec(file_path, O_WRONLY | O_TRUNC | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) >= 0) + break; + } + + if (version > LOG_MAX_SUFFIX_NUMBER) { + pa_log(_("Tried to open target file '%s', '%s.1', '%s.2' ... '%s.%d', but all failed."), + file_path, file_path, file_path, file_path, LOG_MAX_SUFFIX_NUMBER); + pa_xfree(file_path); + return -1; + } else + pa_log_debug("Opened target file %s\n", file_path); + + pa_xfree(file_path); + break; + } + } + + target.type = t->type; + pa_xfree(target.file); + target.file = pa_xstrdup(t->file); + + old_fd = log_fd; + log_fd = fd; + + if (old_fd >= 0) + pa_close(old_fd); + + return 0; } void pa_log_set_flags(pa_log_flags_t _flags, pa_log_merge_t merge) { @@ -276,7 +336,7 @@ void pa_log_levelv_meta( char *t, *n; int saved_errno = errno; char *bt = NULL; - pa_log_target_t _target; + pa_log_target_type_t _target; pa_log_level_t _maximum_level; unsigned _show_backtrace; pa_log_flags_t _flags; @@ -290,7 +350,7 @@ void pa_log_levelv_meta( init_defaults(); - _target = target_override_set ? target_override : target; + _target = target_override_set ? target_override : target.type; _maximum_level = PA_MAX(maximum_level, maximum_level_override); _show_backtrace = PA_MAX(show_backtrace, show_backtrace_override); _flags = flags | flags_override; @@ -410,18 +470,20 @@ void pa_log_levelv_meta( } #endif - case PA_LOG_FD: { + case PA_LOG_FILE: + case PA_LOG_NEWFILE: { if (log_fd >= 0) { char metadata[256]; pa_snprintf(metadata, sizeof(metadata), "\n%c %s %s", level_to_char[level], timestamp, location); if ((write(log_fd, metadata, strlen(metadata)) < 0) || (write(log_fd, t, strlen(t)) < 0)) { + pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL }; saved_errno = errno; pa_log_set_fd(-1); fprintf(stderr, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console."); fprintf(stderr, "%s %s\n", metadata, t); - pa_log_set_target(PA_LOG_STDERR); + pa_log_set_target(&new_target); } } @@ -473,3 +535,68 @@ pa_bool_t pa_log_ratelimit(pa_log_level_t level) { return pa_ratelimit_test(&ratelimit, level); } + +pa_log_target *pa_log_target_new(pa_log_target_type_t type, const char *file) { + pa_log_target *t = NULL; + + t = pa_xnew(pa_log_target, 1); + + t->type = type; + t->file = pa_xstrdup(file); + + return t; +} + +void pa_log_target_free(pa_log_target *t) { + pa_assert(t); + + pa_xfree(t->file); + pa_xfree(t); +} + +pa_log_target *pa_log_parse_target(const char *string) { + pa_log_target *t = NULL; + + pa_assert(string); + + if (pa_streq(string, "stderr")) + t = pa_log_target_new(PA_LOG_STDERR, NULL); + else if (pa_streq(string, "syslog")) + t = pa_log_target_new(PA_LOG_SYSLOG, NULL); + else if (pa_streq(string, "null")) + t = pa_log_target_new(PA_LOG_NULL, NULL); + else if (pa_startswith(string, "file:")) + t = pa_log_target_new(PA_LOG_FILE, string + 5); + else if (pa_startswith(string, "newfile:")) + t = pa_log_target_new(PA_LOG_NEWFILE, string + 8); + else + pa_log(_("Invalid log target.")); + + return t; +} + +char *pa_log_target_to_string(const pa_log_target *t) { + char *string = NULL; + + pa_assert(t); + + switch (t->type) { + case PA_LOG_STDERR: + string = pa_xstrdup("stderr"); + break; + case PA_LOG_SYSLOG: + string = pa_xstrdup("syslog"); + break; + case PA_LOG_NULL: + string = pa_xstrdup("null"); + break; + case PA_LOG_FILE: + string = pa_sprintf_malloc("file:%s", t->file); + break; + case PA_LOG_NEWFILE: + string = pa_sprintf_malloc("newfile:%s", t->file); + break; + } + + return string; +} diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h index 8dd056ba3..dd5e371c6 100644 --- a/src/pulsecore/log.h +++ b/src/pulsecore/log.h @@ -32,13 +32,13 @@ /* A simple logging subsystem */ /* Where to log to */ -typedef enum pa_log_target { - PA_LOG_STDERR, /* default */ +typedef enum pa_log_target_type { + PA_LOG_STDERR, /* default */ PA_LOG_SYSLOG, - PA_LOG_NULL, /* to /dev/null */ - PA_LOG_FD, /* to a file descriptor, e.g. a char device */ - PA_LOG_TARGET_MAX -} pa_log_target_t; + PA_LOG_NULL, /* to /dev/null */ + PA_LOG_FILE, /* to a user specified file */ + PA_LOG_NEWFILE, /* with an automatic suffix to avoid overwriting anything */ +} pa_log_target_type_t; typedef enum pa_log_level { PA_LOG_ERROR = 0, /* Error messages */ @@ -63,11 +63,16 @@ typedef enum pa_log_merge { PA_LOG_RESET } pa_log_merge_t; +typedef struct { + pa_log_target_type_t type; + char *file; +} pa_log_target; + /* Set an identification for the current daemon. Used when logging to syslog. */ void pa_log_set_ident(const char *p); /* Set a log target. */ -void pa_log_set_target(pa_log_target_t t); +int pa_log_set_target(pa_log_target *t); /* Maximal log level */ void pa_log_set_level(pa_log_level_t l); @@ -109,6 +114,14 @@ void pa_log_levelv( const char *format, va_list ap); +pa_log_target *pa_log_target_new(pa_log_target_type_t type, const char *file); + +void pa_log_target_free(pa_log_target *t); + +pa_log_target *pa_log_parse_target(const char *string); + +char *pa_log_target_to_string(const pa_log_target *t); + #if __STDC_VERSION__ >= 199901L /* ISO varargs available */ |