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