199ca880aSopenharmony_ci/*** 299ca880aSopenharmony_ci This file is part of eudev, forked from systemd. 399ca880aSopenharmony_ci 499ca880aSopenharmony_ci Copyright 2010 Lennart Poettering 599ca880aSopenharmony_ci 699ca880aSopenharmony_ci systemd is free software; you can redistribute it and/or modify it 799ca880aSopenharmony_ci under the terms of the GNU Lesser General Public License as published by 899ca880aSopenharmony_ci the Free Software Foundation; either version 2.1 of the License, or 999ca880aSopenharmony_ci (at your option) any later version. 1099ca880aSopenharmony_ci 1199ca880aSopenharmony_ci systemd is distributed in the hope that it will be useful, but 1299ca880aSopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1399ca880aSopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1499ca880aSopenharmony_ci Lesser General Public License for more details. 1599ca880aSopenharmony_ci 1699ca880aSopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1799ca880aSopenharmony_ci along with systemd; If not, see <http://www.gnu.org/licenses/>. 1899ca880aSopenharmony_ci***/ 1999ca880aSopenharmony_ci 2099ca880aSopenharmony_ci#include <stdarg.h> 2199ca880aSopenharmony_ci#include <stdio.h> 2299ca880aSopenharmony_ci#include <errno.h> 2399ca880aSopenharmony_ci#include <unistd.h> 2499ca880aSopenharmony_ci#include <fcntl.h> 2599ca880aSopenharmony_ci#include <sys/socket.h> 2699ca880aSopenharmony_ci#include <sys/un.h> 2799ca880aSopenharmony_ci#include <stddef.h> 2899ca880aSopenharmony_ci#include <string.h> 2999ca880aSopenharmony_ci 3099ca880aSopenharmony_ci#include "log.h" 3199ca880aSopenharmony_ci#include "util.h" 3299ca880aSopenharmony_ci#include "missing.h" 3399ca880aSopenharmony_ci#include "macro.h" 3499ca880aSopenharmony_ci#include "socket-util.h" 3599ca880aSopenharmony_ci#include "time-util.h" 3699ca880aSopenharmony_ci#include "process-util.h" 3799ca880aSopenharmony_ci#include "terminal-util.h" 3899ca880aSopenharmony_ci 3999ca880aSopenharmony_ci#define SNDBUF_SIZE (8*1024*1024) 4099ca880aSopenharmony_ci 4199ca880aSopenharmony_cistatic LogTarget log_target = LOG_TARGET_CONSOLE; 4299ca880aSopenharmony_cistatic int log_max_level = LOG_INFO; 4399ca880aSopenharmony_cistatic int log_facility = LOG_DAEMON; 4499ca880aSopenharmony_ci 4599ca880aSopenharmony_cistatic int console_fd = STDERR_FILENO; 4699ca880aSopenharmony_cistatic int syslog_fd = -1; 4799ca880aSopenharmony_cistatic int kmsg_fd = -1; 4899ca880aSopenharmony_ci 4999ca880aSopenharmony_cistatic bool syslog_is_stream = false; 5099ca880aSopenharmony_ci 5199ca880aSopenharmony_cistatic bool show_color = false; 5299ca880aSopenharmony_cistatic bool show_location = false; 5399ca880aSopenharmony_ci 5499ca880aSopenharmony_ci/* Akin to glibc's __abort_msg; which is private and we hence cannot 5599ca880aSopenharmony_ci * use here. */ 5699ca880aSopenharmony_cistatic char *log_abort_msg = NULL; 5799ca880aSopenharmony_ci 5899ca880aSopenharmony_civoid log_close_console(void) { 5999ca880aSopenharmony_ci 6099ca880aSopenharmony_ci if (console_fd < 0) 6199ca880aSopenharmony_ci return; 6299ca880aSopenharmony_ci 6399ca880aSopenharmony_ci if (getpid() == 1) { 6499ca880aSopenharmony_ci if (console_fd >= 3) 6599ca880aSopenharmony_ci safe_close(console_fd); 6699ca880aSopenharmony_ci 6799ca880aSopenharmony_ci console_fd = -1; 6899ca880aSopenharmony_ci } 6999ca880aSopenharmony_ci} 7099ca880aSopenharmony_ci 7199ca880aSopenharmony_cistatic int log_open_console(void) { 7299ca880aSopenharmony_ci 7399ca880aSopenharmony_ci if (console_fd >= 0) 7499ca880aSopenharmony_ci return 0; 7599ca880aSopenharmony_ci 7699ca880aSopenharmony_ci if (getpid() == 1) { 7799ca880aSopenharmony_ci console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); 7899ca880aSopenharmony_ci if (console_fd < 0) 7999ca880aSopenharmony_ci return console_fd; 8099ca880aSopenharmony_ci } else 8199ca880aSopenharmony_ci console_fd = STDERR_FILENO; 8299ca880aSopenharmony_ci 8399ca880aSopenharmony_ci return 0; 8499ca880aSopenharmony_ci} 8599ca880aSopenharmony_ci 8699ca880aSopenharmony_civoid log_close_kmsg(void) { 8799ca880aSopenharmony_ci kmsg_fd = safe_close(kmsg_fd); 8899ca880aSopenharmony_ci} 8999ca880aSopenharmony_ci 9099ca880aSopenharmony_cistatic int log_open_kmsg(void) { 9199ca880aSopenharmony_ci 9299ca880aSopenharmony_ci if (kmsg_fd >= 0) 9399ca880aSopenharmony_ci return 0; 9499ca880aSopenharmony_ci 9599ca880aSopenharmony_ci kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); 9699ca880aSopenharmony_ci if (kmsg_fd < 0) 9799ca880aSopenharmony_ci return -errno; 9899ca880aSopenharmony_ci 9999ca880aSopenharmony_ci return 0; 10099ca880aSopenharmony_ci} 10199ca880aSopenharmony_ci 10299ca880aSopenharmony_civoid log_close_syslog(void) { 10399ca880aSopenharmony_ci syslog_fd = safe_close(syslog_fd); 10499ca880aSopenharmony_ci} 10599ca880aSopenharmony_ci 10699ca880aSopenharmony_cistatic int create_log_socket(int type) { 10799ca880aSopenharmony_ci struct timeval tv; 10899ca880aSopenharmony_ci int fd; 10999ca880aSopenharmony_ci 11099ca880aSopenharmony_ci fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0); 11199ca880aSopenharmony_ci if (fd < 0) 11299ca880aSopenharmony_ci return -errno; 11399ca880aSopenharmony_ci 11499ca880aSopenharmony_ci fd_inc_sndbuf(fd, SNDBUF_SIZE); 11599ca880aSopenharmony_ci 11699ca880aSopenharmony_ci /* We need a blocking fd here since we'd otherwise lose 11799ca880aSopenharmony_ci messages way too early. However, let's not hang forever in the 11899ca880aSopenharmony_ci unlikely case of a deadlock. */ 11999ca880aSopenharmony_ci if (getpid() == 1) 12099ca880aSopenharmony_ci timeval_store(&tv, 10 * USEC_PER_MSEC); 12199ca880aSopenharmony_ci else 12299ca880aSopenharmony_ci timeval_store(&tv, 10 * USEC_PER_SEC); 12399ca880aSopenharmony_ci (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); 12499ca880aSopenharmony_ci 12599ca880aSopenharmony_ci return fd; 12699ca880aSopenharmony_ci} 12799ca880aSopenharmony_ci 12899ca880aSopenharmony_cistatic int log_open_syslog(void) { 12999ca880aSopenharmony_ci 13099ca880aSopenharmony_ci static const union sockaddr_union sa = { 13199ca880aSopenharmony_ci .un.sun_family = AF_UNIX, 13299ca880aSopenharmony_ci .un.sun_path = "/dev/log", 13399ca880aSopenharmony_ci }; 13499ca880aSopenharmony_ci 13599ca880aSopenharmony_ci int r; 13699ca880aSopenharmony_ci 13799ca880aSopenharmony_ci if (syslog_fd >= 0) 13899ca880aSopenharmony_ci return 0; 13999ca880aSopenharmony_ci 14099ca880aSopenharmony_ci syslog_fd = create_log_socket(SOCK_DGRAM); 14199ca880aSopenharmony_ci if (syslog_fd < 0) { 14299ca880aSopenharmony_ci r = syslog_fd; 14399ca880aSopenharmony_ci goto fail; 14499ca880aSopenharmony_ci } 14599ca880aSopenharmony_ci 14699ca880aSopenharmony_ci if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { 14799ca880aSopenharmony_ci safe_close(syslog_fd); 14899ca880aSopenharmony_ci 14999ca880aSopenharmony_ci /* Some legacy syslog systems still use stream 15099ca880aSopenharmony_ci * sockets. They really shouldn't. But what can we 15199ca880aSopenharmony_ci * do... */ 15299ca880aSopenharmony_ci syslog_fd = create_log_socket(SOCK_STREAM); 15399ca880aSopenharmony_ci if (syslog_fd < 0) { 15499ca880aSopenharmony_ci r = syslog_fd; 15599ca880aSopenharmony_ci goto fail; 15699ca880aSopenharmony_ci } 15799ca880aSopenharmony_ci 15899ca880aSopenharmony_ci if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { 15999ca880aSopenharmony_ci r = -errno; 16099ca880aSopenharmony_ci goto fail; 16199ca880aSopenharmony_ci } 16299ca880aSopenharmony_ci 16399ca880aSopenharmony_ci syslog_is_stream = true; 16499ca880aSopenharmony_ci } else 16599ca880aSopenharmony_ci syslog_is_stream = false; 16699ca880aSopenharmony_ci 16799ca880aSopenharmony_ci return 0; 16899ca880aSopenharmony_ci 16999ca880aSopenharmony_cifail: 17099ca880aSopenharmony_ci log_close_syslog(); 17199ca880aSopenharmony_ci return r; 17299ca880aSopenharmony_ci} 17399ca880aSopenharmony_ci 17499ca880aSopenharmony_ciint log_open(void) { 17599ca880aSopenharmony_ci int r; 17699ca880aSopenharmony_ci 17799ca880aSopenharmony_ci /* If we don't use the console we close it here, to not get 17899ca880aSopenharmony_ci * killed by SAK. If we don't use syslog we close it here so 17999ca880aSopenharmony_ci * that we are not confused by somebody deleting the socket in 18099ca880aSopenharmony_ci * the fs. If we don't use /dev/kmsg we still keep it open, 18199ca880aSopenharmony_ci * because there is no reason to close it. */ 18299ca880aSopenharmony_ci 18399ca880aSopenharmony_ci if (log_target == LOG_TARGET_NULL) { 18499ca880aSopenharmony_ci log_close_syslog(); 18599ca880aSopenharmony_ci log_close_console(); 18699ca880aSopenharmony_ci return 0; 18799ca880aSopenharmony_ci } 18899ca880aSopenharmony_ci 18999ca880aSopenharmony_ci if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) || 19099ca880aSopenharmony_ci getpid() == 1 || 19199ca880aSopenharmony_ci isatty(STDERR_FILENO) <= 0) { 19299ca880aSopenharmony_ci 19399ca880aSopenharmony_ci if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || 19499ca880aSopenharmony_ci log_target == LOG_TARGET_SYSLOG) { 19599ca880aSopenharmony_ci r = log_open_syslog(); 19699ca880aSopenharmony_ci if (r >= 0) { 19799ca880aSopenharmony_ci log_close_console(); 19899ca880aSopenharmony_ci return r; 19999ca880aSopenharmony_ci } 20099ca880aSopenharmony_ci } 20199ca880aSopenharmony_ci 20299ca880aSopenharmony_ci if (log_target == LOG_TARGET_AUTO || 20399ca880aSopenharmony_ci log_target == LOG_TARGET_SAFE || 20499ca880aSopenharmony_ci log_target == LOG_TARGET_SYSLOG_OR_KMSG || 20599ca880aSopenharmony_ci log_target == LOG_TARGET_KMSG) { 20699ca880aSopenharmony_ci r = log_open_kmsg(); 20799ca880aSopenharmony_ci if (r >= 0) { 20899ca880aSopenharmony_ci log_close_syslog(); 20999ca880aSopenharmony_ci log_close_console(); 21099ca880aSopenharmony_ci return r; 21199ca880aSopenharmony_ci } 21299ca880aSopenharmony_ci } 21399ca880aSopenharmony_ci } 21499ca880aSopenharmony_ci 21599ca880aSopenharmony_ci log_close_syslog(); 21699ca880aSopenharmony_ci 21799ca880aSopenharmony_ci return log_open_console(); 21899ca880aSopenharmony_ci} 21999ca880aSopenharmony_ci 22099ca880aSopenharmony_civoid log_set_target(LogTarget target) { 22199ca880aSopenharmony_ci assert(target >= 0); 22299ca880aSopenharmony_ci assert(target < _LOG_TARGET_MAX); 22399ca880aSopenharmony_ci 22499ca880aSopenharmony_ci log_target = target; 22599ca880aSopenharmony_ci} 22699ca880aSopenharmony_ci 22799ca880aSopenharmony_civoid log_close(void) { 22899ca880aSopenharmony_ci log_close_syslog(); 22999ca880aSopenharmony_ci log_close_kmsg(); 23099ca880aSopenharmony_ci log_close_console(); 23199ca880aSopenharmony_ci} 23299ca880aSopenharmony_ci 23399ca880aSopenharmony_civoid log_set_max_level(int level) { 23499ca880aSopenharmony_ci assert((level & LOG_PRIMASK) == level); 23599ca880aSopenharmony_ci 23699ca880aSopenharmony_ci log_max_level = level; 23799ca880aSopenharmony_ci} 23899ca880aSopenharmony_ci 23999ca880aSopenharmony_cistatic int write_to_console( 24099ca880aSopenharmony_ci int level, 24199ca880aSopenharmony_ci int error, 24299ca880aSopenharmony_ci const char *file, 24399ca880aSopenharmony_ci int line, 24499ca880aSopenharmony_ci const char *func, 24599ca880aSopenharmony_ci const char *object_field, 24699ca880aSopenharmony_ci const char *object, 24799ca880aSopenharmony_ci const char *buffer) { 24899ca880aSopenharmony_ci 24999ca880aSopenharmony_ci char location[64], prefix[1 + DECIMAL_STR_MAX(int) + 2]; 25099ca880aSopenharmony_ci struct iovec iovec[6] = {}; 25199ca880aSopenharmony_ci unsigned n = 0; 25299ca880aSopenharmony_ci bool highlight; 25399ca880aSopenharmony_ci 25499ca880aSopenharmony_ci if (console_fd < 0) 25599ca880aSopenharmony_ci return 0; 25699ca880aSopenharmony_ci 25799ca880aSopenharmony_ci if (log_target == LOG_TARGET_CONSOLE_PREFIXED) { 25899ca880aSopenharmony_ci sprintf(prefix, "<%i>", level); 25999ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[n++], prefix); 26099ca880aSopenharmony_ci } 26199ca880aSopenharmony_ci 26299ca880aSopenharmony_ci highlight = LOG_PRI(level) <= LOG_ERR && show_color; 26399ca880aSopenharmony_ci 26499ca880aSopenharmony_ci if (show_location) { 26599ca880aSopenharmony_ci snprintf(location, sizeof(location), "(%s:%i) ", file, line); 26699ca880aSopenharmony_ci char_array_0(location); 26799ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[n++], location); 26899ca880aSopenharmony_ci } 26999ca880aSopenharmony_ci 27099ca880aSopenharmony_ci if (highlight) 27199ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON); 27299ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[n++], buffer); 27399ca880aSopenharmony_ci if (highlight) 27499ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); 27599ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[n++], "\n"); 27699ca880aSopenharmony_ci 27799ca880aSopenharmony_ci if (writev(console_fd, iovec, n) < 0) { 27899ca880aSopenharmony_ci 27999ca880aSopenharmony_ci if (errno == EIO && getpid() == 1) { 28099ca880aSopenharmony_ci 28199ca880aSopenharmony_ci /* If somebody tried to kick us from our 28299ca880aSopenharmony_ci * console tty (via vhangup() or suchlike), 28399ca880aSopenharmony_ci * try to reconnect */ 28499ca880aSopenharmony_ci 28599ca880aSopenharmony_ci log_close_console(); 28699ca880aSopenharmony_ci log_open_console(); 28799ca880aSopenharmony_ci 28899ca880aSopenharmony_ci if (console_fd < 0) 28999ca880aSopenharmony_ci return 0; 29099ca880aSopenharmony_ci 29199ca880aSopenharmony_ci if (writev(console_fd, iovec, n) < 0) 29299ca880aSopenharmony_ci return -errno; 29399ca880aSopenharmony_ci } else 29499ca880aSopenharmony_ci return -errno; 29599ca880aSopenharmony_ci } 29699ca880aSopenharmony_ci 29799ca880aSopenharmony_ci return 1; 29899ca880aSopenharmony_ci} 29999ca880aSopenharmony_ci 30099ca880aSopenharmony_cistatic int write_to_syslog( 30199ca880aSopenharmony_ci int level, 30299ca880aSopenharmony_ci int error, 30399ca880aSopenharmony_ci const char *file, 30499ca880aSopenharmony_ci int line, 30599ca880aSopenharmony_ci const char *func, 30699ca880aSopenharmony_ci const char *object_field, 30799ca880aSopenharmony_ci const char *object, 30899ca880aSopenharmony_ci const char *buffer) { 30999ca880aSopenharmony_ci 31099ca880aSopenharmony_ci char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_time[64], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4]; 31199ca880aSopenharmony_ci struct iovec iovec[5] = {}; 31299ca880aSopenharmony_ci struct msghdr msghdr = { 31399ca880aSopenharmony_ci .msg_iov = iovec, 31499ca880aSopenharmony_ci .msg_iovlen = ELEMENTSOF(iovec), 31599ca880aSopenharmony_ci }; 31699ca880aSopenharmony_ci time_t t; 31799ca880aSopenharmony_ci struct tm *tm; 31899ca880aSopenharmony_ci 31999ca880aSopenharmony_ci if (syslog_fd < 0) 32099ca880aSopenharmony_ci return 0; 32199ca880aSopenharmony_ci 32299ca880aSopenharmony_ci snprintf(header_priority, sizeof(header_priority), "<%i>", level); 32399ca880aSopenharmony_ci char_array_0(header_priority); 32499ca880aSopenharmony_ci 32599ca880aSopenharmony_ci t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC); 32699ca880aSopenharmony_ci tm = localtime(&t); 32799ca880aSopenharmony_ci if (!tm) 32899ca880aSopenharmony_ci return -EINVAL; 32999ca880aSopenharmony_ci 33099ca880aSopenharmony_ci if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) 33199ca880aSopenharmony_ci return -EINVAL; 33299ca880aSopenharmony_ci 33399ca880aSopenharmony_ci snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid()); 33499ca880aSopenharmony_ci char_array_0(header_pid); 33599ca880aSopenharmony_ci 33699ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[0], header_priority); 33799ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[1], header_time); 33899ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[2], program_invocation_short_name); 33999ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[3], header_pid); 34099ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[4], buffer); 34199ca880aSopenharmony_ci 34299ca880aSopenharmony_ci /* When using syslog via SOCK_STREAM separate the messages by NUL chars */ 34399ca880aSopenharmony_ci if (syslog_is_stream) 34499ca880aSopenharmony_ci iovec[4].iov_len++; 34599ca880aSopenharmony_ci 34699ca880aSopenharmony_ci for (;;) { 34799ca880aSopenharmony_ci ssize_t n; 34899ca880aSopenharmony_ci 34999ca880aSopenharmony_ci n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL); 35099ca880aSopenharmony_ci if (n < 0) 35199ca880aSopenharmony_ci return -errno; 35299ca880aSopenharmony_ci 35399ca880aSopenharmony_ci if (!syslog_is_stream || 35499ca880aSopenharmony_ci (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec))) 35599ca880aSopenharmony_ci break; 35699ca880aSopenharmony_ci 35799ca880aSopenharmony_ci IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n); 35899ca880aSopenharmony_ci } 35999ca880aSopenharmony_ci 36099ca880aSopenharmony_ci return 1; 36199ca880aSopenharmony_ci} 36299ca880aSopenharmony_ci 36399ca880aSopenharmony_cistatic int write_to_kmsg( 36499ca880aSopenharmony_ci int level, 36599ca880aSopenharmony_ci int error, 36699ca880aSopenharmony_ci const char*file, 36799ca880aSopenharmony_ci int line, 36899ca880aSopenharmony_ci const char *func, 36999ca880aSopenharmony_ci const char *object_field, 37099ca880aSopenharmony_ci const char *object, 37199ca880aSopenharmony_ci const char *buffer) { 37299ca880aSopenharmony_ci 37399ca880aSopenharmony_ci char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4]; 37499ca880aSopenharmony_ci struct iovec iovec[5] = {}; 37599ca880aSopenharmony_ci 37699ca880aSopenharmony_ci if (kmsg_fd < 0) 37799ca880aSopenharmony_ci return 0; 37899ca880aSopenharmony_ci 37999ca880aSopenharmony_ci snprintf(header_priority, sizeof(header_priority), "<%i>", level); 38099ca880aSopenharmony_ci char_array_0(header_priority); 38199ca880aSopenharmony_ci 38299ca880aSopenharmony_ci snprintf(header_pid, sizeof(header_pid), "["PID_FMT"]: ", getpid()); 38399ca880aSopenharmony_ci char_array_0(header_pid); 38499ca880aSopenharmony_ci 38599ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[0], header_priority); 38699ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[1], program_invocation_short_name); 38799ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[2], header_pid); 38899ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[3], buffer); 38999ca880aSopenharmony_ci IOVEC_SET_STRING(iovec[4], "\n"); 39099ca880aSopenharmony_ci 39199ca880aSopenharmony_ci if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0) 39299ca880aSopenharmony_ci return -errno; 39399ca880aSopenharmony_ci 39499ca880aSopenharmony_ci return 1; 39599ca880aSopenharmony_ci} 39699ca880aSopenharmony_ci 39799ca880aSopenharmony_cistatic int log_dispatch( 39899ca880aSopenharmony_ci int level, 39999ca880aSopenharmony_ci int error, 40099ca880aSopenharmony_ci const char*file, 40199ca880aSopenharmony_ci int line, 40299ca880aSopenharmony_ci const char *func, 40399ca880aSopenharmony_ci const char *object_field, 40499ca880aSopenharmony_ci const char *object, 40599ca880aSopenharmony_ci char *buffer) { 40699ca880aSopenharmony_ci 40799ca880aSopenharmony_ci int r = 0; 40899ca880aSopenharmony_ci 40999ca880aSopenharmony_ci if (log_target == LOG_TARGET_NULL) 41099ca880aSopenharmony_ci return 0; 41199ca880aSopenharmony_ci 41299ca880aSopenharmony_ci /* Patch in LOG_DAEMON facility if necessary */ 41399ca880aSopenharmony_ci if ((level & LOG_FACMASK) == 0) 41499ca880aSopenharmony_ci level = log_facility | LOG_PRI(level); 41599ca880aSopenharmony_ci 41699ca880aSopenharmony_ci do { 41799ca880aSopenharmony_ci char *e; 41899ca880aSopenharmony_ci int k = 0; 41999ca880aSopenharmony_ci 42099ca880aSopenharmony_ci buffer += strspn(buffer, NEWLINE); 42199ca880aSopenharmony_ci 42299ca880aSopenharmony_ci if (buffer[0] == 0) 42399ca880aSopenharmony_ci break; 42499ca880aSopenharmony_ci 42599ca880aSopenharmony_ci if ((e = strpbrk(buffer, NEWLINE))) 42699ca880aSopenharmony_ci *(e++) = 0; 42799ca880aSopenharmony_ci 42899ca880aSopenharmony_ci if (log_target == LOG_TARGET_AUTO) 42999ca880aSopenharmony_ci log_open_kmsg(); 43099ca880aSopenharmony_ci 43199ca880aSopenharmony_ci if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || 43299ca880aSopenharmony_ci log_target == LOG_TARGET_SYSLOG) { 43399ca880aSopenharmony_ci 43499ca880aSopenharmony_ci k = write_to_syslog(level, error, file, line, func, object_field, object, buffer); 43599ca880aSopenharmony_ci if (k < 0) { 43699ca880aSopenharmony_ci if (k != -EAGAIN) 43799ca880aSopenharmony_ci log_close_syslog(); 43899ca880aSopenharmony_ci log_open_kmsg(); 43999ca880aSopenharmony_ci } else if (k > 0) 44099ca880aSopenharmony_ci r++; 44199ca880aSopenharmony_ci } 44299ca880aSopenharmony_ci 44399ca880aSopenharmony_ci if (k <= 0 && 44499ca880aSopenharmony_ci (log_target == LOG_TARGET_AUTO || 44599ca880aSopenharmony_ci log_target == LOG_TARGET_SAFE || 44699ca880aSopenharmony_ci log_target == LOG_TARGET_SYSLOG_OR_KMSG || 44799ca880aSopenharmony_ci log_target == LOG_TARGET_KMSG)) { 44899ca880aSopenharmony_ci 44999ca880aSopenharmony_ci k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer); 45099ca880aSopenharmony_ci if (k < 0) { 45199ca880aSopenharmony_ci log_close_kmsg(); 45299ca880aSopenharmony_ci log_open_console(); 45399ca880aSopenharmony_ci } else if (k > 0) 45499ca880aSopenharmony_ci r++; 45599ca880aSopenharmony_ci } 45699ca880aSopenharmony_ci 45799ca880aSopenharmony_ci if (k <= 0) { 45899ca880aSopenharmony_ci k = write_to_console(level, error, file, line, func, object_field, object, buffer); 45999ca880aSopenharmony_ci if (k < 0) 46099ca880aSopenharmony_ci return k; 46199ca880aSopenharmony_ci } 46299ca880aSopenharmony_ci 46399ca880aSopenharmony_ci buffer = e; 46499ca880aSopenharmony_ci } while (buffer); 46599ca880aSopenharmony_ci 46699ca880aSopenharmony_ci return r; 46799ca880aSopenharmony_ci} 46899ca880aSopenharmony_ci 46999ca880aSopenharmony_ciint log_internalv( 47099ca880aSopenharmony_ci int level, 47199ca880aSopenharmony_ci int error, 47299ca880aSopenharmony_ci const char*file, 47399ca880aSopenharmony_ci int line, 47499ca880aSopenharmony_ci const char *func, 47599ca880aSopenharmony_ci const char *format, 47699ca880aSopenharmony_ci va_list ap) { 47799ca880aSopenharmony_ci 47899ca880aSopenharmony_ci PROTECT_ERRNO; 47999ca880aSopenharmony_ci char buffer[LINE_MAX]; 48099ca880aSopenharmony_ci 48199ca880aSopenharmony_ci if (_likely_(LOG_PRI(level) > log_max_level)) 48299ca880aSopenharmony_ci return 0; 48399ca880aSopenharmony_ci 48499ca880aSopenharmony_ci vsnprintf(buffer, sizeof(buffer), format, ap); 48599ca880aSopenharmony_ci char_array_0(buffer); 48699ca880aSopenharmony_ci 48799ca880aSopenharmony_ci return log_dispatch(level, error, file, line, func, NULL, NULL, buffer); 48899ca880aSopenharmony_ci} 48999ca880aSopenharmony_ci 49099ca880aSopenharmony_ciint log_internal( 49199ca880aSopenharmony_ci int level, 49299ca880aSopenharmony_ci int error, 49399ca880aSopenharmony_ci const char*file, 49499ca880aSopenharmony_ci int line, 49599ca880aSopenharmony_ci const char *func, 49699ca880aSopenharmony_ci const char *format, ...) { 49799ca880aSopenharmony_ci 49899ca880aSopenharmony_ci int r; 49999ca880aSopenharmony_ci va_list ap; 50099ca880aSopenharmony_ci 50199ca880aSopenharmony_ci va_start(ap, format); 50299ca880aSopenharmony_ci r = log_internalv(level, error, file, line, func, format, ap); 50399ca880aSopenharmony_ci va_end(ap); 50499ca880aSopenharmony_ci 50599ca880aSopenharmony_ci return r; 50699ca880aSopenharmony_ci} 50799ca880aSopenharmony_ci 50899ca880aSopenharmony_cistatic void log_assert( 50999ca880aSopenharmony_ci int level, 51099ca880aSopenharmony_ci const char *text, 51199ca880aSopenharmony_ci const char *file, 51299ca880aSopenharmony_ci int line, 51399ca880aSopenharmony_ci const char *func, 51499ca880aSopenharmony_ci const char *format) { 51599ca880aSopenharmony_ci static char buffer[LINE_MAX]; 51699ca880aSopenharmony_ci 51799ca880aSopenharmony_ci if (_likely_(LOG_PRI(level) > log_max_level)) 51899ca880aSopenharmony_ci return; 51999ca880aSopenharmony_ci 52099ca880aSopenharmony_ci DISABLE_WARNING_FORMAT_NONLITERAL; 52199ca880aSopenharmony_ci snprintf(buffer, sizeof(buffer), format, text, file, line, func); 52299ca880aSopenharmony_ci REENABLE_WARNING; 52399ca880aSopenharmony_ci 52499ca880aSopenharmony_ci char_array_0(buffer); 52599ca880aSopenharmony_ci log_abort_msg = buffer; 52699ca880aSopenharmony_ci 52799ca880aSopenharmony_ci log_dispatch(level, 0, file, line, func, NULL, NULL, buffer); 52899ca880aSopenharmony_ci} 52999ca880aSopenharmony_ci 53099ca880aSopenharmony_cinoreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) { 53199ca880aSopenharmony_ci log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); 53299ca880aSopenharmony_ci abort(); 53399ca880aSopenharmony_ci} 53499ca880aSopenharmony_ci 53599ca880aSopenharmony_cinoreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) { 53699ca880aSopenharmony_ci log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); 53799ca880aSopenharmony_ci abort(); 53899ca880aSopenharmony_ci} 53999ca880aSopenharmony_ci 54099ca880aSopenharmony_ciint log_oom_internal(const char *file, int line, const char *func) { 54199ca880aSopenharmony_ci log_internal(LOG_ERR, ENOMEM, file, line, func, "Out of memory."); 54299ca880aSopenharmony_ci return -ENOMEM; 54399ca880aSopenharmony_ci} 54499ca880aSopenharmony_ci 54599ca880aSopenharmony_ciint log_get_max_level(void) { 54699ca880aSopenharmony_ci return log_max_level; 54799ca880aSopenharmony_ci} 54899ca880aSopenharmony_cistatic const char *const log_target_table[] = { 54999ca880aSopenharmony_ci [LOG_TARGET_CONSOLE] = "console", 55099ca880aSopenharmony_ci [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed", 55199ca880aSopenharmony_ci [LOG_TARGET_KMSG] = "kmsg", 55299ca880aSopenharmony_ci [LOG_TARGET_SYSLOG] = "syslog", 55399ca880aSopenharmony_ci [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg", 55499ca880aSopenharmony_ci [LOG_TARGET_AUTO] = "auto", 55599ca880aSopenharmony_ci [LOG_TARGET_SAFE] = "safe", 55699ca880aSopenharmony_ci [LOG_TARGET_NULL] = "null" 55799ca880aSopenharmony_ci}; 55899ca880aSopenharmony_ci 55999ca880aSopenharmony_ciDEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget); 560