LCOV - code coverage report
Current view: top level - shared - logs-show.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 762 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 24 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <fcntl.h>
       5             : #include <signal.h>
       6             : #include <stdint.h>
       7             : #include <stdlib.h>
       8             : #include <string.h>
       9             : #include <sys/socket.h>
      10             : #include <syslog.h>
      11             : #include <time.h>
      12             : #include <unistd.h>
      13             : 
      14             : #include "sd-id128.h"
      15             : #include "sd-journal.h"
      16             : 
      17             : #include "alloc-util.h"
      18             : #include "fd-util.h"
      19             : #include "format-util.h"
      20             : #include "hashmap.h"
      21             : #include "hostname-util.h"
      22             : #include "io-util.h"
      23             : #include "journal-internal.h"
      24             : #include "json.h"
      25             : #include "log.h"
      26             : #include "logs-show.h"
      27             : #include "macro.h"
      28             : #include "namespace-util.h"
      29             : #include "output-mode.h"
      30             : #include "parse-util.h"
      31             : #include "process-util.h"
      32             : #include "pretty-print.h"
      33             : #include "sparse-endian.h"
      34             : #include "stdio-util.h"
      35             : #include "string-table.h"
      36             : #include "string-util.h"
      37             : #include "strv.h"
      38             : #include "terminal-util.h"
      39             : #include "time-util.h"
      40             : #include "utf8.h"
      41             : #include "util.h"
      42             : 
      43             : /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
      44             : #define PRINT_LINE_THRESHOLD 3
      45             : #define PRINT_CHAR_THRESHOLD 300
      46             : 
      47             : #define JSON_THRESHOLD 4096U
      48             : 
      49           0 : static int print_catalog(FILE *f, sd_journal *j) {
      50             :         int r;
      51           0 :         _cleanup_free_ char *t = NULL, *z = NULL;
      52             : 
      53           0 :         r = sd_journal_get_catalog(j, &t);
      54           0 :         if (r < 0)
      55           0 :                 return r;
      56             : 
      57           0 :         z = strreplace(strstrip(t), "\n", "\n-- ");
      58           0 :         if (!z)
      59           0 :                 return log_oom();
      60             : 
      61           0 :         fputs("-- ", f);
      62           0 :         fputs(z, f);
      63           0 :         fputc('\n', f);
      64             : 
      65           0 :         return 0;
      66             : }
      67             : 
      68           0 : static int parse_field(const void *data, size_t length, const char *field, size_t field_len, char **target, size_t *target_len) {
      69             :         size_t nl;
      70             :         char *buf;
      71             : 
      72           0 :         assert(data);
      73           0 :         assert(field);
      74           0 :         assert(target);
      75             : 
      76           0 :         if (length < field_len)
      77           0 :                 return 0;
      78             : 
      79           0 :         if (memcmp(data, field, field_len))
      80           0 :                 return 0;
      81             : 
      82           0 :         nl = length - field_len;
      83             : 
      84           0 :         buf = newdup_suffix0(char, (const char*) data + field_len, nl);
      85           0 :         if (!buf)
      86           0 :                 return log_oom();
      87             : 
      88           0 :         free(*target);
      89           0 :         *target = buf;
      90             : 
      91           0 :         if (target_len)
      92           0 :                 *target_len = nl;
      93             : 
      94           0 :         return 1;
      95             : }
      96             : 
      97             : typedef struct ParseFieldVec {
      98             :         const char *field;
      99             :         size_t field_len;
     100             :         char **target;
     101             :         size_t *target_len;
     102             : } ParseFieldVec;
     103             : 
     104             : #define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) \
     105             :         { .field = _field, .field_len = strlen(_field), .target = _target, .target_len = _target_len }
     106             : 
     107           0 : static int parse_fieldv(const void *data, size_t length, const ParseFieldVec *fields, unsigned n_fields) {
     108             :         unsigned i;
     109             : 
     110           0 :         for (i = 0; i < n_fields; i++) {
     111           0 :                 const ParseFieldVec *f = &fields[i];
     112             :                 int r;
     113             : 
     114           0 :                 r = parse_field(data, length, f->field, f->field_len, f->target, f->target_len);
     115           0 :                 if (r < 0)
     116           0 :                         return r;
     117           0 :                 else if (r > 0)
     118           0 :                         break;
     119             :         }
     120             : 
     121           0 :         return 0;
     122             : }
     123             : 
     124           0 : static int field_set_test(Set *fields, const char *name, size_t n) {
     125           0 :         char *s = NULL;
     126             : 
     127           0 :         if (!fields)
     128           0 :                 return 1;
     129             : 
     130           0 :         s = strndupa(name, n);
     131           0 :         if (!s)
     132           0 :                 return log_oom();
     133             : 
     134           0 :         return set_get(fields, s) ? 1 : 0;
     135             : }
     136             : 
     137           0 : static bool shall_print(const char *p, size_t l, OutputFlags flags) {
     138           0 :         assert(p);
     139             : 
     140           0 :         if (flags & OUTPUT_SHOW_ALL)
     141           0 :                 return true;
     142             : 
     143           0 :         if (l >= PRINT_CHAR_THRESHOLD)
     144           0 :                 return false;
     145             : 
     146           0 :         if (!utf8_is_printable(p, l))
     147           0 :                 return false;
     148             : 
     149           0 :         return true;
     150             : }
     151             : 
     152           0 : static bool print_multiline(
     153             :                 FILE *f,
     154             :                 unsigned prefix,
     155             :                 unsigned n_columns,
     156             :                 OutputFlags flags,
     157             :                 int priority,
     158             :                 bool audit,
     159             :                 const char* message,
     160             :                 size_t message_len,
     161             :                 size_t highlight[2]) {
     162             : 
     163           0 :         const char *color_on = "", *color_off = "", *highlight_on = "";
     164             :         const char *pos, *end;
     165           0 :         bool ellipsized = false;
     166           0 :         int line = 0;
     167             : 
     168           0 :         if (flags & OUTPUT_COLOR) {
     169           0 :                 get_log_colors(priority, &color_on, &color_off, &highlight_on);
     170             : 
     171           0 :                 if (audit && strempty(color_on)) {
     172           0 :                         color_on = ANSI_BLUE;
     173           0 :                         color_off = ANSI_NORMAL;
     174             :                 }
     175             :         }
     176             : 
     177             :         /* A special case: make sure that we print a newline when
     178             :            the message is empty. */
     179           0 :         if (message_len == 0)
     180           0 :                 fputs("\n", f);
     181             : 
     182           0 :         for (pos = message;
     183           0 :              pos < message + message_len;
     184           0 :              pos = end + 1, line++) {
     185           0 :                 bool continuation = line > 0;
     186             :                 bool tail_line;
     187             :                 int len;
     188           0 :                 for (end = pos; end < message + message_len && *end != '\n'; end++)
     189             :                         ;
     190           0 :                 len = end - pos;
     191           0 :                 assert(len >= 0);
     192             : 
     193             :                 /* We need to figure out when we are showing not-last line, *and*
     194             :                  * will skip subsequent lines. In that case, we will put the dots
     195             :                  * at the end of the line, instead of putting dots in the middle
     196             :                  * or not at all.
     197             :                  */
     198           0 :                 tail_line =
     199           0 :                         line + 1 == PRINT_LINE_THRESHOLD ||
     200           0 :                         end + 1 >= message + PRINT_CHAR_THRESHOLD;
     201             : 
     202           0 :                 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
     203           0 :                     (prefix + len + 1 < n_columns && !tail_line)) {
     204           0 :                         if (highlight &&
     205           0 :                             (size_t) (pos - message) <= highlight[0] &&
     206           0 :                             highlight[0] < (size_t) len) {
     207             : 
     208           0 :                                 fprintf(f, "%*s%s%.*s",
     209             :                                         continuation * prefix, "",
     210           0 :                                         color_on, (int) highlight[0], pos);
     211           0 :                                 fprintf(f, "%s%.*s",
     212             :                                         highlight_on,
     213           0 :                                         (int) (MIN((size_t) len, highlight[1]) - highlight[0]),
     214           0 :                                         pos + highlight[0]);
     215           0 :                                 if ((size_t) len > highlight[1])
     216           0 :                                         fprintf(f, "%s%.*s",
     217             :                                                 color_on,
     218           0 :                                                 (int) (len - highlight[1]),
     219           0 :                                                 pos + highlight[1]);
     220           0 :                                 fprintf(f, "%s\n", color_off);
     221             : 
     222             :                         } else
     223           0 :                                 fprintf(f, "%*s%s%.*s%s\n",
     224             :                                         continuation * prefix, "",
     225             :                                         color_on, len, pos, color_off);
     226           0 :                         continue;
     227             :                 }
     228             : 
     229             :                 /* Beyond this point, ellipsization will happen. */
     230           0 :                 ellipsized = true;
     231             : 
     232           0 :                 if (prefix < n_columns && n_columns - prefix >= 3) {
     233           0 :                         if (n_columns - prefix > (unsigned) len + 3)
     234           0 :                                 fprintf(f, "%*s%s%.*s...%s\n",
     235             :                                         continuation * prefix, "",
     236             :                                         color_on, len, pos, color_off);
     237             :                         else {
     238           0 :                                 _cleanup_free_ char *e;
     239             : 
     240           0 :                                 e = ellipsize_mem(pos, len, n_columns - prefix,
     241             :                                                   tail_line ? 100 : 90);
     242           0 :                                 if (!e)
     243           0 :                                         fprintf(f, "%*s%s%.*s%s\n",
     244             :                                                 continuation * prefix, "",
     245             :                                                 color_on, len, pos, color_off);
     246             :                                 else
     247           0 :                                         fprintf(f, "%*s%s%s%s\n",
     248             :                                                 continuation * prefix, "",
     249             :                                                 color_on, e, color_off);
     250             :                         }
     251             :                 } else
     252           0 :                         fputs("...\n", f);
     253             : 
     254           0 :                 if (tail_line)
     255           0 :                         break;
     256             :         }
     257             : 
     258           0 :         return ellipsized;
     259             : }
     260             : 
     261           0 : static int output_timestamp_monotonic(FILE *f, sd_journal *j, const char *monotonic) {
     262             :         sd_id128_t boot_id;
     263             :         uint64_t t;
     264             :         int r;
     265             : 
     266           0 :         assert(f);
     267           0 :         assert(j);
     268             : 
     269           0 :         r = -ENXIO;
     270           0 :         if (monotonic)
     271           0 :                 r = safe_atou64(monotonic, &t);
     272           0 :         if (r < 0)
     273           0 :                 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
     274           0 :         if (r < 0)
     275           0 :                 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
     276             : 
     277           0 :         fprintf(f, "[%5"PRI_USEC".%06"PRI_USEC"]", t / USEC_PER_SEC, t % USEC_PER_SEC);
     278           0 :         return 1 + 5 + 1 + 6 + 1;
     279             : }
     280             : 
     281           0 : static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, OutputFlags flags, const char *realtime) {
     282           0 :         char buf[MAX(FORMAT_TIMESTAMP_MAX, 64)];
     283             :         struct tm *(*gettime_r)(const time_t *, struct tm *);
     284             :         struct tm tm;
     285             :         uint64_t x;
     286             :         time_t t;
     287             :         int r;
     288             : 
     289           0 :         assert(f);
     290           0 :         assert(j);
     291             : 
     292           0 :         if (realtime)
     293           0 :                 r = safe_atou64(realtime, &x);
     294           0 :         if (!realtime || r < 0 || !VALID_REALTIME(x))
     295           0 :                 r = sd_journal_get_realtime_usec(j, &x);
     296           0 :         if (r < 0)
     297           0 :                 return log_error_errno(r, "Failed to get realtime timestamp: %m");
     298             : 
     299           0 :         if (IN_SET(mode, OUTPUT_SHORT_FULL, OUTPUT_WITH_UNIT)) {
     300             :                 const char *k;
     301             : 
     302           0 :                 if (flags & OUTPUT_UTC)
     303           0 :                         k = format_timestamp_utc(buf, sizeof(buf), x);
     304             :                 else
     305           0 :                         k = format_timestamp(buf, sizeof(buf), x);
     306           0 :                 if (!k)
     307           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     308             :                                                "Failed to format timestamp: %" PRIu64, x);
     309             : 
     310             :         } else {
     311             :                 char usec[7];
     312             : 
     313           0 :                 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
     314           0 :                 t = (time_t) (x / USEC_PER_SEC);
     315             : 
     316           0 :                 switch (mode) {
     317             : 
     318           0 :                 case OUTPUT_SHORT_UNIX:
     319           0 :                         xsprintf(buf, "%10"PRI_TIME".%06"PRIu64, t, x % USEC_PER_SEC);
     320           0 :                         break;
     321             : 
     322           0 :                 case OUTPUT_SHORT_ISO:
     323           0 :                         if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm)) <= 0)
     324           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     325             :                                                        "Failed to format ISO time");
     326           0 :                         break;
     327             : 
     328           0 :                 case OUTPUT_SHORT_ISO_PRECISE:
     329             :                         /* No usec in strftime, so we leave space and copy over */
     330           0 :                         if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S.xxxxxx%z", gettime_r(&t, &tm)) <= 0)
     331           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     332             :                                                        "Failed to format ISO-precise time");
     333           0 :                         xsprintf(usec, "%06"PRI_USEC, x % USEC_PER_SEC);
     334           0 :                         memcpy(buf + 20, usec, 6);
     335           0 :                         break;
     336             : 
     337           0 :                 case OUTPUT_SHORT:
     338             :                 case OUTPUT_SHORT_PRECISE:
     339             : 
     340           0 :                         if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)) <= 0)
     341           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     342             :                                                        "Failed to format syslog time");
     343             : 
     344           0 :                         if (mode == OUTPUT_SHORT_PRECISE) {
     345             :                                 size_t k;
     346             : 
     347           0 :                                 assert(sizeof(buf) > strlen(buf));
     348           0 :                                 k = sizeof(buf) - strlen(buf);
     349             : 
     350           0 :                                 r = snprintf(buf + strlen(buf), k, ".%06"PRIu64, x % USEC_PER_SEC);
     351           0 :                                 if (r <= 0 || (size_t) r >= k) /* too long? */
     352           0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     353             :                                                                "Failed to format precise time");
     354             :                         }
     355           0 :                         break;
     356             : 
     357           0 :                 default:
     358           0 :                         assert_not_reached("Unknown time format");
     359             :                 }
     360             :         }
     361             : 
     362           0 :         fputs(buf, f);
     363           0 :         return (int) strlen(buf);
     364             : }
     365             : 
     366           0 : static int output_short(
     367             :                 FILE *f,
     368             :                 sd_journal *j,
     369             :                 OutputMode mode,
     370             :                 unsigned n_columns,
     371             :                 OutputFlags flags,
     372             :                 Set *output_fields,
     373             :                 const size_t highlight[2]) {
     374             : 
     375             :         int r;
     376             :         const void *data;
     377             :         size_t length;
     378           0 :         size_t n = 0;
     379           0 :         _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL, *transport = NULL, *config_file = NULL, *unit = NULL, *user_unit = NULL;
     380           0 :         size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0, priority_len = 0, transport_len = 0, config_file_len = 0, unit_len = 0, user_unit_len = 0;
     381           0 :         int p = LOG_INFO;
     382           0 :         bool ellipsized = false, audit;
     383           0 :         const ParseFieldVec fields[] = {
     384             :                 PARSE_FIELD_VEC_ENTRY("_PID=", &pid, &pid_len),
     385             :                 PARSE_FIELD_VEC_ENTRY("_COMM=", &comm, &comm_len),
     386             :                 PARSE_FIELD_VEC_ENTRY("MESSAGE=", &message, &message_len),
     387             :                 PARSE_FIELD_VEC_ENTRY("PRIORITY=", &priority, &priority_len),
     388             :                 PARSE_FIELD_VEC_ENTRY("_TRANSPORT=", &transport, &transport_len),
     389             :                 PARSE_FIELD_VEC_ENTRY("_HOSTNAME=", &hostname, &hostname_len),
     390             :                 PARSE_FIELD_VEC_ENTRY("SYSLOG_PID=", &fake_pid, &fake_pid_len),
     391             :                 PARSE_FIELD_VEC_ENTRY("SYSLOG_IDENTIFIER=", &identifier, &identifier_len),
     392             :                 PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len),
     393             :                 PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len),
     394             :                 PARSE_FIELD_VEC_ENTRY("CONFIG_FILE=", &config_file, &config_file_len),
     395             :                 PARSE_FIELD_VEC_ENTRY("_SYSTEMD_UNIT=", &unit, &unit_len),
     396             :                 PARSE_FIELD_VEC_ENTRY("_SYSTEMD_USER_UNIT=", &user_unit, &user_unit_len),
     397             :         };
     398           0 :         size_t highlight_shifted[] = {highlight ? highlight[0] : 0, highlight ? highlight[1] : 0};
     399             : 
     400           0 :         assert(f);
     401           0 :         assert(j);
     402             : 
     403             :         /* Set the threshold to one bigger than the actual print
     404             :          * threshold, so that if the line is actually longer than what
     405             :          * we're willing to print, ellipsization will occur. This way
     406             :          * we won't output a misleading line without any indication of
     407             :          * truncation.
     408             :          */
     409           0 :         sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
     410             : 
     411           0 :         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
     412           0 :                 r = parse_fieldv(data, length, fields, ELEMENTSOF(fields));
     413           0 :                 if (r < 0)
     414           0 :                         return r;
     415             :         }
     416           0 :         if (r == -EBADMSG) {
     417           0 :                 log_debug_errno(r, "Skipping message we can't read: %m");
     418           0 :                 return 0;
     419             :         }
     420           0 :         if (r < 0)
     421           0 :                 return log_error_errno(r, "Failed to get journal fields: %m");
     422             : 
     423           0 :         if (!message) {
     424           0 :                 log_debug("Skipping message without MESSAGE= field.");
     425           0 :                 return 0;
     426             :         }
     427             : 
     428           0 :         if (!(flags & OUTPUT_SHOW_ALL))
     429           0 :                 strip_tab_ansi(&message, &message_len, highlight_shifted);
     430             : 
     431           0 :         if (priority_len == 1 && *priority >= '0' && *priority <= '7')
     432           0 :                 p = *priority - '0';
     433             : 
     434           0 :         audit = streq_ptr(transport, "audit");
     435             : 
     436           0 :         if (mode == OUTPUT_SHORT_MONOTONIC)
     437           0 :                 r = output_timestamp_monotonic(f, j, monotonic);
     438             :         else
     439           0 :                 r = output_timestamp_realtime(f, j, mode, flags, realtime);
     440           0 :         if (r < 0)
     441           0 :                 return r;
     442           0 :         n += r;
     443             : 
     444           0 :         if (flags & OUTPUT_NO_HOSTNAME) {
     445             :                 /* Suppress display of the hostname if this is requested. */
     446           0 :                 hostname = mfree(hostname);
     447           0 :                 hostname_len = 0;
     448             :         }
     449             : 
     450           0 :         if (hostname && shall_print(hostname, hostname_len, flags)) {
     451           0 :                 fprintf(f, " %.*s", (int) hostname_len, hostname);
     452           0 :                 n += hostname_len + 1;
     453             :         }
     454             : 
     455           0 :         if (mode == OUTPUT_WITH_UNIT && ((unit && shall_print(unit, unit_len, flags)) ||
     456           0 :                                          (user_unit && shall_print(user_unit, user_unit_len, flags)))) {
     457           0 :                 if (unit) {
     458           0 :                         fprintf(f, " %.*s", (int) unit_len, unit);
     459           0 :                         n += unit_len + 1;
     460             :                 }
     461           0 :                 if (user_unit) {
     462           0 :                         if (unit)
     463           0 :                                 fprintf(f, "/%.*s", (int) user_unit_len, user_unit);
     464             :                         else
     465           0 :                                 fprintf(f, " %.*s", (int) user_unit_len, user_unit);
     466           0 :                         n += unit_len + 1;
     467             :                 }
     468           0 :         } else if (identifier && shall_print(identifier, identifier_len, flags)) {
     469           0 :                 fprintf(f, " %.*s", (int) identifier_len, identifier);
     470           0 :                 n += identifier_len + 1;
     471           0 :         } else if (comm && shall_print(comm, comm_len, flags)) {
     472           0 :                 fprintf(f, " %.*s", (int) comm_len, comm);
     473           0 :                 n += comm_len + 1;
     474             :         } else
     475           0 :                 fputs(" unknown", f);
     476             : 
     477           0 :         if (pid && shall_print(pid, pid_len, flags)) {
     478           0 :                 fprintf(f, "[%.*s]", (int) pid_len, pid);
     479           0 :                 n += pid_len + 2;
     480           0 :         } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
     481           0 :                 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
     482           0 :                 n += fake_pid_len + 2;
     483             :         }
     484             : 
     485           0 :         if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
     486             :                 char bytes[FORMAT_BYTES_MAX];
     487           0 :                 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
     488             :         } else {
     489           0 :                 fputs(": ", f);
     490             : 
     491             :                 /* URLify config_file string in message, if the message starts with it.
     492             :                  * Skip URLification if the highlighted pattern overlaps. */
     493           0 :                 if (config_file &&
     494           0 :                     message_len >= config_file_len &&
     495           0 :                     memcmp(message, config_file, config_file_len) == 0 &&
     496           0 :                     IN_SET(message[config_file_len], ':', ' ', '\0') &&
     497           0 :                     (!highlight || highlight_shifted[0] == 0 || highlight_shifted[0] > config_file_len)) {
     498             : 
     499           0 :                         _cleanup_free_ char *t = NULL, *urlified = NULL;
     500             : 
     501           0 :                         t = strndup(config_file, config_file_len);
     502           0 :                         if (t && terminal_urlify_path(t, NULL, &urlified) >= 0) {
     503           0 :                                 size_t shift = strlen(urlified) - config_file_len;
     504             :                                 char *joined;
     505             : 
     506           0 :                                 joined = strjoin(urlified, message + config_file_len);
     507           0 :                                 if (joined) {
     508           0 :                                         free_and_replace(message, joined);
     509           0 :                                         message_len += shift;
     510           0 :                                         if (highlight) {
     511           0 :                                                 highlight_shifted[0] += shift;
     512           0 :                                                 highlight_shifted[1] += shift;
     513             :                                         }
     514             :                                 }
     515             :                         }
     516             :                 }
     517             : 
     518           0 :                 ellipsized |=
     519           0 :                         print_multiline(f, n + 2, n_columns, flags, p, audit,
     520             :                                         message, message_len,
     521             :                                         highlight_shifted);
     522             :         }
     523             : 
     524           0 :         if (flags & OUTPUT_CATALOG)
     525           0 :                 print_catalog(f, j);
     526             : 
     527           0 :         return ellipsized;
     528             : }
     529             : 
     530           0 : static int output_verbose(
     531             :                 FILE *f,
     532             :                 sd_journal *j,
     533             :                 OutputMode mode,
     534             :                 unsigned n_columns,
     535             :                 OutputFlags flags,
     536             :                 Set *output_fields,
     537             :                 const size_t highlight[2]) {
     538             : 
     539             :         const void *data;
     540             :         size_t length;
     541           0 :         _cleanup_free_ char *cursor = NULL;
     542           0 :         uint64_t realtime = 0;
     543             :         char ts[FORMAT_TIMESTAMP_MAX + 7];
     544             :         const char *timestamp;
     545             :         int r;
     546             : 
     547           0 :         assert(f);
     548           0 :         assert(j);
     549             : 
     550           0 :         sd_journal_set_data_threshold(j, 0);
     551             : 
     552           0 :         r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
     553           0 :         if (r == -ENOENT)
     554           0 :                 log_debug("Source realtime timestamp not found");
     555           0 :         else if (r < 0)
     556           0 :                 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
     557             :         else {
     558           0 :                 _cleanup_free_ char *value = NULL;
     559             : 
     560           0 :                 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=",
     561             :                                 STRLEN("_SOURCE_REALTIME_TIMESTAMP="), &value,
     562             :                                 NULL);
     563           0 :                 if (r < 0)
     564           0 :                         return r;
     565           0 :                 assert(r > 0);
     566             : 
     567           0 :                 r = safe_atou64(value, &realtime);
     568           0 :                 if (r < 0)
     569           0 :                         log_debug_errno(r, "Failed to parse realtime timestamp: %m");
     570             :         }
     571             : 
     572           0 :         if (r < 0) {
     573           0 :                 r = sd_journal_get_realtime_usec(j, &realtime);
     574           0 :                 if (r < 0)
     575           0 :                         return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
     576             :         }
     577             : 
     578           0 :         r = sd_journal_get_cursor(j, &cursor);
     579           0 :         if (r < 0)
     580           0 :                 return log_error_errno(r, "Failed to get cursor: %m");
     581             : 
     582           0 :         timestamp = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
     583           0 :                                        : format_timestamp_us(ts, sizeof ts, realtime);
     584           0 :         fprintf(f, "%s [%s]\n",
     585           0 :                 timestamp ?: "(no timestamp)",
     586             :                 cursor);
     587             : 
     588           0 :         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
     589             :                 const char *c, *p;
     590             :                 int fieldlen;
     591           0 :                 const char *on = "", *off = "";
     592           0 :                 _cleanup_free_ char *urlified = NULL;
     593             :                 size_t valuelen;
     594             : 
     595           0 :                 c = memchr(data, '=', length);
     596           0 :                 if (!c)
     597           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     598             :                                                "Invalid field.");
     599           0 :                 fieldlen = c - (const char*) data;
     600             : 
     601           0 :                 r = field_set_test(output_fields, data, fieldlen);
     602           0 :                 if (r < 0)
     603           0 :                         return r;
     604           0 :                 if (r == 0)
     605           0 :                         continue;
     606             : 
     607           0 :                 valuelen = length - 1 - fieldlen;
     608             : 
     609           0 :                 if ((flags & OUTPUT_COLOR) && (p = startswith(data, "MESSAGE="))) {
     610           0 :                         on = ANSI_HIGHLIGHT;
     611           0 :                         off = ANSI_NORMAL;
     612           0 :                 } else if ((p = startswith(data, "CONFIG_FILE="))) {
     613           0 :                         if (terminal_urlify_path(p, NULL, &urlified) >= 0) {
     614           0 :                                 p = urlified;
     615           0 :                                 valuelen = strlen(urlified);
     616             :                         }
     617             :                 } else
     618           0 :                         p = c + 1;
     619             : 
     620           0 :                 if ((flags & OUTPUT_SHOW_ALL) ||
     621           0 :                     (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
     622           0 :                      && utf8_is_printable(data, length))) {
     623           0 :                         fprintf(f, "    %s%.*s=", on, fieldlen, (const char*)data);
     624           0 :                         print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, false,
     625             :                                         p, valuelen,
     626             :                                         NULL);
     627           0 :                         fputs(off, f);
     628             :                 } else {
     629             :                         char bytes[FORMAT_BYTES_MAX];
     630             : 
     631           0 :                         fprintf(f, "    %s%.*s=[%s blob data]%s\n",
     632             :                                 on,
     633           0 :                                 (int) (c - (const char*) data),
     634             :                                 (const char*) data,
     635           0 :                                 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
     636             :                                 off);
     637             :                 }
     638             :         }
     639             : 
     640           0 :         if (r < 0)
     641           0 :                 return r;
     642             : 
     643           0 :         if (flags & OUTPUT_CATALOG)
     644           0 :                 print_catalog(f, j);
     645             : 
     646           0 :         return 0;
     647             : }
     648             : 
     649           0 : static int output_export(
     650             :                 FILE *f,
     651             :                 sd_journal *j,
     652             :                 OutputMode mode,
     653             :                 unsigned n_columns,
     654             :                 OutputFlags flags,
     655             :                 Set *output_fields,
     656             :                 const size_t highlight[2]) {
     657             : 
     658             :         sd_id128_t boot_id;
     659             :         char sid[33];
     660             :         int r;
     661             :         usec_t realtime, monotonic;
     662           0 :         _cleanup_free_ char *cursor = NULL;
     663             :         const void *data;
     664             :         size_t length;
     665             : 
     666           0 :         assert(j);
     667             : 
     668           0 :         sd_journal_set_data_threshold(j, 0);
     669             : 
     670           0 :         r = sd_journal_get_realtime_usec(j, &realtime);
     671           0 :         if (r < 0)
     672           0 :                 return log_error_errno(r, "Failed to get realtime timestamp: %m");
     673             : 
     674           0 :         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
     675           0 :         if (r < 0)
     676           0 :                 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
     677             : 
     678           0 :         r = sd_journal_get_cursor(j, &cursor);
     679           0 :         if (r < 0)
     680           0 :                 return log_error_errno(r, "Failed to get cursor: %m");
     681             : 
     682           0 :         fprintf(f,
     683             :                 "__CURSOR=%s\n"
     684             :                 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
     685             :                 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
     686             :                 "_BOOT_ID=%s\n",
     687             :                 cursor,
     688             :                 realtime,
     689             :                 monotonic,
     690             :                 sd_id128_to_string(boot_id, sid));
     691             : 
     692           0 :         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
     693             :                 const char *c;
     694             : 
     695             :                 /* We already printed the boot id from the data in the header, hence let's suppress it here */
     696           0 :                 if (memory_startswith(data, length, "_BOOT_ID="))
     697           0 :                         continue;
     698             : 
     699           0 :                 c = memchr(data, '=', length);
     700           0 :                 if (!c)
     701           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     702             :                                                "Invalid field.");
     703             : 
     704           0 :                 r = field_set_test(output_fields, data, c - (const char *) data);
     705           0 :                 if (r < 0)
     706           0 :                         return r;
     707           0 :                 if (!r)
     708           0 :                         continue;
     709             : 
     710           0 :                 if (utf8_is_printable_newline(data, length, false))
     711           0 :                         fwrite(data, length, 1, f);
     712             :                 else {
     713             :                         uint64_t le64;
     714             : 
     715           0 :                         fwrite(data, c - (const char*) data, 1, f);
     716           0 :                         fputc('\n', f);
     717           0 :                         le64 = htole64(length - (c - (const char*) data) - 1);
     718           0 :                         fwrite(&le64, sizeof(le64), 1, f);
     719           0 :                         fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
     720             :                 }
     721             : 
     722           0 :                 fputc('\n', f);
     723             :         }
     724           0 :         if (r == -EBADMSG) {
     725           0 :                 log_debug_errno(r, "Skipping message we can't read: %m");
     726           0 :                 return 0;
     727             :         }
     728             : 
     729           0 :         if (r < 0)
     730           0 :                 return r;
     731             : 
     732           0 :         fputc('\n', f);
     733             : 
     734           0 :         return 0;
     735             : }
     736             : 
     737           0 : void json_escape(
     738             :                 FILE *f,
     739             :                 const char* p,
     740             :                 size_t l,
     741             :                 OutputFlags flags) {
     742             : 
     743           0 :         assert(f);
     744           0 :         assert(p);
     745             : 
     746           0 :         if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
     747           0 :                 fputs("null", f);
     748             : 
     749           0 :         else if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(p, l)) {
     750           0 :                 bool not_first = false;
     751             : 
     752           0 :                 fputs("[ ", f);
     753             : 
     754           0 :                 while (l > 0) {
     755           0 :                         if (not_first)
     756           0 :                                 fprintf(f, ", %u", (uint8_t) *p);
     757             :                         else {
     758           0 :                                 not_first = true;
     759           0 :                                 fprintf(f, "%u", (uint8_t) *p);
     760             :                         }
     761             : 
     762           0 :                         p++;
     763           0 :                         l--;
     764             :                 }
     765             : 
     766           0 :                 fputs(" ]", f);
     767             :         } else {
     768           0 :                 fputc('"', f);
     769             : 
     770           0 :                 while (l > 0) {
     771           0 :                         if (IN_SET(*p, '"', '\\')) {
     772           0 :                                 fputc('\\', f);
     773           0 :                                 fputc(*p, f);
     774           0 :                         } else if (*p == '\n')
     775           0 :                                 fputs("\\n", f);
     776           0 :                         else if ((uint8_t) *p < ' ')
     777           0 :                                 fprintf(f, "\\u%04x", (uint8_t) *p);
     778             :                         else
     779           0 :                                 fputc(*p, f);
     780             : 
     781           0 :                         p++;
     782           0 :                         l--;
     783             :                 }
     784             : 
     785           0 :                 fputc('"', f);
     786             :         }
     787           0 : }
     788             : 
     789             : struct json_data {
     790             :         JsonVariant* name;
     791             :         size_t n_values;
     792             :         JsonVariant* values[];
     793             : };
     794             : 
     795           0 : static int update_json_data(
     796             :                 Hashmap *h,
     797             :                 OutputFlags flags,
     798             :                 const char *name,
     799             :                 const void *value,
     800             :                 size_t size) {
     801             : 
     802           0 :         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
     803             :         struct json_data *d;
     804             :         int r;
     805             : 
     806           0 :         if (!(flags & OUTPUT_SHOW_ALL) && strlen(name) + 1 + size >= JSON_THRESHOLD)
     807           0 :                 r = json_variant_new_null(&v);
     808           0 :         else if (utf8_is_printable(value, size))
     809           0 :                 r = json_variant_new_stringn(&v, value, size);
     810             :         else
     811           0 :                 r = json_variant_new_array_bytes(&v, value, size);
     812           0 :         if (r < 0)
     813           0 :                 return log_error_errno(r, "Failed to allocate JSON data: %m");
     814             : 
     815           0 :         d = hashmap_get(h, name);
     816           0 :         if (d) {
     817             :                 struct json_data *w;
     818             : 
     819           0 :                 w = realloc(d, offsetof(struct json_data, values) + sizeof(JsonVariant*) * (d->n_values + 1));
     820           0 :                 if (!w)
     821           0 :                         return log_oom();
     822             : 
     823           0 :                 d = w;
     824           0 :                 assert_se(hashmap_update(h, json_variant_string(d->name), d) >= 0);
     825             :         } else {
     826           0 :                 _cleanup_(json_variant_unrefp) JsonVariant *n = NULL;
     827             : 
     828           0 :                 r = json_variant_new_string(&n, name);
     829           0 :                 if (r < 0)
     830           0 :                         return log_error_errno(r, "Failed to allocate JSON name variant: %m");
     831             : 
     832           0 :                 d = malloc0(offsetof(struct json_data, values) + sizeof(JsonVariant*));
     833           0 :                 if (!d)
     834           0 :                         return log_oom();
     835             : 
     836           0 :                 r = hashmap_put(h, json_variant_string(n), d);
     837           0 :                 if (r < 0) {
     838           0 :                         free(d);
     839           0 :                         return log_error_errno(r, "Failed to insert JSON name into hashmap: %m");
     840             :                 }
     841             : 
     842           0 :                 d->name = TAKE_PTR(n);
     843             :         }
     844             : 
     845           0 :         d->values[d->n_values++] = TAKE_PTR(v);
     846           0 :         return 0;
     847             : }
     848             : 
     849           0 : static int update_json_data_split(
     850             :                 Hashmap *h,
     851             :                 OutputFlags flags,
     852             :                 Set *output_fields,
     853             :                 const void *data,
     854             :                 size_t size) {
     855             : 
     856             :         const char *eq;
     857             :         char *name;
     858             : 
     859           0 :         assert(h);
     860           0 :         assert(data || size == 0);
     861             : 
     862           0 :         if (memory_startswith(data, size, "_BOOT_ID="))
     863           0 :                 return 0;
     864             : 
     865           0 :         eq = memchr(data, '=', MIN(size, JSON_THRESHOLD));
     866           0 :         if (!eq)
     867           0 :                 return 0;
     868             : 
     869           0 :         if (eq == data)
     870           0 :                 return 0;
     871             : 
     872           0 :         name = strndupa(data, eq - (const char*) data);
     873           0 :         if (output_fields && !set_get(output_fields, name))
     874           0 :                 return 0;
     875             : 
     876           0 :         return update_json_data(h, flags, name, eq + 1, size - (eq - (const char*) data) - 1);
     877             : }
     878             : 
     879           0 : static int output_json(
     880             :                 FILE *f,
     881             :                 sd_journal *j,
     882             :                 OutputMode mode,
     883             :                 unsigned n_columns,
     884             :                 OutputFlags flags,
     885             :                 Set *output_fields,
     886             :                 const size_t highlight[2]) {
     887             : 
     888             :         char sid[SD_ID128_STRING_MAX], usecbuf[DECIMAL_STR_MAX(usec_t)];
     889           0 :         _cleanup_(json_variant_unrefp) JsonVariant *object = NULL;
     890           0 :         _cleanup_free_ char *cursor = NULL;
     891             :         uint64_t realtime, monotonic;
     892           0 :         JsonVariant **array = NULL;
     893             :         struct json_data *d;
     894             :         sd_id128_t boot_id;
     895           0 :         Hashmap *h = NULL;
     896           0 :         size_t n = 0;
     897             :         Iterator i;
     898             :         int r;
     899             : 
     900           0 :         assert(j);
     901             : 
     902           0 :         (void) sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
     903             : 
     904           0 :         r = sd_journal_get_realtime_usec(j, &realtime);
     905           0 :         if (r < 0)
     906           0 :                 return log_error_errno(r, "Failed to get realtime timestamp: %m");
     907             : 
     908           0 :         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
     909           0 :         if (r < 0)
     910           0 :                 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
     911             : 
     912           0 :         r = sd_journal_get_cursor(j, &cursor);
     913           0 :         if (r < 0)
     914           0 :                 return log_error_errno(r, "Failed to get cursor: %m");
     915             : 
     916           0 :         h = hashmap_new(&string_hash_ops);
     917           0 :         if (!h)
     918           0 :                 return log_oom();
     919             : 
     920           0 :         r = update_json_data(h, flags, "__CURSOR", cursor, strlen(cursor));
     921           0 :         if (r < 0)
     922           0 :                 goto finish;
     923             : 
     924           0 :         xsprintf(usecbuf, USEC_FMT, realtime);
     925           0 :         r = update_json_data(h, flags, "__REALTIME_TIMESTAMP", usecbuf, strlen(usecbuf));
     926           0 :         if (r < 0)
     927           0 :                 goto finish;
     928             : 
     929           0 :         xsprintf(usecbuf, USEC_FMT, monotonic);
     930           0 :         r = update_json_data(h, flags, "__MONOTONIC_TIMESTAMP", usecbuf, strlen(usecbuf));
     931           0 :         if (r < 0)
     932           0 :                 goto finish;
     933             : 
     934           0 :         sd_id128_to_string(boot_id, sid);
     935           0 :         r = update_json_data(h, flags, "_BOOT_ID", sid, strlen(sid));
     936           0 :         if (r < 0)
     937           0 :                 goto finish;
     938             : 
     939           0 :         for (;;) {
     940             :                 const void *data;
     941             :                 size_t size;
     942             : 
     943           0 :                 r = sd_journal_enumerate_data(j, &data, &size);
     944           0 :                 if (r == -EBADMSG) {
     945           0 :                         log_debug_errno(r, "Skipping message we can't read: %m");
     946           0 :                         r = 0;
     947           0 :                         goto finish;
     948             :                 }
     949           0 :                 if (r < 0) {
     950           0 :                         log_error_errno(r, "Failed to read journal: %m");
     951           0 :                         goto finish;
     952             :                 }
     953           0 :                 if (r == 0)
     954           0 :                         break;
     955             : 
     956           0 :                 r = update_json_data_split(h, flags, output_fields, data, size);
     957           0 :                 if (r < 0)
     958           0 :                         goto finish;
     959             :         }
     960             : 
     961           0 :         array = new(JsonVariant*, hashmap_size(h)*2);
     962           0 :         if (!array) {
     963           0 :                 r = log_oom();
     964           0 :                 goto finish;
     965             :         }
     966             : 
     967           0 :         HASHMAP_FOREACH(d, h, i) {
     968           0 :                 assert(d->n_values > 0);
     969             : 
     970           0 :                 array[n++] = json_variant_ref(d->name);
     971             : 
     972           0 :                 if (d->n_values == 1)
     973           0 :                         array[n++] = json_variant_ref(d->values[0]);
     974             :                 else {
     975           0 :                         _cleanup_(json_variant_unrefp) JsonVariant *q = NULL;
     976             : 
     977           0 :                         r = json_variant_new_array(&q, d->values, d->n_values);
     978           0 :                         if (r < 0) {
     979           0 :                                 log_error_errno(r, "Failed to create JSON array: %m");
     980           0 :                                 goto finish;
     981             :                         }
     982             : 
     983           0 :                         array[n++] = TAKE_PTR(q);
     984             :                 }
     985             :         }
     986             : 
     987           0 :         r = json_variant_new_object(&object, array, n);
     988           0 :         if (r < 0) {
     989           0 :                 log_error_errno(r, "Failed to allocate JSON object: %m");
     990           0 :                 goto finish;
     991             :         }
     992             : 
     993           0 :         json_variant_dump(object,
     994           0 :                           output_mode_to_json_format_flags(mode) |
     995           0 :                           (FLAGS_SET(flags, OUTPUT_COLOR) ? JSON_FORMAT_COLOR : 0),
     996             :                           f, NULL);
     997             : 
     998           0 :         r = 0;
     999             : 
    1000           0 : finish:
    1001           0 :         while ((d = hashmap_steal_first(h))) {
    1002             :                 size_t k;
    1003             : 
    1004           0 :                 json_variant_unref(d->name);
    1005           0 :                 for (k = 0; k < d->n_values; k++)
    1006           0 :                         json_variant_unref(d->values[k]);
    1007             : 
    1008           0 :                 free(d);
    1009             :         }
    1010             : 
    1011           0 :         hashmap_free(h);
    1012             : 
    1013           0 :         json_variant_unref_many(array, n);
    1014           0 :         free(array);
    1015             : 
    1016           0 :         return r;
    1017             : }
    1018             : 
    1019           0 : static int output_cat(
    1020             :                 FILE *f,
    1021             :                 sd_journal *j,
    1022             :                 OutputMode mode,
    1023             :                 unsigned n_columns,
    1024             :                 OutputFlags flags,
    1025             :                 Set *output_fields,
    1026             :                 const size_t highlight[2]) {
    1027             : 
    1028             :         const void *data;
    1029             :         size_t l;
    1030             :         int r;
    1031           0 :         const char *highlight_on = "", *highlight_off = "";
    1032             : 
    1033           0 :         assert(j);
    1034           0 :         assert(f);
    1035             : 
    1036           0 :         if (flags & OUTPUT_COLOR) {
    1037           0 :                 highlight_on = ANSI_HIGHLIGHT_RED;
    1038           0 :                 highlight_off = ANSI_NORMAL;
    1039             :         }
    1040             : 
    1041           0 :         sd_journal_set_data_threshold(j, 0);
    1042             : 
    1043           0 :         r = sd_journal_get_data(j, "MESSAGE", &data, &l);
    1044           0 :         if (r == -EBADMSG) {
    1045           0 :                 log_debug_errno(r, "Skipping message we can't read: %m");
    1046           0 :                 return 0;
    1047             :         }
    1048           0 :         if (r < 0) {
    1049             :                 /* An entry without MESSAGE=? */
    1050           0 :                 if (r == -ENOENT)
    1051           0 :                         return 0;
    1052             : 
    1053           0 :                 return log_error_errno(r, "Failed to get data: %m");
    1054             :         }
    1055             : 
    1056           0 :         assert(l >= 8);
    1057             : 
    1058           0 :         if (highlight && (flags & OUTPUT_COLOR)) {
    1059           0 :                 assert(highlight[0] <= highlight[1]);
    1060           0 :                 assert(highlight[1] <= l - 8);
    1061             : 
    1062           0 :                 fwrite((const char*) data + 8, 1, highlight[0], f);
    1063           0 :                 fwrite(highlight_on, 1, strlen(highlight_on), f);
    1064           0 :                 fwrite((const char*) data + 8 + highlight[0], 1, highlight[1] - highlight[0], f);
    1065           0 :                 fwrite(highlight_off, 1, strlen(highlight_off), f);
    1066           0 :                 fwrite((const char*) data + 8 + highlight[1], 1, l - 8 - highlight[1], f);
    1067             :         } else
    1068           0 :                 fwrite((const char*) data + 8, 1, l - 8, f);
    1069           0 :         fputc('\n', f);
    1070             : 
    1071           0 :         return 0;
    1072             : }
    1073             : 
    1074             : static int (*output_funcs[_OUTPUT_MODE_MAX])(
    1075             :                 FILE *f,
    1076             :                 sd_journal *j,
    1077             :                 OutputMode mode,
    1078             :                 unsigned n_columns,
    1079             :                 OutputFlags flags,
    1080             :                 Set *output_fields,
    1081             :                 const size_t highlight[2]) = {
    1082             : 
    1083             :         [OUTPUT_SHORT]             = output_short,
    1084             :         [OUTPUT_SHORT_ISO]         = output_short,
    1085             :         [OUTPUT_SHORT_ISO_PRECISE] = output_short,
    1086             :         [OUTPUT_SHORT_PRECISE]     = output_short,
    1087             :         [OUTPUT_SHORT_MONOTONIC]   = output_short,
    1088             :         [OUTPUT_SHORT_UNIX]        = output_short,
    1089             :         [OUTPUT_SHORT_FULL]        = output_short,
    1090             :         [OUTPUT_VERBOSE]           = output_verbose,
    1091             :         [OUTPUT_EXPORT]            = output_export,
    1092             :         [OUTPUT_JSON]              = output_json,
    1093             :         [OUTPUT_JSON_PRETTY]       = output_json,
    1094             :         [OUTPUT_JSON_SSE]          = output_json,
    1095             :         [OUTPUT_JSON_SEQ]          = output_json,
    1096             :         [OUTPUT_CAT]               = output_cat,
    1097             :         [OUTPUT_WITH_UNIT]         = output_short,
    1098             : };
    1099             : 
    1100           0 : int show_journal_entry(
    1101             :                 FILE *f,
    1102             :                 sd_journal *j,
    1103             :                 OutputMode mode,
    1104             :                 unsigned n_columns,
    1105             :                 OutputFlags flags,
    1106             :                 char **output_fields,
    1107             :                 const size_t highlight[2],
    1108             :                 bool *ellipsized) {
    1109             : 
    1110             :         int ret;
    1111           0 :         _cleanup_set_free_free_ Set *fields = NULL;
    1112           0 :         assert(mode >= 0);
    1113           0 :         assert(mode < _OUTPUT_MODE_MAX);
    1114             : 
    1115           0 :         if (n_columns <= 0)
    1116           0 :                 n_columns = columns();
    1117             : 
    1118           0 :         if (output_fields) {
    1119           0 :                 fields = set_new(&string_hash_ops);
    1120           0 :                 if (!fields)
    1121           0 :                         return log_oom();
    1122             : 
    1123           0 :                 ret = set_put_strdupv(fields, output_fields);
    1124           0 :                 if (ret < 0)
    1125           0 :                         return ret;
    1126             :         }
    1127             : 
    1128           0 :         ret = output_funcs[mode](f, j, mode, n_columns, flags, fields, highlight);
    1129             : 
    1130           0 :         if (ellipsized && ret > 0)
    1131           0 :                 *ellipsized = true;
    1132             : 
    1133           0 :         return ret;
    1134             : }
    1135             : 
    1136           0 : static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
    1137           0 :         assert(f);
    1138           0 :         assert(flags);
    1139             : 
    1140           0 :         if (!(*flags & OUTPUT_BEGIN_NEWLINE))
    1141           0 :                 return 0;
    1142             : 
    1143             :         /* Print a beginning new line if that's request, but only once
    1144             :          * on the first line we print. */
    1145             : 
    1146           0 :         fputc('\n', f);
    1147           0 :         *flags &= ~OUTPUT_BEGIN_NEWLINE;
    1148           0 :         return 0;
    1149             : }
    1150             : 
    1151           0 : int show_journal(
    1152             :                 FILE *f,
    1153             :                 sd_journal *j,
    1154             :                 OutputMode mode,
    1155             :                 unsigned n_columns,
    1156             :                 usec_t not_before,
    1157             :                 unsigned how_many,
    1158             :                 OutputFlags flags,
    1159             :                 bool *ellipsized) {
    1160             : 
    1161             :         int r;
    1162           0 :         unsigned line = 0;
    1163           0 :         bool need_seek = false;
    1164           0 :         int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
    1165             : 
    1166           0 :         assert(j);
    1167           0 :         assert(mode >= 0);
    1168           0 :         assert(mode < _OUTPUT_MODE_MAX);
    1169             : 
    1170           0 :         if (how_many == (unsigned) -1)
    1171           0 :                 need_seek = true;
    1172             :         else {
    1173             :                 /* Seek to end */
    1174           0 :                 r = sd_journal_seek_tail(j);
    1175           0 :                 if (r < 0)
    1176           0 :                         return log_error_errno(r, "Failed to seek to tail: %m");
    1177             : 
    1178           0 :                 r = sd_journal_previous_skip(j, how_many);
    1179           0 :                 if (r < 0)
    1180           0 :                         return log_error_errno(r, "Failed to skip previous: %m");
    1181             :         }
    1182             : 
    1183           0 :         for (;;) {
    1184           0 :                 for (;;) {
    1185             :                         usec_t usec;
    1186             : 
    1187           0 :                         if (need_seek) {
    1188           0 :                                 r = sd_journal_next(j);
    1189           0 :                                 if (r < 0)
    1190           0 :                                         return log_error_errno(r, "Failed to iterate through journal: %m");
    1191             :                         }
    1192             : 
    1193           0 :                         if (r == 0)
    1194           0 :                                 break;
    1195             : 
    1196           0 :                         need_seek = true;
    1197             : 
    1198           0 :                         if (not_before > 0) {
    1199           0 :                                 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
    1200             : 
    1201             :                                 /* -ESTALE is returned if the
    1202             :                                    timestamp is not from this boot */
    1203           0 :                                 if (r == -ESTALE)
    1204           0 :                                         continue;
    1205           0 :                                 else if (r < 0)
    1206           0 :                                         return log_error_errno(r, "Failed to get journal time: %m");
    1207             : 
    1208           0 :                                 if (usec < not_before)
    1209           0 :                                         continue;
    1210             :                         }
    1211             : 
    1212           0 :                         line++;
    1213           0 :                         maybe_print_begin_newline(f, &flags);
    1214             : 
    1215           0 :                         r = show_journal_entry(f, j, mode, n_columns, flags, NULL, NULL, ellipsized);
    1216           0 :                         if (r < 0)
    1217           0 :                                 return r;
    1218             :                 }
    1219             : 
    1220           0 :                 if (warn_cutoff && line < how_many && not_before > 0) {
    1221             :                         sd_id128_t boot_id;
    1222           0 :                         usec_t cutoff = 0;
    1223             : 
    1224             :                         /* Check whether the cutoff line is too early */
    1225             : 
    1226           0 :                         r = sd_id128_get_boot(&boot_id);
    1227           0 :                         if (r < 0)
    1228           0 :                                 return log_error_errno(r, "Failed to get boot id: %m");
    1229             : 
    1230           0 :                         r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
    1231           0 :                         if (r < 0)
    1232           0 :                                 return log_error_errno(r, "Failed to get journal cutoff time: %m");
    1233             : 
    1234           0 :                         if (r > 0 && not_before < cutoff) {
    1235           0 :                                 maybe_print_begin_newline(f, &flags);
    1236           0 :                                 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
    1237             :                         }
    1238             : 
    1239           0 :                         warn_cutoff = false;
    1240             :                 }
    1241             : 
    1242           0 :                 if (!(flags & OUTPUT_FOLLOW))
    1243           0 :                         break;
    1244             : 
    1245           0 :                 r = sd_journal_wait(j, USEC_INFINITY);
    1246           0 :                 if (r < 0)
    1247           0 :                         return log_error_errno(r, "Failed to wait for journal: %m");
    1248             : 
    1249             :         }
    1250             : 
    1251           0 :         return 0;
    1252             : }
    1253             : 
    1254           0 : int add_matches_for_unit(sd_journal *j, const char *unit) {
    1255             :         const char *m1, *m2, *m3, *m4;
    1256             :         int r;
    1257             : 
    1258           0 :         assert(j);
    1259           0 :         assert(unit);
    1260             : 
    1261           0 :         m1 = strjoina("_SYSTEMD_UNIT=", unit);
    1262           0 :         m2 = strjoina("COREDUMP_UNIT=", unit);
    1263           0 :         m3 = strjoina("UNIT=", unit);
    1264           0 :         m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
    1265             : 
    1266           0 :         (void)(
    1267             :             /* Look for messages from the service itself */
    1268           0 :             (r = sd_journal_add_match(j, m1, 0)) ||
    1269             : 
    1270             :             /* Look for coredumps of the service */
    1271           0 :             (r = sd_journal_add_disjunction(j)) ||
    1272           0 :             (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
    1273           0 :             (r = sd_journal_add_match(j, "_UID=0", 0)) ||
    1274           0 :             (r = sd_journal_add_match(j, m2, 0)) ||
    1275             : 
    1276             :              /* Look for messages from PID 1 about this service */
    1277           0 :             (r = sd_journal_add_disjunction(j)) ||
    1278           0 :             (r = sd_journal_add_match(j, "_PID=1", 0)) ||
    1279           0 :             (r = sd_journal_add_match(j, m3, 0)) ||
    1280             : 
    1281             :             /* Look for messages from authorized daemons about this service */
    1282           0 :             (r = sd_journal_add_disjunction(j)) ||
    1283           0 :             (r = sd_journal_add_match(j, "_UID=0", 0)) ||
    1284           0 :             (r = sd_journal_add_match(j, m4, 0))
    1285             :         );
    1286             : 
    1287           0 :         if (r == 0 && endswith(unit, ".slice")) {
    1288             :                 const char *m5;
    1289             : 
    1290           0 :                 m5 = strjoina("_SYSTEMD_SLICE=", unit);
    1291             : 
    1292             :                 /* Show all messages belonging to a slice */
    1293           0 :                 (void)(
    1294           0 :                         (r = sd_journal_add_disjunction(j)) ||
    1295           0 :                         (r = sd_journal_add_match(j, m5, 0))
    1296             :                         );
    1297             :         }
    1298             : 
    1299           0 :         return r;
    1300             : }
    1301             : 
    1302           0 : int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
    1303             :         int r;
    1304             :         char *m1, *m2, *m3, *m4;
    1305             :         char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
    1306             : 
    1307           0 :         assert(j);
    1308           0 :         assert(unit);
    1309             : 
    1310           0 :         m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
    1311           0 :         m2 = strjoina("USER_UNIT=", unit);
    1312           0 :         m3 = strjoina("COREDUMP_USER_UNIT=", unit);
    1313           0 :         m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
    1314           0 :         sprintf(muid, "_UID="UID_FMT, uid);
    1315             : 
    1316           0 :         (void) (
    1317             :                 /* Look for messages from the user service itself */
    1318           0 :                 (r = sd_journal_add_match(j, m1, 0)) ||
    1319           0 :                 (r = sd_journal_add_match(j, muid, 0)) ||
    1320             : 
    1321             :                 /* Look for messages from systemd about this service */
    1322           0 :                 (r = sd_journal_add_disjunction(j)) ||
    1323           0 :                 (r = sd_journal_add_match(j, m2, 0)) ||
    1324           0 :                 (r = sd_journal_add_match(j, muid, 0)) ||
    1325             : 
    1326             :                 /* Look for coredumps of the service */
    1327           0 :                 (r = sd_journal_add_disjunction(j)) ||
    1328           0 :                 (r = sd_journal_add_match(j, m3, 0)) ||
    1329           0 :                 (r = sd_journal_add_match(j, muid, 0)) ||
    1330           0 :                 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
    1331             : 
    1332             :                 /* Look for messages from authorized daemons about this service */
    1333           0 :                 (r = sd_journal_add_disjunction(j)) ||
    1334           0 :                 (r = sd_journal_add_match(j, m4, 0)) ||
    1335           0 :                 (r = sd_journal_add_match(j, muid, 0)) ||
    1336           0 :                 (r = sd_journal_add_match(j, "_UID=0", 0))
    1337             :         );
    1338             : 
    1339           0 :         if (r == 0 && endswith(unit, ".slice")) {
    1340             :                 const char *m5;
    1341             : 
    1342           0 :                 m5 = strjoina("_SYSTEMD_SLICE=", unit);
    1343             : 
    1344             :                 /* Show all messages belonging to a slice */
    1345           0 :                 (void)(
    1346           0 :                         (r = sd_journal_add_disjunction(j)) ||
    1347           0 :                         (r = sd_journal_add_match(j, m5, 0)) ||
    1348           0 :                         (r = sd_journal_add_match(j, muid, 0))
    1349             :                         );
    1350             :         }
    1351             : 
    1352           0 :         return r;
    1353             : }
    1354             : 
    1355           0 : static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
    1356           0 :         _cleanup_close_pair_ int pair[2] = { -1, -1 };
    1357           0 :         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
    1358             :         pid_t pid, child;
    1359             :         char buf[37];
    1360             :         ssize_t k;
    1361             :         int r;
    1362             : 
    1363           0 :         assert(machine);
    1364           0 :         assert(boot_id);
    1365             : 
    1366           0 :         if (!machine_name_is_valid(machine))
    1367           0 :                 return -EINVAL;
    1368             : 
    1369           0 :         r = container_get_leader(machine, &pid);
    1370           0 :         if (r < 0)
    1371           0 :                 return r;
    1372             : 
    1373           0 :         r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
    1374           0 :         if (r < 0)
    1375           0 :                 return r;
    1376             : 
    1377           0 :         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
    1378           0 :                 return -errno;
    1379             : 
    1380           0 :         r = namespace_fork("(sd-bootidns)", "(sd-bootid)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
    1381             :                            pidnsfd, mntnsfd, -1, -1, rootfd, &child);
    1382           0 :         if (r < 0)
    1383           0 :                 return r;
    1384           0 :         if (r == 0) {
    1385             :                 int fd;
    1386             : 
    1387           0 :                 pair[0] = safe_close(pair[0]);
    1388             : 
    1389           0 :                 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
    1390           0 :                 if (fd < 0)
    1391           0 :                         _exit(EXIT_FAILURE);
    1392             : 
    1393           0 :                 r = loop_read_exact(fd, buf, 36, false);
    1394           0 :                 safe_close(fd);
    1395           0 :                 if (r < 0)
    1396           0 :                         _exit(EXIT_FAILURE);
    1397             : 
    1398           0 :                 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
    1399           0 :                 if (k != 36)
    1400           0 :                         _exit(EXIT_FAILURE);
    1401             : 
    1402           0 :                 _exit(EXIT_SUCCESS);
    1403             :         }
    1404             : 
    1405           0 :         pair[1] = safe_close(pair[1]);
    1406             : 
    1407           0 :         r = wait_for_terminate_and_check("(sd-bootidns)", child, 0);
    1408           0 :         if (r < 0)
    1409           0 :                 return r;
    1410           0 :         if (r != EXIT_SUCCESS)
    1411           0 :                 return -EIO;
    1412             : 
    1413           0 :         k = recv(pair[0], buf, 36, 0);
    1414           0 :         if (k != 36)
    1415           0 :                 return -EIO;
    1416             : 
    1417           0 :         buf[36] = 0;
    1418           0 :         r = sd_id128_from_string(buf, boot_id);
    1419           0 :         if (r < 0)
    1420           0 :                 return r;
    1421             : 
    1422           0 :         return 0;
    1423             : }
    1424             : 
    1425           0 : int add_match_this_boot(sd_journal *j, const char *machine) {
    1426           0 :         char match[9+32+1] = "_BOOT_ID=";
    1427             :         sd_id128_t boot_id;
    1428             :         int r;
    1429             : 
    1430           0 :         assert(j);
    1431             : 
    1432           0 :         if (machine) {
    1433           0 :                 r = get_boot_id_for_machine(machine, &boot_id);
    1434           0 :                 if (r < 0)
    1435           0 :                         return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
    1436             :         } else {
    1437           0 :                 r = sd_id128_get_boot(&boot_id);
    1438           0 :                 if (r < 0)
    1439           0 :                         return log_error_errno(r, "Failed to get boot id: %m");
    1440             :         }
    1441             : 
    1442           0 :         sd_id128_to_string(boot_id, match + 9);
    1443           0 :         r = sd_journal_add_match(j, match, strlen(match));
    1444           0 :         if (r < 0)
    1445           0 :                 return log_error_errno(r, "Failed to add match: %m");
    1446             : 
    1447           0 :         r = sd_journal_add_conjunction(j);
    1448           0 :         if (r < 0)
    1449           0 :                 return log_error_errno(r, "Failed to add conjunction: %m");
    1450             : 
    1451           0 :         return 0;
    1452             : }
    1453             : 
    1454           0 : int show_journal_by_unit(
    1455             :                 FILE *f,
    1456             :                 const char *unit,
    1457             :                 OutputMode mode,
    1458             :                 unsigned n_columns,
    1459             :                 usec_t not_before,
    1460             :                 unsigned how_many,
    1461             :                 uid_t uid,
    1462             :                 OutputFlags flags,
    1463             :                 int journal_open_flags,
    1464             :                 bool system_unit,
    1465             :                 bool *ellipsized) {
    1466             : 
    1467           0 :         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
    1468             :         int r;
    1469             : 
    1470           0 :         assert(mode >= 0);
    1471           0 :         assert(mode < _OUTPUT_MODE_MAX);
    1472           0 :         assert(unit);
    1473             : 
    1474           0 :         if (how_many <= 0)
    1475           0 :                 return 0;
    1476             : 
    1477           0 :         r = sd_journal_open(&j, journal_open_flags);
    1478           0 :         if (r < 0)
    1479           0 :                 return log_error_errno(r, "Failed to open journal: %m");
    1480             : 
    1481           0 :         r = add_match_this_boot(j, NULL);
    1482           0 :         if (r < 0)
    1483           0 :                 return r;
    1484             : 
    1485           0 :         if (system_unit)
    1486           0 :                 r = add_matches_for_unit(j, unit);
    1487             :         else
    1488           0 :                 r = add_matches_for_user_unit(j, unit, uid);
    1489           0 :         if (r < 0)
    1490           0 :                 return log_error_errno(r, "Failed to add unit matches: %m");
    1491             : 
    1492           0 :         if (DEBUG_LOGGING) {
    1493           0 :                 _cleanup_free_ char *filter;
    1494             : 
    1495           0 :                 filter = journal_make_match_string(j);
    1496           0 :                 if (!filter)
    1497           0 :                         return log_oom();
    1498             : 
    1499           0 :                 log_debug("Journal filter: %s", filter);
    1500             :         }
    1501             : 
    1502           0 :         return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
    1503             : }

Generated by: LCOV version 1.14