LCOV - code coverage report
Current view: top level - basic - log.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 358 575 62.3 %
Date: 2019-08-23 13:36:53 Functions: 40 59 67.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 214 450 47.6 %

           Branch data     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                 :        432 : static void log_close_console(void) {
      79                 :        432 :         console_fd = safe_close_above_stdio(console_fd);
      80                 :        432 : }
      81                 :            : 
      82                 :       1194 : static int log_open_console(void) {
      83                 :            : 
      84         [ +  - ]:       1194 :         if (!always_reopen_console) {
      85                 :       1194 :                 console_fd = STDERR_FILENO;
      86                 :       1194 :                 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                 :          4 : static int log_open_kmsg(void) {
     107                 :            : 
     108         [ -  + ]:          4 :         if (kmsg_fd >= 0)
     109                 :          0 :                 return 0;
     110                 :            : 
     111                 :          4 :         kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
     112         [ +  - ]:          4 :         if (kmsg_fd < 0)
     113                 :          4 :                 return -errno;
     114                 :            : 
     115                 :          0 :         kmsg_fd = fd_move_above_stdio(kmsg_fd);
     116                 :          0 :         return 0;
     117                 :            : }
     118                 :            : 
     119                 :       1618 : static void log_close_syslog(void) {
     120                 :       1618 :         syslog_fd = safe_close(syslog_fd);
     121                 :       1618 : }
     122                 :            : 
     123                 :        404 : static int create_log_socket(int type) {
     124                 :            :         struct timeval tv;
     125                 :            :         int fd;
     126                 :            : 
     127                 :        404 :         fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
     128         [ -  + ]:        404 :         if (fd < 0)
     129                 :          0 :                 return -errno;
     130                 :            : 
     131                 :        404 :         fd = fd_move_above_stdio(fd);
     132                 :        404 :         (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         [ -  + ]:        404 :         if (getpid_cached() == 1)
     137                 :          0 :                 timeval_store(&tv, 10 * USEC_PER_MSEC);
     138                 :            :         else
     139                 :        404 :                 timeval_store(&tv, 10 * USEC_PER_SEC);
     140                 :        404 :         (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
     141                 :            : 
     142                 :        404 :         return fd;
     143                 :            : }
     144                 :            : 
     145                 :          8 : 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         [ +  + ]:          8 :         if (syslog_fd >= 0)
     155                 :          4 :                 return 0;
     156                 :            : 
     157                 :          4 :         syslog_fd = create_log_socket(SOCK_DGRAM);
     158         [ -  + ]:          4 :         if (syslog_fd < 0) {
     159                 :          0 :                 r = syslog_fd;
     160                 :          0 :                 goto fail;
     161                 :            :         }
     162                 :            : 
     163   [ -  +  -  +  :          4 :         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                 :          4 :                 syslog_is_stream = false;
     183                 :            : 
     184                 :          4 :         return 0;
     185                 :            : 
     186                 :          0 : fail:
     187                 :          0 :         log_close_syslog();
     188                 :          0 :         return r;
     189                 :            : }
     190                 :            : 
     191                 :       1206 : static void log_close_journal(void) {
     192                 :       1206 :         journal_fd = safe_close(journal_fd);
     193                 :       1206 : }
     194                 :            : 
     195                 :        420 : 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         [ +  + ]:        420 :         if (journal_fd >= 0)
     205                 :         20 :                 return 0;
     206                 :            : 
     207                 :        400 :         journal_fd = create_log_socket(SOCK_DGRAM);
     208         [ -  + ]:        400 :         if (journal_fd < 0) {
     209                 :          0 :                 r = journal_fd;
     210                 :          0 :                 goto fail;
     211                 :            :         }
     212                 :            : 
     213   [ -  +  -  +  :        400 :         if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
                   -  + ]
     214                 :          0 :                 r = -errno;
     215                 :          0 :                 goto fail;
     216                 :            :         }
     217                 :            : 
     218                 :        400 :         return 0;
     219                 :            : 
     220                 :          0 : fail:
     221                 :          0 :         log_close_journal();
     222                 :          0 :         return r;
     223                 :            : }
     224                 :            : 
     225                 :       1626 : 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         [ +  + ]:       1626 :         if (log_target == LOG_TARGET_NULL) {
     238                 :          4 :                 log_close_journal();
     239                 :          4 :                 log_close_syslog();
     240                 :          4 :                 log_close_console();
     241                 :          4 :                 return 0;
     242                 :            :         }
     243                 :            : 
     244   [ +  +  +  - ]:       2018 :         if (log_target != LOG_TARGET_AUTO ||
     245         [ +  - ]:        792 :             getpid_cached() == 1 ||
     246                 :        396 :             isatty(STDERR_FILENO) <= 0) {
     247                 :            : 
     248         [ +  + ]:       1622 :                 if (!prohibit_ipc &&
     249   [ +  +  +  + ]:       1546 :                     IN_SET(log_target, LOG_TARGET_AUTO,
     250                 :            :                                        LOG_TARGET_JOURNAL_OR_KMSG,
     251                 :            :                                        LOG_TARGET_JOURNAL)) {
     252                 :        420 :                         r = log_open_journal();
     253         [ +  - ]:        420 :                         if (r >= 0) {
     254                 :        420 :                                 log_close_syslog();
     255                 :        420 :                                 log_close_console();
     256                 :        420 :                                 return r;
     257                 :            :                         }
     258                 :            :                 }
     259                 :            : 
     260         [ +  + ]:       1202 :                 if (!prohibit_ipc &&
     261   [ +  +  +  + ]:       1126 :                     IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
     262                 :            :                                        LOG_TARGET_SYSLOG)) {
     263                 :          8 :                         r = log_open_syslog();
     264         [ +  - ]:          8 :                         if (r >= 0) {
     265                 :          8 :                                 log_close_journal();
     266                 :          8 :                                 log_close_console();
     267                 :          8 :                                 return r;
     268                 :            :                         }
     269                 :            :                 }
     270                 :            : 
     271   [ +  +  +  + ]:       1194 :                 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                 :          4 :                         r = log_open_kmsg();
     276         [ -  + ]:          4 :                         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                 :       1194 :         log_close_journal();
     286                 :       1194 :         log_close_syslog();
     287                 :            : 
     288                 :       1194 :         return log_open_console();
     289                 :            : }
     290                 :            : 
     291                 :        580 : void log_set_target(LogTarget target) {
     292         [ -  + ]:        580 :         assert(target >= 0);
     293         [ -  + ]:        580 :         assert(target < _LOG_TARGET_MAX);
     294                 :            : 
     295         [ -  + ]:        580 :         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                 :        580 :         log_target = target;
     303                 :        580 : }
     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                 :       1235 : void log_set_max_level_realm(LogRealm realm, int level) {
     321         [ -  + ]:       1235 :         assert((level & LOG_PRIMASK) == level);
     322         [ -  + ]:       1235 :         assert(realm < ELEMENTSOF(log_max_level));
     323                 :            : 
     324                 :       1235 :         log_max_level[realm] = level;
     325                 :       1235 : }
     326                 :            : 
     327                 :          0 : void log_set_facility(int facility) {
     328                 :          0 :         log_facility = facility;
     329                 :          0 : }
     330                 :            : 
     331                 :     134600 : 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                 :     134600 :         struct iovec iovec[6] = {};
     341                 :     134600 :         const char *on = NULL, *off = NULL;
     342                 :     134600 :         size_t n = 0;
     343                 :            : 
     344         [ -  + ]:     134600 :         if (console_fd < 0)
     345                 :          0 :                 return 0;
     346                 :            : 
     347         [ +  + ]:     134600 :         if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
     348         [ -  + ]:         32 :                 xsprintf(prefix, "<%i>", level);
     349                 :         32 :                 iovec[n++] = IOVEC_MAKE_STRING(prefix);
     350                 :            :         }
     351                 :            : 
     352         [ +  + ]:     134600 :         if (show_color)
     353                 :          4 :                 get_log_colors(LOG_PRI(level), &on, &off, NULL);
     354                 :            : 
     355         [ -  + ]:     134600 :         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         [ +  + ]:     134600 :         if (on)
     367                 :          4 :                 iovec[n++] = IOVEC_MAKE_STRING(on);
     368                 :     134600 :         iovec[n++] = IOVEC_MAKE_STRING(buffer);
     369         [ +  + ]:     134600 :         if (off)
     370                 :          4 :                 iovec[n++] = IOVEC_MAKE_STRING(off);
     371                 :     134600 :         iovec[n++] = IOVEC_MAKE_STRING("\n");
     372                 :            : 
     373         [ -  + ]:     134600 :         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                 :     134600 :         return 1;
     392                 :            : }
     393                 :            : 
     394                 :         64 : 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                 :         64 :         struct iovec iovec[5] = {};
     406                 :         64 :         struct msghdr msghdr = {
     407                 :            :                 .msg_iov = iovec,
     408                 :            :                 .msg_iovlen = ELEMENTSOF(iovec),
     409                 :            :         };
     410                 :            :         time_t t;
     411                 :            :         struct tm tm;
     412                 :            : 
     413         [ -  + ]:         64 :         if (syslog_fd < 0)
     414                 :          0 :                 return 0;
     415                 :            : 
     416         [ -  + ]:         64 :         xsprintf(header_priority, "<%i>", level);
     417                 :            : 
     418                 :         64 :         t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
     419         [ -  + ]:         64 :         if (!localtime_r(&t, &tm))
     420                 :          0 :                 return -EINVAL;
     421                 :            : 
     422         [ -  + ]:         64 :         if (strftime(header_time, sizeof(header_time), "%h %e %T ", &tm) <= 0)
     423                 :          0 :                 return -EINVAL;
     424                 :            : 
     425         [ -  + ]:         64 :         xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
     426                 :            : 
     427                 :         64 :         iovec[0] = IOVEC_MAKE_STRING(header_priority);
     428                 :         64 :         iovec[1] = IOVEC_MAKE_STRING(header_time);
     429                 :         64 :         iovec[2] = IOVEC_MAKE_STRING(program_invocation_short_name);
     430                 :         64 :         iovec[3] = IOVEC_MAKE_STRING(header_pid);
     431                 :         64 :         iovec[4] = IOVEC_MAKE_STRING(buffer);
     432                 :            : 
     433                 :            :         /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
     434         [ -  + ]:         64 :         if (syslog_is_stream)
     435                 :          0 :                 iovec[4].iov_len++;
     436                 :            : 
     437                 :          0 :         for (;;) {
     438                 :            :                 ssize_t n;
     439                 :            : 
     440                 :         64 :                 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
     441         [ -  + ]:         64 :                 if (n < 0)
     442                 :          0 :                         return -errno;
     443                 :            : 
     444         [ -  + ]:         64 :                 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                 :         64 :         return 1;
     452                 :            : }
     453                 :            : 
     454                 :         32 : 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                 :         32 :         struct iovec iovec[5] = {};
     465                 :            : 
     466         [ +  - ]:         32 :         if (kmsg_fd < 0)
     467                 :         32 :                 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                 :        320 : 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         [ +  + ]:        320 :         error = IS_SYNTHETIC_ERRNO(error) ? 0 : ERRNO_VALUE(error);
     495                 :            : 
     496   [ +  +  +  +  :       3840 :         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                 :        320 :                      LOG_FAC(level),
     508                 :        320 :                      isempty(file) ? "" : "CODE_FILE=",
     509                 :        320 :                      isempty(file) ? "" : file,
     510                 :        320 :                      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                 :        320 :                      isempty(func) ? "" : "CODE_FUNC=",
     515                 :        320 :                      isempty(func) ? "" : func,
     516                 :        320 :                      isempty(func) ? "" : "\n",
     517                 :            :                      error ? "ERRNO=" : "",
     518                 :            :                      error ? 1 : 0, error,
     519                 :            :                      error ? "\n" : "",
     520                 :        320 :                      isempty(object) ? "" : object_field,
     521                 :        320 :                      isempty(object) ? "" : object,
     522                 :        320 :                      isempty(object) ? "" : "\n",
     523                 :        320 :                      isempty(extra) ? "" : extra_field,
     524                 :        320 :                      isempty(extra) ? "" : extra,
     525                 :        320 :                      isempty(extra) ? "" : "\n",
     526                 :            :                      program_invocation_short_name);
     527         [ -  + ]:        320 :         assert_raw((size_t) r < size);
     528                 :            : 
     529                 :        320 :         return 0;
     530                 :            : }
     531                 :            : 
     532                 :        236 : 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                 :        236 :         struct iovec iovec[4] = {};
     546                 :        236 :         struct msghdr mh = {};
     547                 :            : 
     548         [ -  + ]:        236 :         if (journal_fd < 0)
     549                 :          0 :                 return 0;
     550                 :            : 
     551                 :        236 :         log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
     552                 :            : 
     553                 :        236 :         iovec[0] = IOVEC_MAKE_STRING(header);
     554                 :        236 :         iovec[1] = IOVEC_MAKE_STRING("MESSAGE=");
     555                 :        236 :         iovec[2] = IOVEC_MAKE_STRING(buffer);
     556                 :        236 :         iovec[3] = IOVEC_MAKE_STRING("\n");
     557                 :            : 
     558                 :        236 :         mh.msg_iov = iovec;
     559                 :        236 :         mh.msg_iovlen = ELEMENTSOF(iovec);
     560                 :            : 
     561         [ -  + ]:        236 :         if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
     562                 :          0 :                 return -errno;
     563                 :            : 
     564                 :        236 :         return 1;
     565                 :            : }
     566                 :            : 
     567                 :     134276 : 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         [ -  + ]:     134276 :         assert_raw(buffer);
     580                 :            : 
     581         [ +  + ]:     134276 :         if (log_target == LOG_TARGET_NULL)
     582                 :          8 :                 return -ERRNO_VALUE(error);
     583                 :            : 
     584                 :            :         /* Patch in LOG_DAEMON facility if necessary */
     585         [ +  + ]:     134268 :         if ((level & LOG_FACMASK) == 0)
     586                 :     133448 :                 level |= log_facility;
     587                 :            : 
     588         [ -  + ]:     134268 :         if (open_when_needed)
     589                 :          0 :                 (void) log_open();
     590                 :            : 
     591                 :            :         do {
     592                 :            :                 char *e;
     593                 :     135468 :                 int k = 0;
     594                 :            : 
     595                 :     135468 :                 buffer += strspn(buffer, NEWLINE);
     596                 :            : 
     597         [ +  + ]:     135468 :                 if (buffer[0] == 0)
     598                 :        568 :                         break;
     599                 :            : 
     600         [ +  + ]:     134900 :                 if ((e = strpbrk(buffer, NEWLINE)))
     601                 :       1200 :                         *(e++) = 0;
     602                 :            : 
     603   [ +  +  +  + ]:     134900 :                 if (IN_SET(log_target, LOG_TARGET_AUTO,
     604                 :            :                                        LOG_TARGET_JOURNAL_OR_KMSG,
     605                 :            :                                        LOG_TARGET_JOURNAL)) {
     606                 :            : 
     607                 :        236 :                         k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
     608   [ -  +  #  # ]:        236 :                         if (k < 0 && k != -EAGAIN)
     609                 :          0 :                                 log_close_journal();
     610                 :            :                 }
     611                 :            : 
     612   [ +  +  +  + ]:     134900 :                 if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
     613                 :            :                                        LOG_TARGET_SYSLOG)) {
     614                 :            : 
     615                 :         64 :                         k = write_to_syslog(level, error, file, line, func, buffer);
     616   [ -  +  #  # ]:         64 :                         if (k < 0 && k != -EAGAIN)
     617                 :          0 :                                 log_close_syslog();
     618                 :            :                 }
     619                 :            : 
     620         [ +  + ]:     134900 :                 if (k <= 0 &&
     621   [ +  +  +  + ]:     134600 :                     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         [ -  + ]:         32 :                         if (k < 0)
     627                 :          0 :                                 log_open_kmsg();
     628                 :            : 
     629                 :         32 :                         k = write_to_kmsg(level, error, file, line, func, buffer);
     630         [ -  + ]:         32 :                         if (k < 0) {
     631                 :          0 :                                 log_close_kmsg();
     632                 :          0 :                                 (void) log_open_console();
     633                 :            :                         }
     634                 :            :                 }
     635                 :            : 
     636         [ +  + ]:     134900 :                 if (k <= 0)
     637                 :     134600 :                         (void) write_to_console(level, error, file, line, func, buffer);
     638                 :            : 
     639                 :     134900 :                 buffer = e;
     640         [ +  + ]:     134900 :         } while (buffer);
     641                 :            : 
     642         [ -  + ]:     134268 :         if (open_when_needed)
     643                 :          0 :                 log_close();
     644                 :            : 
     645                 :     134268 :         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                 :     129964 : 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                 :     129964 :         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
     677                 :            :         char buffer[LINE_MAX];
     678                 :     129964 :         PROTECT_ERRNO;
     679                 :            : 
     680         [ -  + ]:     129964 :         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                 :     129964 :         errno = ERRNO_VALUE(error);
     685                 :            : 
     686                 :     129964 :         (void) vsnprintf(buffer, sizeof buffer, format, ap);
     687                 :            : 
     688                 :     129964 :         return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
     689                 :            : }
     690                 :            : 
     691                 :     129964 : 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                 :     129964 :         va_start(ap, format);
     703                 :     129964 :         r = log_internalv_realm(level, error, file, line, func, format, ap);
     704                 :     129964 :         va_end(ap);
     705                 :            : 
     706                 :     129964 :         return r;
     707                 :            : }
     708                 :            : 
     709                 :       9564 : 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                 :       9564 :         PROTECT_ERRNO;
     723                 :            :         char *buffer, *b;
     724                 :            : 
     725         [ +  + ]:       9564 :         if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
     726                 :       6712 :                 return -ERRNO_VALUE(error);
     727                 :            : 
     728                 :            :         /* Make sure that %m maps to the specified error (or "Success"). */
     729                 :       2852 :         errno = ERRNO_VALUE(error);
     730                 :            : 
     731                 :            :         /* Prepend the object name before the message */
     732         [ +  - ]:       2852 :         if (object) {
     733                 :            :                 size_t n;
     734                 :            : 
     735                 :       2852 :                 n = strlen(object);
     736   [ -  +  -  + ]:       2852 :                 buffer = newa(char, n + 2 + LINE_MAX);
     737                 :       2852 :                 b = stpcpy(stpcpy(buffer, object), ": ");
     738                 :            :         } else
     739   [ #  #  #  # ]:          0 :                 b = buffer = newa(char, LINE_MAX);
     740                 :            : 
     741                 :       2852 :         (void) vsnprintf(b, LINE_MAX, format, ap);
     742                 :            : 
     743                 :       2852 :         return log_dispatch_internal(level, error, file, line, func,
     744                 :            :                                      object_field, object, extra_field, extra, buffer);
     745                 :            : }
     746                 :            : 
     747                 :       9564 : 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                 :       9564 :         va_start(ap, format);
     763                 :       9564 :         r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
     764                 :       9564 :         va_end(ap);
     765                 :            : 
     766                 :       9564 :         return r;
     767                 :            : }
     768                 :            : 
     769                 :        720 : 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                 :        720 :         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
     779                 :            : 
     780         [ +  + ]:        720 :         if (_likely_(LOG_PRI(level) > log_max_level[realm]))
     781                 :         80 :                 return;
     782                 :            : 
     783                 :            :         DISABLE_WARNING_FORMAT_NONLITERAL;
     784                 :        640 :         (void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
     785                 :            :         REENABLE_WARNING;
     786                 :            : 
     787                 :        640 :         log_abort_msg = buffer;
     788                 :            : 
     789                 :        640 :         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                 :        720 : 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                 :        720 :         PROTECT_ERRNO;
     823                 :        720 :         log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func,
     824                 :            :                    "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
     825                 :        720 : }
     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                 :         84 : 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   [ +  +  +  - ]:        372 :         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                 :        288 :                 errno = ERRNO_VALUE(error);
     853                 :            : 
     854                 :        288 :                 va_copy(aq, ap);
     855                 :        288 :                 r = vasprintf(&m, format, aq);
     856                 :        288 :                 va_end(aq);
     857         [ -  + ]:        288 :                 if (r < 0)
     858                 :          0 :                         return -EINVAL;
     859                 :            : 
     860                 :            :                 /* Now, jump enough ahead, so that we point to
     861                 :            :                  * the next format string */
     862   [ -  +  -  +  :        672 :                 VA_FORMAT_ADVANCE(format, ap);
          +  +  -  -  +  
             +  +  -  +  
                      + ]
     863                 :            : 
     864                 :        288 :                 iovec[(*n)++] = IOVEC_MAKE_STRING(m);
     865                 :            : 
     866         [ +  - ]:        288 :                 if (newline_separator) {
     867                 :        288 :                         iovec[*n] = IOVEC_MAKE((char *)&nl, 1);
     868                 :        288 :                         (*n)++;
     869                 :            :                 }
     870                 :            : 
     871                 :        288 :                 format = va_arg(ap, char *);
     872                 :            :         }
     873                 :         84 :         return 0;
     874                 :            : }
     875                 :            : 
     876                 :        944 : 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                 :        944 :         LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
     885                 :            :         char buf[LINE_MAX];
     886                 :        944 :         bool found = false;
     887                 :        944 :         PROTECT_ERRNO;
     888                 :            :         va_list ap;
     889                 :            : 
     890         [ +  + ]:        944 :         if (_likely_(LOG_PRI(level) > log_max_level[realm]) ||
     891         [ +  + ]:        920 :             log_target == LOG_TARGET_NULL)
     892                 :         40 :                 return -ERRNO_VALUE(error);
     893                 :            : 
     894         [ +  - ]:        904 :         if ((level & LOG_FACMASK) == 0)
     895                 :        904 :                 level |= log_facility;
     896                 :            : 
     897   [ +  +  +  + ]:        904 :         if (IN_SET(log_target,
     898                 :            :                    LOG_TARGET_AUTO,
     899                 :            :                    LOG_TARGET_JOURNAL_OR_KMSG,
     900                 :            :                    LOG_TARGET_JOURNAL)) {
     901                 :            : 
     902         [ -  + ]:         84 :                 if (open_when_needed)
     903                 :          0 :                         log_open_journal();
     904                 :            : 
     905         [ +  - ]:         84 :                 if (journal_fd >= 0) {
     906                 :            :                         char header[LINE_MAX];
     907                 :         84 :                         struct iovec iovec[17] = {};
     908                 :         84 :                         size_t n = 0, i;
     909                 :            :                         int r;
     910                 :         84 :                         struct msghdr mh = {
     911                 :            :                                 .msg_iov = iovec,
     912                 :            :                         };
     913                 :         84 :                         bool fallback = false;
     914                 :            : 
     915                 :            :                         /* If the journal is available do structured logging.
     916                 :            :                          * Do not report the errno if it is synthetic. */
     917                 :         84 :                         log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
     918                 :         84 :                         iovec[n++] = IOVEC_MAKE_STRING(header);
     919                 :            : 
     920                 :         84 :                         va_start(ap, format);
     921                 :         84 :                         r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
     922         [ -  + ]:         84 :                         if (r < 0)
     923                 :          0 :                                 fallback = true;
     924                 :            :                         else {
     925                 :         84 :                                 mh.msg_iovlen = n;
     926                 :         84 :                                 (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
     927                 :            :                         }
     928                 :            : 
     929                 :         84 :                         va_end(ap);
     930         [ +  + ]:        372 :                         for (i = 1; i < n; i += 2)
     931                 :        288 :                                 free(iovec[i].iov_base);
     932                 :            : 
     933         [ +  - ]:         84 :                         if (!fallback) {
     934         [ -  + ]:         84 :                                 if (open_when_needed)
     935                 :          0 :                                         log_close();
     936                 :            : 
     937                 :         84 :                                 return -ERRNO_VALUE(error);
     938                 :            :                         }
     939                 :            :                 }
     940                 :            :         }
     941                 :            : 
     942                 :            :         /* Fallback if journal logging is not available or didn't work. */
     943                 :            : 
     944                 :        820 :         va_start(ap, format);
     945         [ +  - ]:       2844 :         while (format) {
     946                 :            :                 va_list aq;
     947                 :            : 
     948                 :       2844 :                 errno = ERRNO_VALUE(error);
     949                 :            : 
     950                 :       2844 :                 va_copy(aq, ap);
     951                 :       2844 :                 (void) vsnprintf(buf, sizeof buf, format, aq);
     952                 :       2844 :                 va_end(aq);
     953                 :            : 
     954         [ +  + ]:       2844 :                 if (startswith(buf, "MESSAGE=")) {
     955                 :        820 :                         found = true;
     956                 :        820 :                         break;
     957                 :            :                 }
     958                 :            : 
     959   [ -  +  -  +  :       3368 :                 VA_FORMAT_ADVANCE(format, ap);
          +  -  -  -  +  
             -  -  -  +  
                      + ]
     960                 :            : 
     961                 :       2024 :                 format = va_arg(ap, char *);
     962                 :            :         }
     963                 :        820 :         va_end(ap);
     964                 :            : 
     965         [ -  + ]:        820 :         if (!found) {
     966         [ #  # ]:          0 :                 if (open_when_needed)
     967                 :          0 :                         log_close();
     968                 :            : 
     969                 :          0 :                 return -ERRNO_VALUE(error);
     970                 :            :         }
     971                 :            : 
     972                 :        820 :         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                 :         76 : int log_set_target_from_string(const char *e) {
    1034                 :            :         LogTarget t;
    1035                 :            : 
    1036                 :         76 :         t = log_target_from_string(e);
    1037         [ -  + ]:         76 :         if (t < 0)
    1038                 :          0 :                 return -EINVAL;
    1039                 :            : 
    1040                 :         76 :         log_set_target(t);
    1041                 :         76 :         return 0;
    1042                 :            : }
    1043                 :            : 
    1044                 :        771 : int log_set_max_level_from_string_realm(LogRealm realm, const char *e) {
    1045                 :            :         int t;
    1046                 :            : 
    1047                 :        771 :         t = log_level_from_string(e);
    1048         [ -  + ]:        771 :         if (t < 0)
    1049                 :          0 :                 return -EINVAL;
    1050                 :            : 
    1051                 :        771 :         log_set_max_level_realm(realm, t);
    1052                 :        771 :         return 0;
    1053                 :            : }
    1054                 :            : 
    1055                 :       9636 : 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   [ -  +  #  # ]:       9636 :         if (streq(key, "debug") && !value)
    1067                 :          0 :                 log_set_max_level(LOG_DEBUG);
    1068                 :            : 
    1069         [ -  + ]:       9636 :         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         [ -  + ]:       9636 :         } 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         [ -  + ]:       9636 :         } 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         [ -  + ]:       9636 :         } 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                 :       9636 :         return 0;
    1097                 :            : }
    1098                 :            : 
    1099                 :       1606 : void log_parse_environment_realm(LogRealm realm) {
    1100                 :            :         /* Do not call from library code. */
    1101                 :            : 
    1102                 :            :         const char *e;
    1103                 :            : 
    1104   [ +  -  +  - ]:       1606 :         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                 :       1606 :                 (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
    1109                 :            : 
    1110                 :       1606 :         e = getenv("SYSTEMD_LOG_TARGET");
    1111   [ +  +  -  + ]:       1606 :         if (e && log_set_target_from_string(e) < 0)
    1112         [ #  # ]:          0 :                 log_warning("Failed to parse log target '%s'. Ignoring.", e);
    1113                 :            : 
    1114                 :       1606 :         e = getenv("SYSTEMD_LOG_LEVEL");
    1115   [ +  +  -  + ]:       1606 :         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                 :       1606 :         e = getenv("SYSTEMD_LOG_COLOR");
    1119   [ -  +  #  # ]:       1606 :         if (e && log_show_color_from_string(e) < 0)
    1120         [ #  # ]:          0 :                 log_warning("Failed to parse log color '%s'. Ignoring.", e);
    1121                 :            : 
    1122                 :       1606 :         e = getenv("SYSTEMD_LOG_LOCATION");
    1123   [ -  +  #  # ]:       1606 :         if (e && log_show_location_from_string(e) < 0)
    1124         [ #  # ]:          0 :                 log_warning("Failed to parse log location '%s'. Ignoring.", e);
    1125                 :       1606 : }
    1126                 :            : 
    1127                 :          0 : LogTarget log_get_target(void) {
    1128                 :          0 :         return log_target;
    1129                 :            : }
    1130                 :            : 
    1131                 :     487277 : int log_get_max_level_realm(LogRealm realm) {
    1132                 :     487277 :         return log_max_level[realm];
    1133                 :            : }
    1134                 :            : 
    1135                 :        447 : void log_show_color(bool b) {
    1136                 :        447 :         show_color = b;
    1137                 :        447 : }
    1138                 :            : 
    1139                 :        184 : bool log_get_show_color(void) {
    1140                 :        184 :         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                 :        200 : bool log_on_console(void) {
    1174   [ +  -  +  - ]:        200 :         if (IN_SET(log_target, LOG_TARGET_CONSOLE,
    1175                 :            :                                LOG_TARGET_CONSOLE_PREFIXED))
    1176                 :        200 :                 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   [ +  +  +  + ]:        164 : DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
    1194                 :            : 
    1195                 :          3 : void log_received_signal(int level, const struct signalfd_siginfo *si) {
    1196         [ -  + ]:          3 :         assert(si);
    1197                 :            : 
    1198         [ +  - ]:          3 :         if (pid_is_valid(si->ssi_pid)) {
    1199                 :          6 :                 _cleanup_free_ char *p = NULL;
    1200                 :            : 
    1201                 :          3 :                 (void) get_process_comm(si->ssi_pid, &p);
    1202                 :            : 
    1203         [ -  + ]:          3 :                 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                 :          3 : }
    1212                 :            : 
    1213                 :        700 : 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                 :        700 :         PROTECT_ERRNO;
    1225                 :            :         char buffer[LINE_MAX];
    1226                 :            :         va_list ap;
    1227                 :        700 :         const char *unit_fmt = NULL;
    1228                 :            : 
    1229         [ +  - ]:        700 :         if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]) ||
    1230         [ +  + ]:        700 :             log_target == LOG_TARGET_NULL)
    1231                 :         12 :                 return -ERRNO_VALUE(error);
    1232                 :            : 
    1233                 :        688 :         errno = ERRNO_VALUE(error);
    1234                 :            : 
    1235                 :        688 :         va_start(ap, format);
    1236                 :        688 :         (void) vsnprintf(buffer, sizeof buffer, format, ap);
    1237                 :        688 :         va_end(ap);
    1238                 :            : 
    1239         [ +  + ]:        688 :         if (unit)
    1240         [ -  + ]:        460 :                 unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
    1241                 :            : 
    1242         [ +  - ]:        688 :         if (config_file) {
    1243         [ +  + ]:        688 :                 if (config_line > 0)
    1244                 :        672 :                         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                 :         16 :                         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                 :          4 : 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                 :          8 :         _cleanup_free_ char *p = NULL;
    1294                 :            : 
    1295         [ +  - ]:          4 :         if (rvalue)
    1296                 :          4 :                 p = utf8_escape_invalid(rvalue);
    1297                 :            : 
    1298                 :          4 :         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                 :          4 :         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                 :         76 : void log_set_prohibit_ipc(bool b) {
    1325                 :         76 :         prohibit_ipc = b;
    1326                 :         76 : }
    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                 :        436 : 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                 :        436 :         log_set_target(LOG_TARGET_AUTO);
    1358                 :        436 :         log_parse_environment();
    1359                 :        436 :         (void) log_open();
    1360                 :        436 : }

Generated by: LCOV version 1.14