LCOV - code coverage report
Current view: top level - basic - log.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 351 575 61.0 %
Date: 2019-08-22 15:41:25 Functions: 39 59 66.1 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <fcntl.h>
       5             : #include <inttypes.h>
       6             : #include <limits.h>
       7             : #include <stdarg.h>
       8             : #include <stddef.h>
       9             : #include <stdio.h>
      10             : #include <string.h>
      11             : #include <sys/signalfd.h>
      12             : #include <sys/socket.h>
      13             : #include <sys/time.h>
      14             : #include <sys/uio.h>
      15             : #include <sys/un.h>
      16             : #include <time.h>
      17             : #include <unistd.h>
      18             : 
      19             : #include "sd-messages.h"
      20             : 
      21             : #include "alloc-util.h"
      22             : #include "errno-util.h"
      23             : #include "fd-util.h"
      24             : #include "format-util.h"
      25             : #include "io-util.h"
      26             : #include "log.h"
      27             : #include "macro.h"
      28             : #include "missing.h"
      29             : #include "parse-util.h"
      30             : #include "proc-cmdline.h"
      31             : #include "process-util.h"
      32             : #include "signal-util.h"
      33             : #include "socket-util.h"
      34             : #include "stdio-util.h"
      35             : #include "string-table.h"
      36             : #include "string-util.h"
      37             : #include "syslog-util.h"
      38             : #include "terminal-util.h"
      39             : #include "time-util.h"
      40             : #include "utf8.h"
      41             : 
      42             : #define SNDBUF_SIZE (8*1024*1024)
      43             : 
      44             : static LogTarget log_target = LOG_TARGET_CONSOLE;
      45             : static int log_max_level[] = {LOG_INFO, LOG_INFO};
      46             : assert_cc(ELEMENTSOF(log_max_level) == _LOG_REALM_MAX);
      47             : static int log_facility = LOG_DAEMON;
      48             : 
      49             : static int console_fd = STDERR_FILENO;
      50             : static int syslog_fd = -1;
      51             : static int kmsg_fd = -1;
      52             : static int journal_fd = -1;
      53             : 
      54             : static bool syslog_is_stream = false;
      55             : 
      56             : static bool show_color = false;
      57             : static bool show_location = false;
      58             : 
      59             : static bool upgrade_syslog_to_journal = false;
      60             : static bool always_reopen_console = false;
      61             : static bool open_when_needed = false;
      62             : static bool prohibit_ipc = false;
      63             : 
      64             : /* Akin to glibc's __abort_msg; which is private and we hence cannot
      65             :  * use here. */
      66             : static char *log_abort_msg = NULL;
      67             : 
      68             : /* An assert to use in logging functions that does not call recursively
      69             :  * into our logging functions (since that might lead to a loop). */
      70             : #define assert_raw(expr)                                                \
      71             :         do {                                                            \
      72             :                 if (_unlikely_(!(expr))) {                              \
      73             :                         fputs(#expr "\n", stderr);                      \
      74             :                         abort();                                        \
      75             :                 }                                                       \
      76             :         } while (false)
      77             : 
      78         108 : static void log_close_console(void) {
      79         108 :         console_fd = safe_close_above_stdio(console_fd);
      80         108 : }
      81             : 
      82         299 : static int log_open_console(void) {
      83             : 
      84         299 :         if (!always_reopen_console) {
      85         299 :                 console_fd = STDERR_FILENO;
      86         299 :                 return 0;
      87             :         }
      88             : 
      89           0 :         if (console_fd < 3) {
      90             :                 int fd;
      91             : 
      92           0 :                 fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
      93           0 :                 if (fd < 0)
      94           0 :                         return fd;
      95             : 
      96           0 :                 console_fd = fd_move_above_stdio(fd);
      97             :         }
      98             : 
      99           0 :         return 0;
     100             : }
     101             : 
     102           0 : static void log_close_kmsg(void) {
     103           0 :         kmsg_fd = safe_close(kmsg_fd);
     104           0 : }
     105             : 
     106           1 : static int log_open_kmsg(void) {
     107             : 
     108           1 :         if (kmsg_fd >= 0)
     109           0 :                 return 0;
     110             : 
     111           1 :         kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
     112           1 :         if (kmsg_fd < 0)
     113           1 :                 return -errno;
     114             : 
     115           0 :         kmsg_fd = fd_move_above_stdio(kmsg_fd);
     116           0 :         return 0;
     117             : }
     118             : 
     119         405 : static void log_close_syslog(void) {
     120         405 :         syslog_fd = safe_close(syslog_fd);
     121         405 : }
     122             : 
     123         101 : static int create_log_socket(int type) {
     124             :         struct timeval tv;
     125             :         int fd;
     126             : 
     127         101 :         fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
     128         101 :         if (fd < 0)
     129           0 :                 return -errno;
     130             : 
     131         101 :         fd = fd_move_above_stdio(fd);
     132         101 :         (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
     133             : 
     134             :         /* We need a blocking fd here since we'd otherwise lose messages way too early. However, let's not hang forever
     135             :          * in the unlikely case of a deadlock. */
     136         101 :         if (getpid_cached() == 1)
     137           0 :                 timeval_store(&tv, 10 * USEC_PER_MSEC);
     138             :         else
     139         101 :                 timeval_store(&tv, 10 * USEC_PER_SEC);
     140         101 :         (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
     141             : 
     142         101 :         return fd;
     143             : }
     144             : 
     145           2 : static int log_open_syslog(void) {
     146             : 
     147             :         static const union sockaddr_union sa = {
     148             :                 .un.sun_family = AF_UNIX,
     149             :                 .un.sun_path = "/dev/log",
     150             :         };
     151             : 
     152             :         int r;
     153             : 
     154           2 :         if (syslog_fd >= 0)
     155           1 :                 return 0;
     156             : 
     157           1 :         syslog_fd = create_log_socket(SOCK_DGRAM);
     158           1 :         if (syslog_fd < 0) {
     159           0 :                 r = syslog_fd;
     160           0 :                 goto fail;
     161             :         }
     162             : 
     163           1 :         if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
     164           0 :                 safe_close(syslog_fd);
     165             : 
     166             :                 /* Some legacy syslog systems still use stream
     167             :                  * sockets. They really shouldn't. But what can we
     168             :                  * do... */
     169           0 :                 syslog_fd = create_log_socket(SOCK_STREAM);
     170           0 :                 if (syslog_fd < 0) {
     171           0 :                         r = syslog_fd;
     172           0 :                         goto fail;
     173             :                 }
     174             : 
     175           0 :                 if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
     176           0 :                         r = -errno;
     177           0 :                         goto fail;
     178             :                 }
     179             : 
     180           0 :                 syslog_is_stream = true;
     181             :         } else
     182           1 :                 syslog_is_stream = false;
     183             : 
     184           1 :         return 0;
     185             : 
     186           0 : fail:
     187           0 :         log_close_syslog();
     188           0 :         return r;
     189             : }
     190             : 
     191         302 : static void log_close_journal(void) {
     192         302 :         journal_fd = safe_close(journal_fd);
     193         302 : }
     194             : 
     195         105 : static int log_open_journal(void) {
     196             : 
     197             :         static const union sockaddr_union sa = {
     198             :                 .un.sun_family = AF_UNIX,
     199             :                 .un.sun_path = "/run/systemd/journal/socket",
     200             :         };
     201             : 
     202             :         int r;
     203             : 
     204         105 :         if (journal_fd >= 0)
     205           5 :                 return 0;
     206             : 
     207         100 :         journal_fd = create_log_socket(SOCK_DGRAM);
     208         100 :         if (journal_fd < 0) {
     209           0 :                 r = journal_fd;
     210           0 :                 goto fail;
     211             :         }
     212             : 
     213         100 :         if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
     214           0 :                 r = -errno;
     215           0 :                 goto fail;
     216             :         }
     217             : 
     218         100 :         return 0;
     219             : 
     220           0 : fail:
     221           0 :         log_close_journal();
     222           0 :         return r;
     223             : }
     224             : 
     225         407 : int log_open(void) {
     226             :         int r;
     227             : 
     228             :         /* Do not call from library code. */
     229             : 
     230             :         /* If we don't use the console we close it here, to not get
     231             :          * killed by SAK. If we don't use syslog we close it here so
     232             :          * that we are not confused by somebody deleting the socket in
     233             :          * the fs, and to make sure we don't use it if prohibit_ipc is
     234             :          * set. If we don't use /dev/kmsg we still keep it open,
     235             :          * because there is no reason to close it. */
     236             : 
     237         407 :         if (log_target == LOG_TARGET_NULL) {
     238           1 :                 log_close_journal();
     239           1 :                 log_close_syslog();
     240           1 :                 log_close_console();
     241           1 :                 return 0;
     242             :         }
     243             : 
     244         505 :         if (log_target != LOG_TARGET_AUTO ||
     245         198 :             getpid_cached() == 1 ||
     246          99 :             isatty(STDERR_FILENO) <= 0) {
     247             : 
     248         406 :                 if (!prohibit_ipc &&
     249         387 :                     IN_SET(log_target, LOG_TARGET_AUTO,
     250             :                                        LOG_TARGET_JOURNAL_OR_KMSG,
     251             :                                        LOG_TARGET_JOURNAL)) {
     252         105 :                         r = log_open_journal();
     253         105 :                         if (r >= 0) {
     254         105 :                                 log_close_syslog();
     255         105 :                                 log_close_console();
     256         105 :                                 return r;
     257             :                         }
     258             :                 }
     259             : 
     260         301 :                 if (!prohibit_ipc &&
     261         282 :                     IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
     262             :                                        LOG_TARGET_SYSLOG)) {
     263           2 :                         r = log_open_syslog();
     264           2 :                         if (r >= 0) {
     265           2 :                                 log_close_journal();
     266           2 :                                 log_close_console();
     267           2 :                                 return r;
     268             :                         }
     269             :                 }
     270             : 
     271         299 :                 if (IN_SET(log_target, LOG_TARGET_AUTO,
     272             :                                        LOG_TARGET_JOURNAL_OR_KMSG,
     273             :                                        LOG_TARGET_SYSLOG_OR_KMSG,
     274             :                                        LOG_TARGET_KMSG)) {
     275           1 :                         r = log_open_kmsg();
     276           1 :                         if (r >= 0) {
     277           0 :                                 log_close_journal();
     278           0 :                                 log_close_syslog();
     279           0 :                                 log_close_console();
     280           0 :                                 return r;
     281             :                         }
     282             :                 }
     283             :         }
     284             : 
     285         299 :         log_close_journal();
     286         299 :         log_close_syslog();
     287             : 
     288         299 :         return log_open_console();
     289             : }
     290             : 
     291         145 : void log_set_target(LogTarget target) {
     292         145 :         assert(target >= 0);
     293         145 :         assert(target < _LOG_TARGET_MAX);
     294             : 
     295         145 :         if (upgrade_syslog_to_journal) {
     296           0 :                 if (target == LOG_TARGET_SYSLOG)
     297           0 :                         target = LOG_TARGET_JOURNAL;
     298           0 :                 else if (target == LOG_TARGET_SYSLOG_OR_KMSG)
     299           0 :                         target = LOG_TARGET_JOURNAL_OR_KMSG;
     300             :         }
     301             : 
     302         145 :         log_target = target;
     303         145 : }
     304             : 
     305           0 : void log_close(void) {
     306             :         /* Do not call from library code. */
     307             : 
     308           0 :         log_close_journal();
     309           0 :         log_close_syslog();
     310           0 :         log_close_kmsg();
     311           0 :         log_close_console();
     312           0 : }
     313             : 
     314           0 : void log_forget_fds(void) {
     315             :         /* Do not call from library code. */
     316             : 
     317           0 :         console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
     318           0 : }
     319             : 
     320         309 : void log_set_max_level_realm(LogRealm realm, int level) {
     321         309 :         assert((level & LOG_PRIMASK) == level);
     322         309 :         assert(realm < ELEMENTSOF(log_max_level));
     323             : 
     324         309 :         log_max_level[realm] = level;
     325         309 : }
     326             : 
     327           0 : void log_set_facility(int facility) {
     328           0 :         log_facility = facility;
     329           0 : }
     330             : 
     331       33909 : static int write_to_console(
     332             :                 int level,
     333             :                 int error,
     334             :                 const char *file,
     335             :                 int line,
     336             :                 const char *func,
     337             :                 const char *buffer) {
     338             : 
     339             :         char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2];
     340       33909 :         struct iovec iovec[6] = {};
     341       33909 :         const char *on = NULL, *off = NULL;
     342       33909 :         size_t n = 0;
     343             : 
     344       33909 :         if (console_fd < 0)
     345           0 :                 return 0;
     346             : 
     347       33909 :         if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
     348           8 :                 xsprintf(prefix, "<%i>", level);
     349           8 :                 iovec[n++] = IOVEC_MAKE_STRING(prefix);
     350             :         }
     351             : 
     352       33909 :         if (show_color)
     353           1 :                 get_log_colors(LOG_PRI(level), &on, &off, NULL);
     354             : 
     355       33909 :         if (show_location) {
     356           0 :                 const char *lon = "", *loff = "";
     357           0 :                 if (show_color) {
     358           0 :                         lon = ANSI_HIGHLIGHT_YELLOW4;
     359           0 :                         loff = ANSI_NORMAL;
     360             :                 }
     361             : 
     362           0 :                 (void) snprintf(location, sizeof location, "%s%s:%i%s: ", lon, file, line, loff);
     363           0 :                 iovec[n++] = IOVEC_MAKE_STRING(location);
     364             :         }
     365             : 
     366       33909 :         if (on)
     367           1 :                 iovec[n++] = IOVEC_MAKE_STRING(on);
     368       33909 :         iovec[n++] = IOVEC_MAKE_STRING(buffer);
     369       33909 :         if (off)
     370           1 :                 iovec[n++] = IOVEC_MAKE_STRING(off);
     371       33909 :         iovec[n++] = IOVEC_MAKE_STRING("\n");
     372             : 
     373       33909 :         if (writev(console_fd, iovec, n) < 0) {
     374             : 
     375           0 :                 if (errno == EIO && getpid_cached() == 1) {
     376             : 
     377             :                         /* If somebody tried to kick us from our console tty (via vhangup() or suchlike), try
     378             :                          * to reconnect. */
     379             : 
     380           0 :                         log_close_console();
     381           0 :                         (void) log_open_console();
     382           0 :                         if (console_fd < 0)
     383           0 :                                 return 0;
     384             : 
     385           0 :                         if (writev(console_fd, iovec, n) < 0)
     386           0 :                                 return -errno;
     387             :                 } else
     388           0 :                         return -errno;
     389             :         }
     390             : 
     391       33909 :         return 1;
     392             : }
     393             : 
     394          16 : static int write_to_syslog(
     395             :                 int level,
     396             :                 int error,
     397             :                 const char *file,
     398             :                 int line,
     399             :                 const char *func,
     400             :                 const char *buffer) {
     401             : 
     402             :         char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
     403             :              header_time[64],
     404             :              header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
     405          16 :         struct iovec iovec[5] = {};
     406          16 :         struct msghdr msghdr = {
     407             :                 .msg_iov = iovec,
     408             :                 .msg_iovlen = ELEMENTSOF(iovec),
     409             :         };
     410             :         time_t t;
     411             :         struct tm tm;
     412             : 
     413          16 :         if (syslog_fd < 0)
     414           0 :                 return 0;
     415             : 
     416          16 :         xsprintf(header_priority, "<%i>", level);
     417             : 
     418          16 :         t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
     419          16 :         if (!localtime_r(&t, &tm))
     420           0 :                 return -EINVAL;
     421             : 
     422          16 :         if (strftime(header_time, sizeof(header_time), "%h %e %T ", &tm) <= 0)
     423           0 :                 return -EINVAL;
     424             : 
     425          16 :         xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
     426             : 
     427          16 :         iovec[0] = IOVEC_MAKE_STRING(header_priority);
     428          16 :         iovec[1] = IOVEC_MAKE_STRING(header_time);
     429          16 :         iovec[2] = IOVEC_MAKE_STRING(program_invocation_short_name);
     430          16 :         iovec[3] = IOVEC_MAKE_STRING(header_pid);
     431          16 :         iovec[4] = IOVEC_MAKE_STRING(buffer);
     432             : 
     433             :         /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
     434          16 :         if (syslog_is_stream)
     435           0 :                 iovec[4].iov_len++;
     436             : 
     437           0 :         for (;;) {
     438             :                 ssize_t n;
     439             : 
     440          16 :                 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
     441          16 :                 if (n < 0)
     442           0 :                         return -errno;
     443             : 
     444          16 :                 if (!syslog_is_stream ||
     445           0 :                     (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
     446             :                         break;
     447             : 
     448           0 :                 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
     449             :         }
     450             : 
     451          16 :         return 1;
     452             : }
     453             : 
     454           8 : static int write_to_kmsg(
     455             :                 int level,
     456             :                 int error,
     457             :                 const char *file,
     458             :                 int line,
     459             :                 const char *func,
     460             :                 const char *buffer) {
     461             : 
     462             :         char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
     463             :              header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
     464           8 :         struct iovec iovec[5] = {};
     465             : 
     466           8 :         if (kmsg_fd < 0)
     467           8 :                 return 0;
     468             : 
     469           0 :         xsprintf(header_priority, "<%i>", level);
     470           0 :         xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
     471             : 
     472           0 :         iovec[0] = IOVEC_MAKE_STRING(header_priority);
     473           0 :         iovec[1] = IOVEC_MAKE_STRING(program_invocation_short_name);
     474           0 :         iovec[2] = IOVEC_MAKE_STRING(header_pid);
     475           0 :         iovec[3] = IOVEC_MAKE_STRING(buffer);
     476           0 :         iovec[4] = IOVEC_MAKE_STRING("\n");
     477             : 
     478           0 :         if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
     479           0 :                 return -errno;
     480             : 
     481           0 :         return 1;
     482             : }
     483             : 
     484          80 : static int log_do_header(
     485             :                 char *header,
     486             :                 size_t size,
     487             :                 int level,
     488             :                 int error,
     489             :                 const char *file, int line, const char *func,
     490             :                 const char *object_field, const char *object,
     491             :                 const char *extra_field, const char *extra) {
     492             :         int r;
     493             : 
     494          80 :         error = IS_SYNTHETIC_ERRNO(error) ? 0 : ERRNO_VALUE(error);
     495             : 
     496         960 :         r = snprintf(header, size,
     497             :                      "PRIORITY=%i\n"
     498             :                      "SYSLOG_FACILITY=%i\n"
     499             :                      "%s%.256s%s"        /* CODE_FILE */
     500             :                      "%s%.*i%s"          /* CODE_LINE */
     501             :                      "%s%.256s%s"        /* CODE_FUNC */
     502             :                      "%s%.*i%s"          /* ERRNO */
     503             :                      "%s%.256s%s"        /* object */
     504             :                      "%s%.256s%s"        /* extra */
     505             :                      "SYSLOG_IDENTIFIER=%.256s\n",
     506             :                      LOG_PRI(level),
     507          80 :                      LOG_FAC(level),
     508          80 :                      isempty(file) ? "" : "CODE_FILE=",
     509          80 :                      isempty(file) ? "" : file,
     510          80 :                      isempty(file) ? "" : "\n",
     511             :                      line ? "CODE_LINE=" : "",
     512             :                      line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
     513             :                      line ? "\n" : "",
     514          80 :                      isempty(func) ? "" : "CODE_FUNC=",
     515          80 :                      isempty(func) ? "" : func,
     516          80 :                      isempty(func) ? "" : "\n",
     517             :                      error ? "ERRNO=" : "",
     518             :                      error ? 1 : 0, error,
     519             :                      error ? "\n" : "",
     520          80 :                      isempty(object) ? "" : object_field,
     521          80 :                      isempty(object) ? "" : object,
     522          80 :                      isempty(object) ? "" : "\n",
     523          80 :                      isempty(extra) ? "" : extra_field,
     524          80 :                      isempty(extra) ? "" : extra,
     525          80 :                      isempty(extra) ? "" : "\n",
     526             :                      program_invocation_short_name);
     527          80 :         assert_raw((size_t) r < size);
     528             : 
     529          80 :         return 0;
     530             : }
     531             : 
     532          59 : static int write_to_journal(
     533             :                 int level,
     534             :                 int error,
     535             :                 const char *file,
     536             :                 int line,
     537             :                 const char *func,
     538             :                 const char *object_field,
     539             :                 const char *object,
     540             :                 const char *extra_field,
     541             :                 const char *extra,
     542             :                 const char *buffer) {
     543             : 
     544             :         char header[LINE_MAX];
     545          59 :         struct iovec iovec[4] = {};
     546          59 :         struct msghdr mh = {};
     547             : 
     548          59 :         if (journal_fd < 0)
     549           0 :                 return 0;
     550             : 
     551          59 :         log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
     552             : 
     553          59 :         iovec[0] = IOVEC_MAKE_STRING(header);
     554          59 :         iovec[1] = IOVEC_MAKE_STRING("MESSAGE=");
     555          59 :         iovec[2] = IOVEC_MAKE_STRING(buffer);
     556          59 :         iovec[3] = IOVEC_MAKE_STRING("\n");
     557             : 
     558          59 :         mh.msg_iov = iovec;
     559          59 :         mh.msg_iovlen = ELEMENTSOF(iovec);
     560             : 
     561          59 :         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
     562           0 :                 return -errno;
     563             : 
     564          59 :         return 1;
     565             : }
     566             : 
     567       33828 : int log_dispatch_internal(
     568             :                 int level,
     569             :                 int error,
     570             :                 const char *file,
     571             :                 int line,
     572             :                 const char *func,
     573             :                 const char *object_field,
     574             :                 const char *object,
     575             :                 const char *extra_field,
     576             :                 const char *extra,
     577             :                 char *buffer) {
     578             : 
     579       33828 :         assert_raw(buffer);
     580             : 
     581       33828 :         if (log_target == LOG_TARGET_NULL)
     582           2 :                 return -ERRNO_VALUE(error);
     583             : 
     584             :         /* Patch in LOG_DAEMON facility if necessary */
     585       33826 :         if ((level & LOG_FACMASK) == 0)
     586       33621 :                 level |= log_facility;
     587             : 
     588       33826 :         if (open_when_needed)
     589           0 :                 (void) log_open();
     590             : 
     591             :         do {
     592             :                 char *e;
     593       34126 :                 int k = 0;
     594             : 
     595       34126 :                 buffer += strspn(buffer, NEWLINE);
     596             : 
     597       34126 :                 if (buffer[0] == 0)
     598         142 :                         break;
     599             : 
     600       33984 :                 if ((e = strpbrk(buffer, NEWLINE)))
     601         300 :                         *(e++) = 0;
     602             : 
     603       33984 :                 if (IN_SET(log_target, LOG_TARGET_AUTO,
     604             :                                        LOG_TARGET_JOURNAL_OR_KMSG,
     605             :                                        LOG_TARGET_JOURNAL)) {
     606             : 
     607          59 :                         k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
     608          59 :                         if (k < 0 && k != -EAGAIN)
     609           0 :                                 log_close_journal();
     610             :                 }
     611             : 
     612       33984 :                 if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
     613             :                                        LOG_TARGET_SYSLOG)) {
     614             : 
     615          16 :                         k = write_to_syslog(level, error, file, line, func, buffer);
     616          16 :                         if (k < 0 && k != -EAGAIN)
     617           0 :                                 log_close_syslog();
     618             :                 }
     619             : 
     620       33984 :                 if (k <= 0 &&
     621       33909 :                     IN_SET(log_target, LOG_TARGET_AUTO,
     622             :                                        LOG_TARGET_SYSLOG_OR_KMSG,
     623             :                                        LOG_TARGET_JOURNAL_OR_KMSG,
     624             :                                        LOG_TARGET_KMSG)) {
     625             : 
     626           8 :                         if (k < 0)
     627           0 :                                 log_open_kmsg();
     628             : 
     629           8 :                         k = write_to_kmsg(level, error, file, line, func, buffer);
     630           8 :                         if (k < 0) {
     631           0 :                                 log_close_kmsg();
     632           0 :                                 (void) log_open_console();
     633             :                         }
     634             :                 }
     635             : 
     636       33984 :                 if (k <= 0)
     637       33909 :                         (void) write_to_console(level, error, file, line, func, buffer);
     638             : 
     639       33984 :                 buffer = e;
     640       33984 :         } while (buffer);
     641             : 
     642       33826 :         if (open_when_needed)
     643           0 :                 log_close();
     644             : 
     645       33826 :         return -ERRNO_VALUE(error);
     646             : }
     647             : 
     648           0 : int log_dump_internal(
     649             :                 int level,
     650             :                 int error,
     651             :                 const char *file,
     652             :                 int line,
     653             :                 const char *func,
     654             :                 char *buffer) {
     655             : 
     656           0 :         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
     657           0 :         PROTECT_ERRNO;
     658             : 
     659             :         /* This modifies the buffer... */
     660             : 
     661           0 :         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
     662           0 :                 return -ERRNO_VALUE(error);
     663             : 
     664           0 :         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
     665             : }
     666             : 
     667       32756 : int log_internalv_realm(
     668             :                 int level,
     669             :                 int error,
     670             :                 const char *file,
     671             :                 int line,
     672             :                 const char *func,
     673             :                 const char *format,
     674             :                 va_list ap) {
     675             : 
     676       32756 :         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
     677             :         char buffer[LINE_MAX];
     678       32756 :         PROTECT_ERRNO;
     679             : 
     680       32756 :         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
     681           0 :                 return -ERRNO_VALUE(error);
     682             : 
     683             :         /* Make sure that %m maps to the specified error (or "Success"). */
     684       32756 :         errno = ERRNO_VALUE(error);
     685             : 
     686       32756 :         (void) vsnprintf(buffer, sizeof buffer, format, ap);
     687             : 
     688       32756 :         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
     689             : }
     690             : 
     691       32756 : int log_internal_realm(
     692             :                 int level,
     693             :                 int error,
     694             :                 const char *file,
     695             :                 int line,
     696             :                 const char *func,
     697             :                 const char *format, ...) {
     698             : 
     699             :         va_list ap;
     700             :         int r;
     701             : 
     702       32756 :         va_start(ap, format);
     703       32756 :         r = log_internalv_realm(level, error, file, line, func, format, ap);
     704       32756 :         va_end(ap);
     705             : 
     706       32756 :         return r;
     707             : }
     708             : 
     709        2362 : int log_object_internalv(
     710             :                 int level,
     711             :                 int error,
     712             :                 const char *file,
     713             :                 int line,
     714             :                 const char *func,
     715             :                 const char *object_field,
     716             :                 const char *object,
     717             :                 const char *extra_field,
     718             :                 const char *extra,
     719             :                 const char *format,
     720             :                 va_list ap) {
     721             : 
     722        2362 :         PROTECT_ERRNO;
     723             :         char *buffer, *b;
     724             : 
     725        2362 :         if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
     726        1655 :                 return -ERRNO_VALUE(error);
     727             : 
     728             :         /* Make sure that %m maps to the specified error (or "Success"). */
     729         707 :         errno = ERRNO_VALUE(error);
     730             : 
     731             :         /* Prepend the object name before the message */
     732         707 :         if (object) {
     733             :                 size_t n;
     734             : 
     735         707 :                 n = strlen(object);
     736         707 :                 buffer = newa(char, n + 2 + LINE_MAX);
     737         707 :                 b = stpcpy(stpcpy(buffer, object), ": ");
     738             :         } else
     739           0 :                 b = buffer = newa(char, LINE_MAX);
     740             : 
     741         707 :         (void) vsnprintf(b, LINE_MAX, format, ap);
     742             : 
     743         707 :         return log_dispatch_internal(level, error, file, line, func,
     744             :                                      object_field, object, extra_field, extra, buffer);
     745             : }
     746             : 
     747        2362 : int log_object_internal(
     748             :                 int level,
     749             :                 int error,
     750             :                 const char *file,
     751             :                 int line,
     752             :                 const char *func,
     753             :                 const char *object_field,
     754             :                 const char *object,
     755             :                 const char *extra_field,
     756             :                 const char *extra,
     757             :                 const char *format, ...) {
     758             : 
     759             :         va_list ap;
     760             :         int r;
     761             : 
     762        2362 :         va_start(ap, format);
     763        2362 :         r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
     764        2362 :         va_end(ap);
     765             : 
     766        2362 :         return r;
     767             : }
     768             : 
     769         208 : static void log_assert(
     770             :                 int level,
     771             :                 const char *text,
     772             :                 const char *file,
     773             :                 int line,
     774             :                 const char *func,
     775             :                 const char *format) {
     776             : 
     777             :         static char buffer[LINE_MAX];
     778         208 :         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
     779             : 
     780         208 :         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
     781          48 :                 return;
     782             : 
     783             :         DISABLE_WARNING_FORMAT_NONLITERAL;
     784         160 :         (void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
     785             :         REENABLE_WARNING;
     786             : 
     787         160 :         log_abort_msg = buffer;
     788             : 
     789         160 :         log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
     790             : }
     791             : 
     792           0 : _noreturn_ void log_assert_failed_realm(
     793             :                 LogRealm realm,
     794             :                 const char *text,
     795             :                 const char *file,
     796             :                 int line,
     797             :                 const char *func) {
     798           0 :         (void) log_open();
     799           0 :         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
     800             :                    "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
     801           0 :         abort();
     802             : }
     803             : 
     804           0 : _noreturn_ void log_assert_failed_unreachable_realm(
     805             :                 LogRealm realm,
     806             :                 const char *text,
     807             :                 const char *file,
     808             :                 int line,
     809             :                 const char *func) {
     810           0 :         (void) log_open();
     811           0 :         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
     812             :                    "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
     813           0 :         abort();
     814             : }
     815             : 
     816         208 : void log_assert_failed_return_realm(
     817             :                 LogRealm realm,
     818             :                 const char *text,
     819             :                 const char *file,
     820             :                 int line,
     821             :                 const char *func) {
     822         208 :         PROTECT_ERRNO;
     823         208 :         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func,
     824             :                    "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
     825         208 : }
     826             : 
     827           0 : int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
     828           0 :         return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
     829             :                                   ENOMEM, file, line, func, "Out of memory.");
     830             : }
     831             : 
     832          21 : int log_format_iovec(
     833             :                 struct iovec *iovec,
     834             :                 size_t iovec_len,
     835             :                 size_t *n,
     836             :                 bool newline_separator,
     837             :                 int error,
     838             :                 const char *format,
     839             :                 va_list ap) {
     840             : 
     841             :         static const char nl = '\n';
     842             : 
     843          93 :         while (format && *n + 1 < iovec_len) {
     844             :                 va_list aq;
     845             :                 char *m;
     846             :                 int r;
     847             : 
     848             :                 /* We need to copy the va_list structure,
     849             :                  * since vasprintf() leaves it afterwards at
     850             :                  * an undefined location */
     851             : 
     852          72 :                 errno = ERRNO_VALUE(error);
     853             : 
     854          72 :                 va_copy(aq, ap);
     855          72 :                 r = vasprintf(&m, format, aq);
     856          72 :                 va_end(aq);
     857          72 :                 if (r < 0)
     858           0 :                         return -EINVAL;
     859             : 
     860             :                 /* Now, jump enough ahead, so that we point to
     861             :                  * the next format string */
     862         168 :                 VA_FORMAT_ADVANCE(format, ap);
     863             : 
     864          72 :                 iovec[(*n)++] = IOVEC_MAKE_STRING(m);
     865             : 
     866          72 :                 if (newline_separator) {
     867          72 :                         iovec[*n] = IOVEC_MAKE((char *)&nl, 1);
     868          72 :                         (*n)++;
     869             :                 }
     870             : 
     871          72 :                 format = va_arg(ap, char *);
     872             :         }
     873          21 :         return 0;
     874             : }
     875             : 
     876         236 : int log_struct_internal(
     877             :                 int level,
     878             :                 int error,
     879             :                 const char *file,
     880             :                 int line,
     881             :                 const char *func,
     882             :                 const char *format, ...) {
     883             : 
     884         236 :         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
     885             :         char buf[LINE_MAX];
     886         236 :         bool found = false;
     887         236 :         PROTECT_ERRNO;
     888             :         va_list ap;
     889             : 
     890         236 :         if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
     891         230 :             log_target == LOG_TARGET_NULL)
     892          10 :                 return -ERRNO_VALUE(error);
     893             : 
     894         226 :         if ((level & LOG_FACMASK) == 0)
     895         226 :                 level |= log_facility;
     896             : 
     897         226 :         if (IN_SET(log_target,
     898             :                    LOG_TARGET_AUTO,
     899             :                    LOG_TARGET_JOURNAL_OR_KMSG,
     900             :                    LOG_TARGET_JOURNAL)) {
     901             : 
     902          21 :                 if (open_when_needed)
     903           0 :                         log_open_journal();
     904             : 
     905          21 :                 if (journal_fd >= 0) {
     906             :                         char header[LINE_MAX];
     907          21 :                         struct iovec iovec[17] = {};
     908          21 :                         size_t n = 0, i;
     909             :                         int r;
     910          21 :                         struct msghdr mh = {
     911             :                                 .msg_iov = iovec,
     912             :                         };
     913          21 :                         bool fallback = false;
     914             : 
     915             :                         /* If the journal is available do structured logging.
     916             :                          * Do not report the errno if it is synthetic. */
     917          21 :                         log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
     918          21 :                         iovec[n++] = IOVEC_MAKE_STRING(header);
     919             : 
     920          21 :                         va_start(ap, format);
     921          21 :                         r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
     922          21 :                         if (r < 0)
     923           0 :                                 fallback = true;
     924             :                         else {
     925          21 :                                 mh.msg_iovlen = n;
     926          21 :                                 (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
     927             :                         }
     928             : 
     929          21 :                         va_end(ap);
     930          93 :                         for (i = 1; i < n; i += 2)
     931          72 :                                 free(iovec[i].iov_base);
     932             : 
     933          21 :                         if (!fallback) {
     934          21 :                                 if (open_when_needed)
     935           0 :                                         log_close();
     936             : 
     937          21 :                                 return -ERRNO_VALUE(error);
     938             :                         }
     939             :                 }
     940             :         }
     941             : 
     942             :         /* Fallback if journal logging is not available or didn't work. */
     943             : 
     944         205 :         va_start(ap, format);
     945         711 :         while (format) {
     946             :                 va_list aq;
     947             : 
     948         711 :                 errno = ERRNO_VALUE(error);
     949             : 
     950         711 :                 va_copy(aq, ap);
     951         711 :                 (void) vsnprintf(buf, sizeof buf, format, aq);
     952         711 :                 va_end(aq);
     953             : 
     954         711 :                 if (startswith(buf, "MESSAGE=")) {
     955         205 :                         found = true;
     956         205 :                         break;
     957             :                 }
     958             : 
     959         842 :                 VA_FORMAT_ADVANCE(format, ap);
     960             : 
     961         506 :                 format = va_arg(ap, char *);
     962             :         }
     963         205 :         va_end(ap);
     964             : 
     965         205 :         if (!found) {
     966           0 :                 if (open_when_needed)
     967           0 :                         log_close();
     968             : 
     969           0 :                 return -ERRNO_VALUE(error);
     970             :         }
     971             : 
     972         205 :         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
     973             : }
     974             : 
     975           0 : int log_struct_iovec_internal(
     976             :                 int level,
     977             :                 int error,
     978             :                 const char *file,
     979             :                 int line,
     980             :                 const char *func,
     981             :                 const struct iovec input_iovec[],
     982             :                 size_t n_input_iovec) {
     983             : 
     984           0 :         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
     985           0 :         PROTECT_ERRNO;
     986             :         size_t i;
     987             :         char *m;
     988             : 
     989           0 :         if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
     990           0 :             log_target == LOG_TARGET_NULL)
     991           0 :                 return -ERRNO_VALUE(error);
     992             : 
     993           0 :         if ((level & LOG_FACMASK) == 0)
     994           0 :                 level |= log_facility;
     995             : 
     996           0 :         if (IN_SET(log_target, LOG_TARGET_AUTO,
     997             :                                LOG_TARGET_JOURNAL_OR_KMSG,
     998           0 :                                LOG_TARGET_JOURNAL) &&
     999           0 :             journal_fd >= 0) {
    1000             : 
    1001           0 :                 struct iovec iovec[1 + n_input_iovec*2];
    1002             :                 char header[LINE_MAX];
    1003           0 :                 struct msghdr mh = {
    1004             :                         .msg_iov = iovec,
    1005           0 :                         .msg_iovlen = 1 + n_input_iovec*2,
    1006             :                 };
    1007             : 
    1008           0 :                 log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
    1009           0 :                 iovec[0] = IOVEC_MAKE_STRING(header);
    1010             : 
    1011           0 :                 for (i = 0; i < n_input_iovec; i++) {
    1012           0 :                         iovec[1+i*2] = input_iovec[i];
    1013           0 :                         iovec[1+i*2+1] = IOVEC_MAKE_STRING("\n");
    1014             :                 }
    1015             : 
    1016           0 :                 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) >= 0)
    1017           0 :                         return -ERRNO_VALUE(error);
    1018             :         }
    1019             : 
    1020           0 :         for (i = 0; i < n_input_iovec; i++)
    1021           0 :                 if (memory_startswith(input_iovec[i].iov_base, input_iovec[i].iov_len, "MESSAGE="))
    1022           0 :                         break;
    1023             : 
    1024           0 :         if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
    1025           0 :                 return -ERRNO_VALUE(error);
    1026             : 
    1027           0 :         m = strndupa(input_iovec[i].iov_base + STRLEN("MESSAGE="),
    1028             :                      input_iovec[i].iov_len - STRLEN("MESSAGE="));
    1029             : 
    1030           0 :         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
    1031             : }
    1032             : 
    1033          19 : int log_set_target_from_string(const char *e) {
    1034             :         LogTarget t;
    1035             : 
    1036          19 :         t = log_target_from_string(e);
    1037          19 :         if (t < 0)
    1038           0 :                 return -EINVAL;
    1039             : 
    1040          19 :         log_set_target(t);
    1041          19 :         return 0;
    1042             : }
    1043             : 
    1044         193 : int log_set_max_level_from_string_realm(LogRealm realm, const char *e) {
    1045             :         int t;
    1046             : 
    1047         193 :         t = log_level_from_string(e);
    1048         193 :         if (t < 0)
    1049           0 :                 return -EINVAL;
    1050             : 
    1051         193 :         log_set_max_level_realm(realm, t);
    1052         193 :         return 0;
    1053             : }
    1054             : 
    1055        2412 : static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
    1056             : 
    1057             :         /*
    1058             :          * The systemd.log_xyz= settings are parsed by all tools, and
    1059             :          * so is "debug".
    1060             :          *
    1061             :          * However, "quiet" is only parsed by PID 1, and only turns of
    1062             :          * status output to /dev/console, but does not alter the log
    1063             :          * level.
    1064             :          */
    1065             : 
    1066        2412 :         if (streq(key, "debug") && !value)
    1067           0 :                 log_set_max_level(LOG_DEBUG);
    1068             : 
    1069        2412 :         else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
    1070             : 
    1071           0 :                 if (proc_cmdline_value_missing(key, value))
    1072           0 :                         return 0;
    1073             : 
    1074           0 :                 if (log_set_target_from_string(value) < 0)
    1075           0 :                         log_warning("Failed to parse log target '%s'. Ignoring.", value);
    1076             : 
    1077        2412 :         } else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
    1078             : 
    1079           0 :                 if (proc_cmdline_value_missing(key, value))
    1080           0 :                         return 0;
    1081             : 
    1082           0 :                 if (log_set_max_level_from_string(value) < 0)
    1083           0 :                         log_warning("Failed to parse log level '%s'. Ignoring.", value);
    1084             : 
    1085        2412 :         } else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
    1086             : 
    1087           0 :                 if (log_show_color_from_string(value ?: "1") < 0)
    1088           0 :                         log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
    1089             : 
    1090        2412 :         } else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
    1091             : 
    1092           0 :                 if (log_show_location_from_string(value ?: "1") < 0)
    1093           0 :                         log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
    1094             :         }
    1095             : 
    1096        2412 :         return 0;
    1097             : }
    1098             : 
    1099         402 : void log_parse_environment_realm(LogRealm realm) {
    1100             :         /* Do not call from library code. */
    1101             : 
    1102             :         const char *e;
    1103             : 
    1104         402 :         if (getpid_cached() == 1 || get_ctty_devnr(0, NULL) < 0)
    1105             :                 /* Only try to read the command line in daemons. We assume that anything that has a
    1106             :                  * controlling tty is user stuff. For PID1 we do a special check in case it hasn't
    1107             :                  * closed the console yet. */
    1108         402 :                 (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
    1109             : 
    1110         402 :         e = getenv("SYSTEMD_LOG_TARGET");
    1111         402 :         if (e && log_set_target_from_string(e) < 0)
    1112           0 :                 log_warning("Failed to parse log target '%s'. Ignoring.", e);
    1113             : 
    1114         402 :         e = getenv("SYSTEMD_LOG_LEVEL");
    1115         402 :         if (e && log_set_max_level_from_string_realm(realm, e) < 0)
    1116           0 :                 log_warning("Failed to parse log level '%s'. Ignoring.", e);
    1117             : 
    1118         402 :         e = getenv("SYSTEMD_LOG_COLOR");
    1119         402 :         if (e && log_show_color_from_string(e) < 0)
    1120           0 :                 log_warning("Failed to parse log color '%s'. Ignoring.", e);
    1121             : 
    1122         402 :         e = getenv("SYSTEMD_LOG_LOCATION");
    1123         402 :         if (e && log_show_location_from_string(e) < 0)
    1124           0 :                 log_warning("Failed to parse log location '%s'. Ignoring.", e);
    1125         402 : }
    1126             : 
    1127           0 : LogTarget log_get_target(void) {
    1128           0 :         return log_target;
    1129             : }
    1130             : 
    1131       97235 : int log_get_max_level_realm(LogRealm realm) {
    1132       97235 :         return log_max_level[realm];
    1133             : }
    1134             : 
    1135         112 : void log_show_color(bool b) {
    1136         112 :         show_color = b;
    1137         112 : }
    1138             : 
    1139          46 : bool log_get_show_color(void) {
    1140          46 :         return show_color;
    1141             : }
    1142             : 
    1143           0 : void log_show_location(bool b) {
    1144           0 :         show_location = b;
    1145           0 : }
    1146             : 
    1147           0 : bool log_get_show_location(void) {
    1148           0 :         return show_location;
    1149             : }
    1150             : 
    1151           0 : int log_show_color_from_string(const char *e) {
    1152             :         int t;
    1153             : 
    1154           0 :         t = parse_boolean(e);
    1155           0 :         if (t < 0)
    1156           0 :                 return t;
    1157             : 
    1158           0 :         log_show_color(t);
    1159           0 :         return 0;
    1160             : }
    1161             : 
    1162           0 : int log_show_location_from_string(const char *e) {
    1163             :         int t;
    1164             : 
    1165           0 :         t = parse_boolean(e);
    1166           0 :         if (t < 0)
    1167           0 :                 return t;
    1168             : 
    1169           0 :         log_show_location(t);
    1170           0 :         return 0;
    1171             : }
    1172             : 
    1173          50 : bool log_on_console(void) {
    1174          50 :         if (IN_SET(log_target, LOG_TARGET_CONSOLE,
    1175             :                                LOG_TARGET_CONSOLE_PREFIXED))
    1176          50 :                 return true;
    1177             : 
    1178           0 :         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
    1179             : }
    1180             : 
    1181             : static const char *const log_target_table[_LOG_TARGET_MAX] = {
    1182             :         [LOG_TARGET_CONSOLE] = "console",
    1183             :         [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
    1184             :         [LOG_TARGET_KMSG] = "kmsg",
    1185             :         [LOG_TARGET_JOURNAL] = "journal",
    1186             :         [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
    1187             :         [LOG_TARGET_SYSLOG] = "syslog",
    1188             :         [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
    1189             :         [LOG_TARGET_AUTO] = "auto",
    1190             :         [LOG_TARGET_NULL] = "null",
    1191             : };
    1192             : 
    1193          41 : DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
    1194             : 
    1195           0 : void log_received_signal(int level, const struct signalfd_siginfo *si) {
    1196           0 :         assert(si);
    1197             : 
    1198           0 :         if (pid_is_valid(si->ssi_pid)) {
    1199           0 :                 _cleanup_free_ char *p = NULL;
    1200             : 
    1201           0 :                 (void) get_process_comm(si->ssi_pid, &p);
    1202             : 
    1203           0 :                 log_full(level,
    1204             :                          "Received SIG%s from PID %"PRIu32" (%s).",
    1205             :                          signal_to_string(si->ssi_signo),
    1206             :                          si->ssi_pid, strna(p));
    1207             :         } else
    1208           0 :                 log_full(level,
    1209             :                          "Received SIG%s.",
    1210             :                          signal_to_string(si->ssi_signo));
    1211           0 : }
    1212             : 
    1213         175 : int log_syntax_internal(
    1214             :                 const char *unit,
    1215             :                 int level,
    1216             :                 const char *config_file,
    1217             :                 unsigned config_line,
    1218             :                 int error,
    1219             :                 const char *file,
    1220             :                 int line,
    1221             :                 const char *func,
    1222             :                 const char *format, ...) {
    1223             : 
    1224         175 :         PROTECT_ERRNO;
    1225             :         char buffer[LINE_MAX];
    1226             :         va_list ap;
    1227         175 :         const char *unit_fmt = NULL;
    1228             : 
    1229         175 :         if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]) ||
    1230         175 :             log_target == LOG_TARGET_NULL)
    1231           3 :                 return -ERRNO_VALUE(error);
    1232             : 
    1233         172 :         errno = ERRNO_VALUE(error);
    1234             : 
    1235         172 :         va_start(ap, format);
    1236         172 :         (void) vsnprintf(buffer, sizeof buffer, format, ap);
    1237         172 :         va_end(ap);
    1238             : 
    1239         172 :         if (unit)
    1240         115 :                 unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
    1241             : 
    1242         172 :         if (config_file) {
    1243         172 :                 if (config_line > 0)
    1244         168 :                         return log_struct_internal(
    1245             :                                         LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
    1246             :                                         error,
    1247             :                                         file, line, func,
    1248             :                                         "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
    1249             :                                         "CONFIG_FILE=%s", config_file,
    1250             :                                         "CONFIG_LINE=%u", config_line,
    1251             :                                         LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
    1252             :                                         unit_fmt, unit,
    1253             :                                         NULL);
    1254             :                 else
    1255           4 :                         return log_struct_internal(
    1256             :                                         LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
    1257             :                                         error,
    1258             :                                         file, line, func,
    1259             :                                         "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
    1260             :                                         "CONFIG_FILE=%s", config_file,
    1261             :                                         LOG_MESSAGE("%s: %s", config_file, buffer),
    1262             :                                         unit_fmt, unit,
    1263             :                                         NULL);
    1264           0 :         } else if (unit)
    1265           0 :                 return log_struct_internal(
    1266             :                                 LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
    1267             :                                 error,
    1268             :                                 file, line, func,
    1269             :                                 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
    1270             :                                 LOG_MESSAGE("%s: %s", unit, buffer),
    1271             :                                 unit_fmt, unit,
    1272             :                                 NULL);
    1273             :         else
    1274           0 :                 return log_struct_internal(
    1275             :                                 LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
    1276             :                                 error,
    1277             :                                 file, line, func,
    1278             :                                 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
    1279             :                                 LOG_MESSAGE("%s", buffer),
    1280             :                                 NULL);
    1281             : }
    1282             : 
    1283           1 : int log_syntax_invalid_utf8_internal(
    1284             :                 const char *unit,
    1285             :                 int level,
    1286             :                 const char *config_file,
    1287             :                 unsigned config_line,
    1288             :                 const char *file,
    1289             :                 int line,
    1290             :                 const char *func,
    1291             :                 const char *rvalue) {
    1292             : 
    1293           2 :         _cleanup_free_ char *p = NULL;
    1294             : 
    1295           1 :         if (rvalue)
    1296           1 :                 p = utf8_escape_invalid(rvalue);
    1297             : 
    1298           1 :         log_syntax_internal(unit, level, config_file, config_line, 0, file, line, func,
    1299             :                             "String is not UTF-8 clean, ignoring assignment: %s", strna(p));
    1300             : 
    1301           1 :         return -EINVAL;
    1302             : }
    1303             : 
    1304           0 : void log_set_upgrade_syslog_to_journal(bool b) {
    1305           0 :         upgrade_syslog_to_journal = b;
    1306             : 
    1307             :         /* Make the change effective immediately */
    1308           0 :         if (b) {
    1309           0 :                 if (log_target == LOG_TARGET_SYSLOG)
    1310           0 :                         log_target = LOG_TARGET_JOURNAL;
    1311           0 :                 else if (log_target == LOG_TARGET_SYSLOG_OR_KMSG)
    1312           0 :                         log_target = LOG_TARGET_JOURNAL_OR_KMSG;
    1313             :         }
    1314           0 : }
    1315             : 
    1316           0 : void log_set_always_reopen_console(bool b) {
    1317           0 :         always_reopen_console = b;
    1318           0 : }
    1319             : 
    1320           0 : void log_set_open_when_needed(bool b) {
    1321           0 :         open_when_needed = b;
    1322           0 : }
    1323             : 
    1324          19 : void log_set_prohibit_ipc(bool b) {
    1325          19 :         prohibit_ipc = b;
    1326          19 : }
    1327             : 
    1328           0 : int log_emergency_level(void) {
    1329             :         /* Returns the log level to use for log_emergency() logging. We use LOG_EMERG only when we are PID 1, as only
    1330             :          * then the system of the whole system is obviously affected. */
    1331             : 
    1332           0 :         return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR;
    1333             : }
    1334             : 
    1335           0 : int log_dup_console(void) {
    1336             :         int copy;
    1337             : 
    1338             :         /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful
    1339             :          * whenever we want to continue logging through the original fd, but want to rearrange stderr. */
    1340             : 
    1341           0 :         if (console_fd >= 3)
    1342           0 :                 return 0;
    1343             : 
    1344           0 :         copy = fcntl(console_fd, F_DUPFD_CLOEXEC, 3);
    1345           0 :         if (copy < 0)
    1346           0 :                 return -errno;
    1347             : 
    1348           0 :         console_fd = copy;
    1349           0 :         return 0;
    1350             : }
    1351             : 
    1352         109 : void log_setup_service(void) {
    1353             :         /* Sets up logging the way it is most appropriate for running a program as a service. Note that using this
    1354             :          * doesn't make the binary unsuitable for invocation on the command line, as log output will still go to the
    1355             :          * terminal if invoked interactively. */
    1356             : 
    1357         109 :         log_set_target(LOG_TARGET_AUTO);
    1358         109 :         log_parse_environment();
    1359         109 :         (void) log_open();
    1360         109 : }

Generated by: LCOV version 1.14