153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 953a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 1053a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1853a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <stdarg.h> 2653a5a1b3Sopenharmony_ci#include <stdio.h> 2753a5a1b3Sopenharmony_ci#include <unistd.h> 2853a5a1b3Sopenharmony_ci#include <string.h> 2953a5a1b3Sopenharmony_ci#include <errno.h> 3053a5a1b3Sopenharmony_ci#include <fcntl.h> 3153a5a1b3Sopenharmony_ci#include <sys/stat.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#ifdef HAVE_EXECINFO_H 3453a5a1b3Sopenharmony_ci#include <execinfo.h> 3553a5a1b3Sopenharmony_ci#endif 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H 3853a5a1b3Sopenharmony_ci#include <syslog.h> 3953a5a1b3Sopenharmony_ci#endif 4053a5a1b3Sopenharmony_ci 4153a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL 4253a5a1b3Sopenharmony_ci 4353a5a1b3Sopenharmony_ci/* sd_journal_send() implicitly add fields for the source file, 4453a5a1b3Sopenharmony_ci * function name and code line from where it's invoked. As the 4553a5a1b3Sopenharmony_ci * correct code location fields CODE_FILE, CODE_LINE and 4653a5a1b3Sopenharmony_ci * CODE_FUNC are already handled by this module, we do not want 4753a5a1b3Sopenharmony_ci * the automatic values supplied by the systemd journal API. 4853a5a1b3Sopenharmony_ci * 4953a5a1b3Sopenharmony_ci * Without suppressing these, both the actual log event source 5053a5a1b3Sopenharmony_ci * and the call to sd_journal_send() will be logged. */ 5153a5a1b3Sopenharmony_ci#define SD_JOURNAL_SUPPRESS_LOCATION 5253a5a1b3Sopenharmony_ci 5353a5a1b3Sopenharmony_ci#include <systemd/sd-journal.h> 5453a5a1b3Sopenharmony_ci#endif 5553a5a1b3Sopenharmony_ci 5653a5a1b3Sopenharmony_ci#include <pulse/gccmacro.h> 5753a5a1b3Sopenharmony_ci#include <pulse/rtclock.h> 5853a5a1b3Sopenharmony_ci#include <pulse/utf8.h> 5953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 6053a5a1b3Sopenharmony_ci#include <pulse/util.h> 6153a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 6453a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 6553a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 6653a5a1b3Sopenharmony_ci#include <pulsecore/once.h> 6753a5a1b3Sopenharmony_ci#include <pulsecore/ratelimit.h> 6853a5a1b3Sopenharmony_ci#include <pulsecore/thread.h> 6953a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h> 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci#include "log.h" 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_ci#define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG" 7453a5a1b3Sopenharmony_ci#define ENV_LOG_JOURNAL "PULSE_LOG_JOURNAL" 7553a5a1b3Sopenharmony_ci#define ENV_LOG_LEVEL "PULSE_LOG" 7653a5a1b3Sopenharmony_ci#define ENV_LOG_COLORS "PULSE_LOG_COLORS" 7753a5a1b3Sopenharmony_ci#define ENV_LOG_PRINT_TIME "PULSE_LOG_TIME" 7853a5a1b3Sopenharmony_ci#define ENV_LOG_PRINT_FILE "PULSE_LOG_FILE" 7953a5a1b3Sopenharmony_ci#define ENV_LOG_PRINT_META "PULSE_LOG_META" 8053a5a1b3Sopenharmony_ci#define ENV_LOG_PRINT_LEVEL "PULSE_LOG_LEVEL" 8153a5a1b3Sopenharmony_ci#define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE" 8253a5a1b3Sopenharmony_ci#define ENV_LOG_BACKTRACE_SKIP "PULSE_LOG_BACKTRACE_SKIP" 8353a5a1b3Sopenharmony_ci#define ENV_LOG_NO_RATELIMIT "PULSE_LOG_NO_RATE_LIMIT" 8453a5a1b3Sopenharmony_ci#define LOG_MAX_SUFFIX_NUMBER 99 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_cistatic char *ident = NULL; /* in local charset format */ 8753a5a1b3Sopenharmony_cistatic pa_log_target target = { PA_LOG_STDERR, NULL }; 8853a5a1b3Sopenharmony_cistatic pa_log_target_type_t target_override; 8953a5a1b3Sopenharmony_cistatic bool target_override_set = false; 9053a5a1b3Sopenharmony_cistatic pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_LOG_ERROR; 9153a5a1b3Sopenharmony_cistatic unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0; 9253a5a1b3Sopenharmony_cistatic pa_log_flags_t flags = 0, flags_override = 0; 9353a5a1b3Sopenharmony_cistatic bool no_rate_limit = false; 9453a5a1b3Sopenharmony_cistatic int log_fd = -1; 9553a5a1b3Sopenharmony_cistatic int write_type = 0; 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H 9853a5a1b3Sopenharmony_cistatic const int level_to_syslog[] = { 9953a5a1b3Sopenharmony_ci [PA_LOG_ERROR] = LOG_ERR, 10053a5a1b3Sopenharmony_ci [PA_LOG_WARN] = LOG_WARNING, 10153a5a1b3Sopenharmony_ci [PA_LOG_NOTICE] = LOG_NOTICE, 10253a5a1b3Sopenharmony_ci [PA_LOG_INFO] = LOG_INFO, 10353a5a1b3Sopenharmony_ci [PA_LOG_DEBUG] = LOG_DEBUG 10453a5a1b3Sopenharmony_ci}; 10553a5a1b3Sopenharmony_ci#endif 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_ci/* These are actually equivalent to the syslog ones 10853a5a1b3Sopenharmony_ci * but we don't want to depend on syslog.h */ 10953a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL 11053a5a1b3Sopenharmony_cistatic const int level_to_journal[] = { 11153a5a1b3Sopenharmony_ci [PA_LOG_ERROR] = 3, 11253a5a1b3Sopenharmony_ci [PA_LOG_WARN] = 4, 11353a5a1b3Sopenharmony_ci [PA_LOG_NOTICE] = 5, 11453a5a1b3Sopenharmony_ci [PA_LOG_INFO] = 6, 11553a5a1b3Sopenharmony_ci [PA_LOG_DEBUG] = 7 11653a5a1b3Sopenharmony_ci}; 11753a5a1b3Sopenharmony_ci#endif 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_cistatic const char level_to_char[] = { 12053a5a1b3Sopenharmony_ci [PA_LOG_ERROR] = 'E', 12153a5a1b3Sopenharmony_ci [PA_LOG_WARN] = 'W', 12253a5a1b3Sopenharmony_ci [PA_LOG_NOTICE] = 'N', 12353a5a1b3Sopenharmony_ci [PA_LOG_INFO] = 'I', 12453a5a1b3Sopenharmony_ci [PA_LOG_DEBUG] = 'D' 12553a5a1b3Sopenharmony_ci}; 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_civoid pa_log_set_ident(const char *p) { 12853a5a1b3Sopenharmony_ci pa_xfree(ident); 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci if (!(ident = pa_utf8_to_locale(p))) 13153a5a1b3Sopenharmony_ci ident = pa_ascii_filter(p); 13253a5a1b3Sopenharmony_ci} 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci/* To make valgrind shut up. */ 13553a5a1b3Sopenharmony_cistatic void ident_destructor(void) PA_GCC_DESTRUCTOR; 13653a5a1b3Sopenharmony_cistatic void ident_destructor(void) { 13753a5a1b3Sopenharmony_ci if (!pa_in_valgrind()) 13853a5a1b3Sopenharmony_ci return; 13953a5a1b3Sopenharmony_ci 14053a5a1b3Sopenharmony_ci pa_xfree(ident); 14153a5a1b3Sopenharmony_ci} 14253a5a1b3Sopenharmony_ci 14353a5a1b3Sopenharmony_civoid pa_log_set_level(pa_log_level_t l) { 14453a5a1b3Sopenharmony_ci pa_assert(l < PA_LOG_LEVEL_MAX); 14553a5a1b3Sopenharmony_ci 14653a5a1b3Sopenharmony_ci maximum_level = l; 14753a5a1b3Sopenharmony_ci} 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ciint pa_log_set_target(pa_log_target *t) { 15053a5a1b3Sopenharmony_ci int fd = -1; 15153a5a1b3Sopenharmony_ci int old_fd; 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci pa_assert(t); 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci switch (t->type) { 15653a5a1b3Sopenharmony_ci case PA_LOG_STDERR: 15753a5a1b3Sopenharmony_ci case PA_LOG_SYSLOG: 15853a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL 15953a5a1b3Sopenharmony_ci case PA_LOG_JOURNAL: 16053a5a1b3Sopenharmony_ci#endif 16153a5a1b3Sopenharmony_ci case PA_LOG_NULL: 16253a5a1b3Sopenharmony_ci break; 16353a5a1b3Sopenharmony_ci case PA_LOG_FILE: 16453a5a1b3Sopenharmony_ci if ((fd = pa_open_cloexec(t->file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { 16553a5a1b3Sopenharmony_ci pa_log(_("Failed to open target file '%s'."), t->file); 16653a5a1b3Sopenharmony_ci return -1; 16753a5a1b3Sopenharmony_ci } 16853a5a1b3Sopenharmony_ci break; 16953a5a1b3Sopenharmony_ci case PA_LOG_NEWFILE: { 17053a5a1b3Sopenharmony_ci char *file_path; 17153a5a1b3Sopenharmony_ci char *p; 17253a5a1b3Sopenharmony_ci unsigned version; 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci file_path = pa_sprintf_malloc("%s.xx", t->file); 17553a5a1b3Sopenharmony_ci p = file_path + strlen(t->file); 17653a5a1b3Sopenharmony_ci 17753a5a1b3Sopenharmony_ci for (version = 0; version <= LOG_MAX_SUFFIX_NUMBER; version++) { 17853a5a1b3Sopenharmony_ci memset(p, 0, 3); /* Overwrite the ".xx" part in file_path with zero bytes. */ 17953a5a1b3Sopenharmony_ci 18053a5a1b3Sopenharmony_ci if (version > 0) 18153a5a1b3Sopenharmony_ci pa_snprintf(p, 4, ".%u", version); /* Why 4? ".xx" + termitating zero byte. */ 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci if ((fd = pa_open_cloexec(file_path, O_WRONLY | O_TRUNC | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) >= 0) 18453a5a1b3Sopenharmony_ci break; 18553a5a1b3Sopenharmony_ci } 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci if (version > LOG_MAX_SUFFIX_NUMBER) { 18853a5a1b3Sopenharmony_ci pa_log(_("Tried to open target file '%s', '%s.1', '%s.2' ... '%s.%d', but all failed."), 18953a5a1b3Sopenharmony_ci t->file, t->file, t->file, t->file, LOG_MAX_SUFFIX_NUMBER); 19053a5a1b3Sopenharmony_ci pa_xfree(file_path); 19153a5a1b3Sopenharmony_ci return -1; 19253a5a1b3Sopenharmony_ci } else 19353a5a1b3Sopenharmony_ci pa_log_debug("Opened target file %s\n", file_path); 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci pa_xfree(file_path); 19653a5a1b3Sopenharmony_ci break; 19753a5a1b3Sopenharmony_ci } 19853a5a1b3Sopenharmony_ci } 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci target.type = t->type; 20153a5a1b3Sopenharmony_ci pa_xfree(target.file); 20253a5a1b3Sopenharmony_ci target.file = pa_xstrdup(t->file); 20353a5a1b3Sopenharmony_ci 20453a5a1b3Sopenharmony_ci old_fd = log_fd; 20553a5a1b3Sopenharmony_ci log_fd = fd; 20653a5a1b3Sopenharmony_ci 20753a5a1b3Sopenharmony_ci if (old_fd >= 0) 20853a5a1b3Sopenharmony_ci pa_close(old_fd); 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci return 0; 21153a5a1b3Sopenharmony_ci} 21253a5a1b3Sopenharmony_ci 21353a5a1b3Sopenharmony_civoid pa_log_set_flags(pa_log_flags_t _flags, pa_log_merge_t merge) { 21453a5a1b3Sopenharmony_ci pa_assert(!(_flags & ~(PA_LOG_COLORS|PA_LOG_PRINT_TIME|PA_LOG_PRINT_FILE|PA_LOG_PRINT_META|PA_LOG_PRINT_LEVEL))); 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci if (merge == PA_LOG_SET) 21753a5a1b3Sopenharmony_ci flags |= _flags; 21853a5a1b3Sopenharmony_ci else if (merge == PA_LOG_UNSET) 21953a5a1b3Sopenharmony_ci flags &= ~_flags; 22053a5a1b3Sopenharmony_ci else 22153a5a1b3Sopenharmony_ci flags = _flags; 22253a5a1b3Sopenharmony_ci} 22353a5a1b3Sopenharmony_ci 22453a5a1b3Sopenharmony_civoid pa_log_set_show_backtrace(unsigned nlevels) { 22553a5a1b3Sopenharmony_ci show_backtrace = nlevels; 22653a5a1b3Sopenharmony_ci} 22753a5a1b3Sopenharmony_ci 22853a5a1b3Sopenharmony_civoid pa_log_set_skip_backtrace(unsigned nlevels) { 22953a5a1b3Sopenharmony_ci skip_backtrace = nlevels; 23053a5a1b3Sopenharmony_ci} 23153a5a1b3Sopenharmony_ci 23253a5a1b3Sopenharmony_ci#ifdef HAVE_EXECINFO_H 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_cistatic char* get_backtrace(unsigned show_nframes) { 23553a5a1b3Sopenharmony_ci void* trace[32]; 23653a5a1b3Sopenharmony_ci int n_frames; 23753a5a1b3Sopenharmony_ci char **symbols, *e, *r; 23853a5a1b3Sopenharmony_ci unsigned j, n, s; 23953a5a1b3Sopenharmony_ci size_t a; 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci pa_assert(show_nframes > 0); 24253a5a1b3Sopenharmony_ci 24353a5a1b3Sopenharmony_ci n_frames = backtrace(trace, PA_ELEMENTSOF(trace)); 24453a5a1b3Sopenharmony_ci 24553a5a1b3Sopenharmony_ci if (n_frames <= 0) 24653a5a1b3Sopenharmony_ci return NULL; 24753a5a1b3Sopenharmony_ci 24853a5a1b3Sopenharmony_ci symbols = backtrace_symbols(trace, n_frames); 24953a5a1b3Sopenharmony_ci 25053a5a1b3Sopenharmony_ci if (!symbols) 25153a5a1b3Sopenharmony_ci return NULL; 25253a5a1b3Sopenharmony_ci 25353a5a1b3Sopenharmony_ci s = skip_backtrace; 25453a5a1b3Sopenharmony_ci n = PA_MIN((unsigned) n_frames, s + show_nframes); 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci a = 4; 25753a5a1b3Sopenharmony_ci 25853a5a1b3Sopenharmony_ci for (j = s; j < n; j++) { 25953a5a1b3Sopenharmony_ci if (j > s) 26053a5a1b3Sopenharmony_ci a += 2; 26153a5a1b3Sopenharmony_ci a += strlen(pa_path_get_filename(symbols[j])); 26253a5a1b3Sopenharmony_ci } 26353a5a1b3Sopenharmony_ci 26453a5a1b3Sopenharmony_ci r = pa_xnew(char, a); 26553a5a1b3Sopenharmony_ci 26653a5a1b3Sopenharmony_ci strcpy(r, " ("); 26753a5a1b3Sopenharmony_ci e = r + 2; 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci for (j = s; j < n; j++) { 27053a5a1b3Sopenharmony_ci const char *sym; 27153a5a1b3Sopenharmony_ci 27253a5a1b3Sopenharmony_ci if (j > s) { 27353a5a1b3Sopenharmony_ci strcpy(e, "<<"); 27453a5a1b3Sopenharmony_ci e += 2; 27553a5a1b3Sopenharmony_ci } 27653a5a1b3Sopenharmony_ci 27753a5a1b3Sopenharmony_ci sym = pa_path_get_filename(symbols[j]); 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci strcpy(e, sym); 28053a5a1b3Sopenharmony_ci e += strlen(sym); 28153a5a1b3Sopenharmony_ci } 28253a5a1b3Sopenharmony_ci 28353a5a1b3Sopenharmony_ci strcpy(e, ")"); 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_ci free(symbols); 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci return r; 28853a5a1b3Sopenharmony_ci} 28953a5a1b3Sopenharmony_ci 29053a5a1b3Sopenharmony_ci#endif 29153a5a1b3Sopenharmony_ci 29253a5a1b3Sopenharmony_cistatic void init_defaults(void) { 29353a5a1b3Sopenharmony_ci PA_ONCE_BEGIN { 29453a5a1b3Sopenharmony_ci 29553a5a1b3Sopenharmony_ci const char *e; 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci if (!ident) { 29853a5a1b3Sopenharmony_ci char binary[256]; 29953a5a1b3Sopenharmony_ci if (pa_get_binary_name(binary, sizeof(binary))) 30053a5a1b3Sopenharmony_ci pa_log_set_ident(binary); 30153a5a1b3Sopenharmony_ci } 30253a5a1b3Sopenharmony_ci 30353a5a1b3Sopenharmony_ci if (getenv(ENV_LOG_SYSLOG)) { 30453a5a1b3Sopenharmony_ci target_override = PA_LOG_SYSLOG; 30553a5a1b3Sopenharmony_ci target_override_set = true; 30653a5a1b3Sopenharmony_ci } 30753a5a1b3Sopenharmony_ci 30853a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL 30953a5a1b3Sopenharmony_ci if (getenv(ENV_LOG_JOURNAL)) { 31053a5a1b3Sopenharmony_ci target_override = PA_LOG_JOURNAL; 31153a5a1b3Sopenharmony_ci target_override_set = true; 31253a5a1b3Sopenharmony_ci } 31353a5a1b3Sopenharmony_ci#endif 31453a5a1b3Sopenharmony_ci 31553a5a1b3Sopenharmony_ci if ((e = getenv(ENV_LOG_LEVEL))) { 31653a5a1b3Sopenharmony_ci maximum_level_override = (pa_log_level_t) atoi(e); 31753a5a1b3Sopenharmony_ci 31853a5a1b3Sopenharmony_ci if (maximum_level_override >= PA_LOG_LEVEL_MAX) 31953a5a1b3Sopenharmony_ci maximum_level_override = PA_LOG_LEVEL_MAX-1; 32053a5a1b3Sopenharmony_ci } 32153a5a1b3Sopenharmony_ci 32253a5a1b3Sopenharmony_ci if (getenv(ENV_LOG_COLORS)) 32353a5a1b3Sopenharmony_ci flags_override |= PA_LOG_COLORS; 32453a5a1b3Sopenharmony_ci 32553a5a1b3Sopenharmony_ci if (getenv(ENV_LOG_PRINT_TIME)) 32653a5a1b3Sopenharmony_ci flags_override |= PA_LOG_PRINT_TIME; 32753a5a1b3Sopenharmony_ci 32853a5a1b3Sopenharmony_ci if (getenv(ENV_LOG_PRINT_FILE)) 32953a5a1b3Sopenharmony_ci flags_override |= PA_LOG_PRINT_FILE; 33053a5a1b3Sopenharmony_ci 33153a5a1b3Sopenharmony_ci if (getenv(ENV_LOG_PRINT_META)) 33253a5a1b3Sopenharmony_ci flags_override |= PA_LOG_PRINT_META; 33353a5a1b3Sopenharmony_ci 33453a5a1b3Sopenharmony_ci if (getenv(ENV_LOG_PRINT_LEVEL)) 33553a5a1b3Sopenharmony_ci flags_override |= PA_LOG_PRINT_LEVEL; 33653a5a1b3Sopenharmony_ci 33753a5a1b3Sopenharmony_ci if ((e = getenv(ENV_LOG_BACKTRACE))) { 33853a5a1b3Sopenharmony_ci show_backtrace_override = (unsigned) atoi(e); 33953a5a1b3Sopenharmony_ci 34053a5a1b3Sopenharmony_ci if (show_backtrace_override <= 0) 34153a5a1b3Sopenharmony_ci show_backtrace_override = 0; 34253a5a1b3Sopenharmony_ci } 34353a5a1b3Sopenharmony_ci 34453a5a1b3Sopenharmony_ci if ((e = getenv(ENV_LOG_BACKTRACE_SKIP))) { 34553a5a1b3Sopenharmony_ci skip_backtrace = (unsigned) atoi(e); 34653a5a1b3Sopenharmony_ci 34753a5a1b3Sopenharmony_ci if (skip_backtrace <= 0) 34853a5a1b3Sopenharmony_ci skip_backtrace = 0; 34953a5a1b3Sopenharmony_ci } 35053a5a1b3Sopenharmony_ci 35153a5a1b3Sopenharmony_ci if (getenv(ENV_LOG_NO_RATELIMIT)) 35253a5a1b3Sopenharmony_ci no_rate_limit = true; 35353a5a1b3Sopenharmony_ci 35453a5a1b3Sopenharmony_ci } PA_ONCE_END; 35553a5a1b3Sopenharmony_ci} 35653a5a1b3Sopenharmony_ci 35753a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H 35853a5a1b3Sopenharmony_cistatic void log_syslog(pa_log_level_t level, char *t, char *timestamp, char *location, char *bt) { 35953a5a1b3Sopenharmony_ci char *local_t; 36053a5a1b3Sopenharmony_ci 36153a5a1b3Sopenharmony_ci openlog(ident, LOG_PID, LOG_USER); 36253a5a1b3Sopenharmony_ci 36353a5a1b3Sopenharmony_ci if ((local_t = pa_utf8_to_locale(t))) 36453a5a1b3Sopenharmony_ci t = local_t; 36553a5a1b3Sopenharmony_ci 36653a5a1b3Sopenharmony_ci syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt)); 36753a5a1b3Sopenharmony_ci pa_xfree(local_t); 36853a5a1b3Sopenharmony_ci} 36953a5a1b3Sopenharmony_ci#endif 37053a5a1b3Sopenharmony_ci 37153a5a1b3Sopenharmony_civoid pa_log_levelv_meta( 37253a5a1b3Sopenharmony_ci pa_log_level_t level, 37353a5a1b3Sopenharmony_ci const char*file, 37453a5a1b3Sopenharmony_ci int line, 37553a5a1b3Sopenharmony_ci const char *func, 37653a5a1b3Sopenharmony_ci const char *format, 37753a5a1b3Sopenharmony_ci va_list ap) { 37853a5a1b3Sopenharmony_ci 37953a5a1b3Sopenharmony_ci char *t, *n; 38053a5a1b3Sopenharmony_ci int saved_errno = errno; 38153a5a1b3Sopenharmony_ci char *bt = NULL; 38253a5a1b3Sopenharmony_ci pa_log_target_type_t _target; 38353a5a1b3Sopenharmony_ci pa_log_level_t _maximum_level; 38453a5a1b3Sopenharmony_ci unsigned _show_backtrace; 38553a5a1b3Sopenharmony_ci pa_log_flags_t _flags; 38653a5a1b3Sopenharmony_ci 38753a5a1b3Sopenharmony_ci /* We don't use dynamic memory allocation here to minimize the hit 38853a5a1b3Sopenharmony_ci * in RT threads */ 38953a5a1b3Sopenharmony_ci char text[256], location[128], timestamp[32]; 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_ci pa_assert(level < PA_LOG_LEVEL_MAX); 39253a5a1b3Sopenharmony_ci pa_assert(format); 39353a5a1b3Sopenharmony_ci 39453a5a1b3Sopenharmony_ci init_defaults(); 39553a5a1b3Sopenharmony_ci 39653a5a1b3Sopenharmony_ci _target = target_override_set ? target_override : target.type; 39753a5a1b3Sopenharmony_ci _maximum_level = PA_MAX(maximum_level, maximum_level_override); 39853a5a1b3Sopenharmony_ci _show_backtrace = PA_MAX(show_backtrace, show_backtrace_override); 39953a5a1b3Sopenharmony_ci _flags = flags | flags_override; 40053a5a1b3Sopenharmony_ci 40153a5a1b3Sopenharmony_ci if (PA_LIKELY(level > _maximum_level)) { 40253a5a1b3Sopenharmony_ci errno = saved_errno; 40353a5a1b3Sopenharmony_ci return; 40453a5a1b3Sopenharmony_ci } 40553a5a1b3Sopenharmony_ci 40653a5a1b3Sopenharmony_ci pa_vsnprintf(text, sizeof(text), format, ap); 40753a5a1b3Sopenharmony_ci 40853a5a1b3Sopenharmony_ci const char *filename = strrchr(file, '/'); 40953a5a1b3Sopenharmony_ci if (filename) { 41053a5a1b3Sopenharmony_ci filename++; 41153a5a1b3Sopenharmony_ci } else { 41253a5a1b3Sopenharmony_ci filename = file; 41353a5a1b3Sopenharmony_ci } 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci if (level == PA_LOG_ERROR) { 41653a5a1b3Sopenharmony_ci AUDIO_ERR_LOG("%{public}s:%{public}u (%{public}s) %{public}s", filename, line, func, text); 41753a5a1b3Sopenharmony_ci } else if (level == PA_LOG_WARN) { 41853a5a1b3Sopenharmony_ci AUDIO_WARNING_LOG("%{public}s:%{public}u (%{public}s) %{public}s", filename, line, func, text); 41953a5a1b3Sopenharmony_ci } else if (level == PA_LOG_NOTICE || level == PA_LOG_INFO) { 42053a5a1b3Sopenharmony_ci AUDIO_INFO_LOG("%{public}s:%{public}u (%{public}s) %{public}s", filename, line, func, text); 42153a5a1b3Sopenharmony_ci } else if (level == PA_LOG_DEBUG) { 42253a5a1b3Sopenharmony_ci AUDIO_DEBUG_LOG("%{public}s:%{public}u (%{public}s) %{public}s", filename, line, func, text); 42353a5a1b3Sopenharmony_ci } 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci if ((_flags & PA_LOG_PRINT_META) && file && line > 0 && func) 42653a5a1b3Sopenharmony_ci pa_snprintf(location, sizeof(location), "[%s][%s:%i %s()] ", 42753a5a1b3Sopenharmony_ci pa_strnull(pa_thread_get_name(pa_thread_self())), file, line, func); 42853a5a1b3Sopenharmony_ci else if ((_flags & (PA_LOG_PRINT_META|PA_LOG_PRINT_FILE)) && file) 42953a5a1b3Sopenharmony_ci pa_snprintf(location, sizeof(location), "[%s] %s: ", 43053a5a1b3Sopenharmony_ci pa_strnull(pa_thread_get_name(pa_thread_self())), pa_path_get_filename(file)); 43153a5a1b3Sopenharmony_ci else 43253a5a1b3Sopenharmony_ci location[0] = 0; 43353a5a1b3Sopenharmony_ci 43453a5a1b3Sopenharmony_ci if (_flags & PA_LOG_PRINT_TIME) { 43553a5a1b3Sopenharmony_ci static pa_usec_t start, last; 43653a5a1b3Sopenharmony_ci pa_usec_t u, a, r; 43753a5a1b3Sopenharmony_ci 43853a5a1b3Sopenharmony_ci u = pa_rtclock_now(); 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci PA_ONCE_BEGIN { 44153a5a1b3Sopenharmony_ci start = u; 44253a5a1b3Sopenharmony_ci last = u; 44353a5a1b3Sopenharmony_ci } PA_ONCE_END; 44453a5a1b3Sopenharmony_ci 44553a5a1b3Sopenharmony_ci r = u - last; 44653a5a1b3Sopenharmony_ci a = u - start; 44753a5a1b3Sopenharmony_ci 44853a5a1b3Sopenharmony_ci /* This is not thread safe, but this is a debugging tool only 44953a5a1b3Sopenharmony_ci * anyway. */ 45053a5a1b3Sopenharmony_ci last = u; 45153a5a1b3Sopenharmony_ci 45253a5a1b3Sopenharmony_ci pa_snprintf(timestamp, sizeof(timestamp), "(%4llu.%03llu|%4llu.%03llu) ", 45353a5a1b3Sopenharmony_ci (unsigned long long) (a / PA_USEC_PER_SEC), 45453a5a1b3Sopenharmony_ci (unsigned long long) (((a / PA_USEC_PER_MSEC)) % 1000), 45553a5a1b3Sopenharmony_ci (unsigned long long) (r / PA_USEC_PER_SEC), 45653a5a1b3Sopenharmony_ci (unsigned long long) (((r / PA_USEC_PER_MSEC)) % 1000)); 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci } else 45953a5a1b3Sopenharmony_ci timestamp[0] = 0; 46053a5a1b3Sopenharmony_ci 46153a5a1b3Sopenharmony_ci#ifdef HAVE_EXECINFO_H 46253a5a1b3Sopenharmony_ci if (_show_backtrace > 0) 46353a5a1b3Sopenharmony_ci bt = get_backtrace(_show_backtrace); 46453a5a1b3Sopenharmony_ci#endif 46553a5a1b3Sopenharmony_ci 46653a5a1b3Sopenharmony_ci if (!pa_utf8_valid(text)) 46753a5a1b3Sopenharmony_ci pa_logl(level, "Invalid UTF-8 string following below:"); 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_ci for (t = text; t; t = n) { 47053a5a1b3Sopenharmony_ci if ((n = strchr(t, '\n'))) { 47153a5a1b3Sopenharmony_ci *n = 0; 47253a5a1b3Sopenharmony_ci n++; 47353a5a1b3Sopenharmony_ci } 47453a5a1b3Sopenharmony_ci 47553a5a1b3Sopenharmony_ci /* We ignore strings only made out of whitespace */ 47653a5a1b3Sopenharmony_ci if (t[strspn(t, "\t ")] == 0) 47753a5a1b3Sopenharmony_ci continue; 47853a5a1b3Sopenharmony_ci 47953a5a1b3Sopenharmony_ci switch (_target) { 48053a5a1b3Sopenharmony_ci 48153a5a1b3Sopenharmony_ci case PA_LOG_STDERR: { 48253a5a1b3Sopenharmony_ci const char *prefix = "", *suffix = "", *grey = ""; 48353a5a1b3Sopenharmony_ci char *local_t; 48453a5a1b3Sopenharmony_ci 48553a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 48653a5a1b3Sopenharmony_ci /* Yes indeed. Useless, but fun! */ 48753a5a1b3Sopenharmony_ci if ((_flags & PA_LOG_COLORS) && isatty(STDERR_FILENO)) { 48853a5a1b3Sopenharmony_ci if (level <= PA_LOG_ERROR) 48953a5a1b3Sopenharmony_ci prefix = "\x1B[1;31m"; 49053a5a1b3Sopenharmony_ci else if (level <= PA_LOG_WARN) 49153a5a1b3Sopenharmony_ci prefix = "\x1B[1m"; 49253a5a1b3Sopenharmony_ci 49353a5a1b3Sopenharmony_ci if (bt) 49453a5a1b3Sopenharmony_ci grey = "\x1B[2m"; 49553a5a1b3Sopenharmony_ci 49653a5a1b3Sopenharmony_ci if (grey[0] || prefix[0]) 49753a5a1b3Sopenharmony_ci suffix = "\x1B[0m"; 49853a5a1b3Sopenharmony_ci } 49953a5a1b3Sopenharmony_ci#endif 50053a5a1b3Sopenharmony_ci 50153a5a1b3Sopenharmony_ci /* We shouldn't be using dynamic allocation here to 50253a5a1b3Sopenharmony_ci * minimize the hit in RT threads */ 50353a5a1b3Sopenharmony_ci if ((local_t = pa_utf8_to_locale(t))) 50453a5a1b3Sopenharmony_ci t = local_t; 50553a5a1b3Sopenharmony_ci 50653a5a1b3Sopenharmony_ci if (_flags & PA_LOG_PRINT_LEVEL) 50753a5a1b3Sopenharmony_ci fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, grey, pa_strempty(bt), suffix); 50853a5a1b3Sopenharmony_ci else 50953a5a1b3Sopenharmony_ci fprintf(stderr, "%s%s%s%s%s%s%s\n", timestamp, location, prefix, t, grey, pa_strempty(bt), suffix); 51053a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 51153a5a1b3Sopenharmony_ci fflush(stderr); 51253a5a1b3Sopenharmony_ci#endif 51353a5a1b3Sopenharmony_ci 51453a5a1b3Sopenharmony_ci pa_xfree(local_t); 51553a5a1b3Sopenharmony_ci 51653a5a1b3Sopenharmony_ci break; 51753a5a1b3Sopenharmony_ci } 51853a5a1b3Sopenharmony_ci 51953a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H 52053a5a1b3Sopenharmony_ci case PA_LOG_SYSLOG: 52153a5a1b3Sopenharmony_ci log_syslog(level, t, timestamp, location, bt); 52253a5a1b3Sopenharmony_ci break; 52353a5a1b3Sopenharmony_ci#endif 52453a5a1b3Sopenharmony_ci 52553a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL 52653a5a1b3Sopenharmony_ci case PA_LOG_JOURNAL: 52753a5a1b3Sopenharmony_ci if (sd_journal_send("MESSAGE=%s", t, 52853a5a1b3Sopenharmony_ci "PRIORITY=%i", level_to_journal[level], 52953a5a1b3Sopenharmony_ci "CODE_FILE=%s", file, 53053a5a1b3Sopenharmony_ci "CODE_FUNC=%s", func, 53153a5a1b3Sopenharmony_ci "CODE_LINE=%d", line, 53253a5a1b3Sopenharmony_ci "PULSE_BACKTRACE=%s", pa_strempty(bt), 53353a5a1b3Sopenharmony_ci NULL) < 0) { 53453a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H 53553a5a1b3Sopenharmony_ci pa_log_target new_target = { .type = PA_LOG_SYSLOG, .file = NULL }; 53653a5a1b3Sopenharmony_ci 53753a5a1b3Sopenharmony_ci syslog(level_to_syslog[PA_LOG_ERROR], "%s%s%s", timestamp, __FILE__, 53853a5a1b3Sopenharmony_ci "Error writing logs to the journal. Redirect log messages to syslog."); 53953a5a1b3Sopenharmony_ci log_syslog(level, t, timestamp, location, bt); 54053a5a1b3Sopenharmony_ci#else 54153a5a1b3Sopenharmony_ci pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL }; 54253a5a1b3Sopenharmony_ci 54353a5a1b3Sopenharmony_ci saved_errno = errno; 54453a5a1b3Sopenharmony_ci fprintf(stderr, "%s\n", "Error writing logs to the journal. Redirect log messages to console."); 54553a5a1b3Sopenharmony_ci fprintf(stderr, "%s\n", t); 54653a5a1b3Sopenharmony_ci#endif 54753a5a1b3Sopenharmony_ci pa_log_set_target(&new_target); 54853a5a1b3Sopenharmony_ci } 54953a5a1b3Sopenharmony_ci break; 55053a5a1b3Sopenharmony_ci#endif 55153a5a1b3Sopenharmony_ci 55253a5a1b3Sopenharmony_ci case PA_LOG_FILE: 55353a5a1b3Sopenharmony_ci case PA_LOG_NEWFILE: { 55453a5a1b3Sopenharmony_ci char *local_t; 55553a5a1b3Sopenharmony_ci 55653a5a1b3Sopenharmony_ci if ((local_t = pa_utf8_to_locale(t))) 55753a5a1b3Sopenharmony_ci t = local_t; 55853a5a1b3Sopenharmony_ci 55953a5a1b3Sopenharmony_ci if (log_fd >= 0) { 56053a5a1b3Sopenharmony_ci char metadata[256]; 56153a5a1b3Sopenharmony_ci 56253a5a1b3Sopenharmony_ci if (_flags & PA_LOG_PRINT_LEVEL) 56353a5a1b3Sopenharmony_ci pa_snprintf(metadata, sizeof(metadata), "%s%c: %s", timestamp, level_to_char[level], location); 56453a5a1b3Sopenharmony_ci else 56553a5a1b3Sopenharmony_ci pa_snprintf(metadata, sizeof(metadata), "%s%s", timestamp, location); 56653a5a1b3Sopenharmony_ci 56753a5a1b3Sopenharmony_ci if ((pa_write(log_fd, metadata, strlen(metadata), &write_type) < 0) 56853a5a1b3Sopenharmony_ci || (pa_write(log_fd, t, strlen(t), &write_type) < 0) 56953a5a1b3Sopenharmony_ci || (bt && pa_write(log_fd, bt, strlen(bt), &write_type) < 0) 57053a5a1b3Sopenharmony_ci || (pa_write(log_fd, "\n", 1, &write_type) < 0)) { 57153a5a1b3Sopenharmony_ci pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL }; 57253a5a1b3Sopenharmony_ci saved_errno = errno; 57353a5a1b3Sopenharmony_ci fprintf(stderr, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console."); 57453a5a1b3Sopenharmony_ci fprintf(stderr, "%s %s\n", metadata, t); 57553a5a1b3Sopenharmony_ci pa_log_set_target(&new_target); 57653a5a1b3Sopenharmony_ci } 57753a5a1b3Sopenharmony_ci } 57853a5a1b3Sopenharmony_ci 57953a5a1b3Sopenharmony_ci pa_xfree(local_t); 58053a5a1b3Sopenharmony_ci 58153a5a1b3Sopenharmony_ci break; 58253a5a1b3Sopenharmony_ci } 58353a5a1b3Sopenharmony_ci case PA_LOG_NULL: 58453a5a1b3Sopenharmony_ci default: 58553a5a1b3Sopenharmony_ci break; 58653a5a1b3Sopenharmony_ci } 58753a5a1b3Sopenharmony_ci } 58853a5a1b3Sopenharmony_ci 58953a5a1b3Sopenharmony_ci pa_xfree(bt); 59053a5a1b3Sopenharmony_ci errno = saved_errno; 59153a5a1b3Sopenharmony_ci} 59253a5a1b3Sopenharmony_ci 59353a5a1b3Sopenharmony_civoid PrintCallStackInfo() 59453a5a1b3Sopenharmony_ci{ 59553a5a1b3Sopenharmony_ci const int32_t maxDepth = 20; 59653a5a1b3Sopenharmony_ci void *stacks[maxDepth]; 59753a5a1b3Sopenharmony_ci 59853a5a1b3Sopenharmony_ci int stackNum = backtrace(stacks, maxDepth); 59953a5a1b3Sopenharmony_ci AUDIO_ERR_LOG("backtrace() returned %{public}d addresses\n", stackNum); 60053a5a1b3Sopenharmony_ci 60153a5a1b3Sopenharmony_ci char **symbols = backtrace_symbols(stacks, stackNum); 60253a5a1b3Sopenharmony_ci if (symbols == NULL) { 60353a5a1b3Sopenharmony_ci AUDIO_ERR_LOG("backtrace_symbols faile."); 60453a5a1b3Sopenharmony_ci for (int i = 0; i < stackNum; i++) { 60553a5a1b3Sopenharmony_ci AUDIO_ERR_LOG(" [%{public}02d] addr: %{public}p\n", i, stacks[i]); 60653a5a1b3Sopenharmony_ci } 60753a5a1b3Sopenharmony_ci return; 60853a5a1b3Sopenharmony_ci } 60953a5a1b3Sopenharmony_ci 61053a5a1b3Sopenharmony_ci for (int i = 0; i < stackNum; i++) { 61153a5a1b3Sopenharmony_ci AUDIO_ERR_LOG(" [%{public}02d] %{public}s\n", i, symbols[i]); 61253a5a1b3Sopenharmony_ci } 61353a5a1b3Sopenharmony_ci 61453a5a1b3Sopenharmony_ci free(symbols); 61553a5a1b3Sopenharmony_ci} 61653a5a1b3Sopenharmony_ci 61753a5a1b3Sopenharmony_civoid pa_log_level_meta( 61853a5a1b3Sopenharmony_ci pa_log_level_t level, 61953a5a1b3Sopenharmony_ci const char*file, 62053a5a1b3Sopenharmony_ci int line, 62153a5a1b3Sopenharmony_ci const char *func, 62253a5a1b3Sopenharmony_ci const char *format, ...) { 62353a5a1b3Sopenharmony_ci 62453a5a1b3Sopenharmony_ci va_list ap; 62553a5a1b3Sopenharmony_ci va_start(ap, format); 62653a5a1b3Sopenharmony_ci pa_log_levelv_meta(level, file, line, func, format, ap); 62753a5a1b3Sopenharmony_ci va_end(ap); 62853a5a1b3Sopenharmony_ci} 62953a5a1b3Sopenharmony_ci 63053a5a1b3Sopenharmony_civoid pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { 63153a5a1b3Sopenharmony_ci pa_log_levelv_meta(level, NULL, 0, NULL, format, ap); 63253a5a1b3Sopenharmony_ci} 63353a5a1b3Sopenharmony_ci 63453a5a1b3Sopenharmony_civoid pa_log_level(pa_log_level_t level, const char *format, ...) { 63553a5a1b3Sopenharmony_ci va_list ap; 63653a5a1b3Sopenharmony_ci 63753a5a1b3Sopenharmony_ci va_start(ap, format); 63853a5a1b3Sopenharmony_ci pa_log_levelv_meta(level, NULL, 0, NULL, format, ap); 63953a5a1b3Sopenharmony_ci va_end(ap); 64053a5a1b3Sopenharmony_ci} 64153a5a1b3Sopenharmony_ci 64253a5a1b3Sopenharmony_cibool pa_log_ratelimit(pa_log_level_t level) { 64353a5a1b3Sopenharmony_ci /* Not more than 10 messages every 5s */ 64453a5a1b3Sopenharmony_ci static PA_DEFINE_RATELIMIT(ratelimit, 5 * PA_USEC_PER_SEC, 10); 64553a5a1b3Sopenharmony_ci 64653a5a1b3Sopenharmony_ci init_defaults(); 64753a5a1b3Sopenharmony_ci 64853a5a1b3Sopenharmony_ci if (no_rate_limit) 64953a5a1b3Sopenharmony_ci return true; 65053a5a1b3Sopenharmony_ci 65153a5a1b3Sopenharmony_ci return pa_ratelimit_test(&ratelimit, level); 65253a5a1b3Sopenharmony_ci} 65353a5a1b3Sopenharmony_ci 65453a5a1b3Sopenharmony_cipa_log_target *pa_log_target_new(pa_log_target_type_t type, const char *file) { 65553a5a1b3Sopenharmony_ci pa_log_target *t = NULL; 65653a5a1b3Sopenharmony_ci 65753a5a1b3Sopenharmony_ci t = pa_xnew(pa_log_target, 1); 65853a5a1b3Sopenharmony_ci 65953a5a1b3Sopenharmony_ci t->type = type; 66053a5a1b3Sopenharmony_ci t->file = pa_xstrdup(file); 66153a5a1b3Sopenharmony_ci 66253a5a1b3Sopenharmony_ci return t; 66353a5a1b3Sopenharmony_ci} 66453a5a1b3Sopenharmony_ci 66553a5a1b3Sopenharmony_civoid pa_log_target_free(pa_log_target *t) { 66653a5a1b3Sopenharmony_ci pa_assert(t); 66753a5a1b3Sopenharmony_ci 66853a5a1b3Sopenharmony_ci pa_xfree(t->file); 66953a5a1b3Sopenharmony_ci pa_xfree(t); 67053a5a1b3Sopenharmony_ci} 67153a5a1b3Sopenharmony_ci 67253a5a1b3Sopenharmony_cipa_log_target *pa_log_parse_target(const char *string) { 67353a5a1b3Sopenharmony_ci pa_log_target *t = NULL; 67453a5a1b3Sopenharmony_ci 67553a5a1b3Sopenharmony_ci pa_assert(string); 67653a5a1b3Sopenharmony_ci 67753a5a1b3Sopenharmony_ci if (pa_streq(string, "stderr")) 67853a5a1b3Sopenharmony_ci t = pa_log_target_new(PA_LOG_STDERR, NULL); 67953a5a1b3Sopenharmony_ci else if (pa_streq(string, "syslog")) 68053a5a1b3Sopenharmony_ci t = pa_log_target_new(PA_LOG_SYSLOG, NULL); 68153a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL 68253a5a1b3Sopenharmony_ci else if (pa_streq(string, "journal")) 68353a5a1b3Sopenharmony_ci t = pa_log_target_new(PA_LOG_JOURNAL, NULL); 68453a5a1b3Sopenharmony_ci#endif 68553a5a1b3Sopenharmony_ci else if (pa_streq(string, "null")) 68653a5a1b3Sopenharmony_ci t = pa_log_target_new(PA_LOG_NULL, NULL); 68753a5a1b3Sopenharmony_ci else if (pa_startswith(string, "file:")) 68853a5a1b3Sopenharmony_ci t = pa_log_target_new(PA_LOG_FILE, string + 5); 68953a5a1b3Sopenharmony_ci else if (pa_startswith(string, "newfile:")) 69053a5a1b3Sopenharmony_ci t = pa_log_target_new(PA_LOG_NEWFILE, string + 8); 69153a5a1b3Sopenharmony_ci else 69253a5a1b3Sopenharmony_ci pa_log(_("Invalid log target.")); 69353a5a1b3Sopenharmony_ci 69453a5a1b3Sopenharmony_ci return t; 69553a5a1b3Sopenharmony_ci} 69653a5a1b3Sopenharmony_ci 69753a5a1b3Sopenharmony_cichar *pa_log_target_to_string(const pa_log_target *t) { 69853a5a1b3Sopenharmony_ci char *string = NULL; 69953a5a1b3Sopenharmony_ci 70053a5a1b3Sopenharmony_ci pa_assert(t); 70153a5a1b3Sopenharmony_ci 70253a5a1b3Sopenharmony_ci switch (t->type) { 70353a5a1b3Sopenharmony_ci case PA_LOG_STDERR: 70453a5a1b3Sopenharmony_ci string = pa_xstrdup("stderr"); 70553a5a1b3Sopenharmony_ci break; 70653a5a1b3Sopenharmony_ci case PA_LOG_SYSLOG: 70753a5a1b3Sopenharmony_ci string = pa_xstrdup("syslog"); 70853a5a1b3Sopenharmony_ci break; 70953a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL 71053a5a1b3Sopenharmony_ci case PA_LOG_JOURNAL: 71153a5a1b3Sopenharmony_ci string = pa_xstrdup("journal"); 71253a5a1b3Sopenharmony_ci break; 71353a5a1b3Sopenharmony_ci#endif 71453a5a1b3Sopenharmony_ci case PA_LOG_NULL: 71553a5a1b3Sopenharmony_ci string = pa_xstrdup("null"); 71653a5a1b3Sopenharmony_ci break; 71753a5a1b3Sopenharmony_ci case PA_LOG_FILE: 71853a5a1b3Sopenharmony_ci string = pa_sprintf_malloc("file:%s", t->file); 71953a5a1b3Sopenharmony_ci break; 72053a5a1b3Sopenharmony_ci case PA_LOG_NEWFILE: 72153a5a1b3Sopenharmony_ci string = pa_sprintf_malloc("newfile:%s", t->file); 72253a5a1b3Sopenharmony_ci break; 72353a5a1b3Sopenharmony_ci } 72453a5a1b3Sopenharmony_ci 72553a5a1b3Sopenharmony_ci return string; 72653a5a1b3Sopenharmony_ci} 727