LCOV - code coverage report
Current view: top level - shared - logs-show.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 1 651 0.2 %
Date: 2015-07-29 18:47:03 Functions: 2 20 10.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2012 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <time.h>
      23             : #include <errno.h>
      24             : #include <sys/socket.h>
      25             : #include <string.h>
      26             : #include <fcntl.h>
      27             : 
      28             : #include "logs-show.h"
      29             : #include "log.h"
      30             : #include "util.h"
      31             : #include "utf8.h"
      32             : #include "hashmap.h"
      33             : #include "journal-internal.h"
      34             : #include "formats-util.h"
      35             : #include "process-util.h"
      36             : #include "terminal-util.h"
      37             : 
      38             : /* up to three lines (each up to 100 characters),
      39             :    or 300 characters, whichever is less */
      40             : #define PRINT_LINE_THRESHOLD 3
      41             : #define PRINT_CHAR_THRESHOLD 300
      42             : 
      43             : #define JSON_THRESHOLD 4096
      44             : 
      45           0 : static int print_catalog(FILE *f, sd_journal *j) {
      46             :         int r;
      47           0 :         _cleanup_free_ char *t = NULL, *z = NULL;
      48             : 
      49             : 
      50           0 :         r = sd_journal_get_catalog(j, &t);
      51           0 :         if (r < 0)
      52           0 :                 return r;
      53             : 
      54           0 :         z = strreplace(strstrip(t), "\n", "\n-- ");
      55           0 :         if (!z)
      56           0 :                 return log_oom();
      57             : 
      58           0 :         fputs("-- ", f);
      59           0 :         fputs(z, f);
      60           0 :         fputc('\n', f);
      61             : 
      62           0 :         return 0;
      63             : }
      64             : 
      65           0 : static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
      66             :         size_t fl, nl;
      67             :         void *buf;
      68             : 
      69           0 :         assert(data);
      70           0 :         assert(field);
      71           0 :         assert(target);
      72           0 :         assert(target_size);
      73             : 
      74           0 :         fl = strlen(field);
      75           0 :         if (length < fl)
      76           0 :                 return 0;
      77             : 
      78           0 :         if (memcmp(data, field, fl))
      79           0 :                 return 0;
      80             : 
      81           0 :         nl = length - fl;
      82           0 :         buf = malloc(nl+1);
      83           0 :         if (!buf)
      84           0 :                 return log_oom();
      85             : 
      86           0 :         memcpy(buf, (const char*) data + fl, nl);
      87           0 :         ((char*)buf)[nl] = 0;
      88             : 
      89           0 :         free(*target);
      90           0 :         *target = buf;
      91           0 :         *target_size = nl;
      92             : 
      93           0 :         return 1;
      94             : }
      95             : 
      96           0 : static bool shall_print(const char *p, size_t l, OutputFlags flags) {
      97           0 :         assert(p);
      98             : 
      99           0 :         if (flags & OUTPUT_SHOW_ALL)
     100           0 :                 return true;
     101             : 
     102           0 :         if (l >= PRINT_CHAR_THRESHOLD)
     103           0 :                 return false;
     104             : 
     105           0 :         if (!utf8_is_printable(p, l))
     106           0 :                 return false;
     107             : 
     108           0 :         return true;
     109             : }
     110             : 
     111           0 : static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
     112           0 :         const char *color_on = "", *color_off = "";
     113             :         const char *pos, *end;
     114           0 :         bool ellipsized = false;
     115           0 :         int line = 0;
     116             : 
     117           0 :         if (flags & OUTPUT_COLOR) {
     118           0 :                 if (priority <= LOG_ERR) {
     119           0 :                         color_on = ANSI_HIGHLIGHT_RED_ON;
     120           0 :                         color_off = ANSI_HIGHLIGHT_OFF;
     121           0 :                 } else if (priority <= LOG_NOTICE) {
     122           0 :                         color_on = ANSI_HIGHLIGHT_ON;
     123           0 :                         color_off = ANSI_HIGHLIGHT_OFF;
     124             :                 }
     125             :         }
     126             : 
     127             :         /* A special case: make sure that we print a newline when
     128             :            the message is empty. */
     129           0 :         if (message_len == 0)
     130           0 :                 fputs("\n", f);
     131             : 
     132           0 :         for (pos = message;
     133           0 :              pos < message + message_len;
     134           0 :              pos = end + 1, line++) {
     135           0 :                 bool continuation = line > 0;
     136             :                 bool tail_line;
     137             :                 int len;
     138           0 :                 for (end = pos; end < message + message_len && *end != '\n'; end++)
     139             :                         ;
     140           0 :                 len = end - pos;
     141           0 :                 assert(len >= 0);
     142             : 
     143             :                 /* We need to figure out when we are showing not-last line, *and*
     144             :                  * will skip subsequent lines. In that case, we will put the dots
     145             :                  * at the end of the line, instead of putting dots in the middle
     146             :                  * or not at all.
     147             :                  */
     148           0 :                 tail_line =
     149           0 :                         line + 1 == PRINT_LINE_THRESHOLD ||
     150           0 :                         end + 1 >= message + PRINT_CHAR_THRESHOLD;
     151             : 
     152           0 :                 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
     153           0 :                     (prefix + len + 1 < n_columns && !tail_line)) {
     154           0 :                         fprintf(f, "%*s%s%.*s%s\n",
     155             :                                 continuation * prefix, "",
     156             :                                 color_on, len, pos, color_off);
     157           0 :                         continue;
     158             :                 }
     159             : 
     160             :                 /* Beyond this point, ellipsization will happen. */
     161           0 :                 ellipsized = true;
     162             : 
     163           0 :                 if (prefix < n_columns && n_columns - prefix >= 3) {
     164           0 :                         if (n_columns - prefix > (unsigned) len + 3)
     165           0 :                                 fprintf(f, "%*s%s%.*s...%s\n",
     166             :                                         continuation * prefix, "",
     167             :                                         color_on, len, pos, color_off);
     168             :                         else {
     169           0 :                                 _cleanup_free_ char *e;
     170             : 
     171           0 :                                 e = ellipsize_mem(pos, len, n_columns - prefix,
     172             :                                                   tail_line ? 100 : 90);
     173           0 :                                 if (!e)
     174           0 :                                         fprintf(f, "%*s%s%.*s%s\n",
     175             :                                                 continuation * prefix, "",
     176             :                                                 color_on, len, pos, color_off);
     177             :                                 else
     178           0 :                                         fprintf(f, "%*s%s%s%s\n",
     179             :                                                 continuation * prefix, "",
     180             :                                                 color_on, e, color_off);
     181             :                         }
     182             :                 } else
     183           0 :                         fputs("...\n", f);
     184             : 
     185           0 :                 if (tail_line)
     186           0 :                         break;
     187             :         }
     188             : 
     189           0 :         return ellipsized;
     190             : }
     191             : 
     192           0 : static int output_short(
     193             :                 FILE *f,
     194             :                 sd_journal *j,
     195             :                 OutputMode mode,
     196             :                 unsigned n_columns,
     197             :                 OutputFlags flags) {
     198             : 
     199             :         int r;
     200             :         const void *data;
     201             :         size_t length;
     202           0 :         size_t n = 0;
     203           0 :         _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
     204           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;
     205           0 :         int p = LOG_INFO;
     206           0 :         bool ellipsized = false;
     207             : 
     208           0 :         assert(f);
     209           0 :         assert(j);
     210             : 
     211             :         /* Set the threshold to one bigger than the actual print
     212             :          * threshold, so that if the line is actually longer than what
     213             :          * we're willing to print, ellipsization will occur. This way
     214             :          * we won't output a misleading line without any indication of
     215             :          * truncation.
     216             :          */
     217           0 :         sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
     218             : 
     219           0 :         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
     220             : 
     221           0 :                 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
     222           0 :                 if (r < 0)
     223           0 :                         return r;
     224           0 :                 else if (r > 0)
     225           0 :                         continue;
     226             : 
     227           0 :                 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
     228           0 :                 if (r < 0)
     229           0 :                         return r;
     230           0 :                 else if (r > 0)
     231           0 :                         continue;
     232             : 
     233           0 :                 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
     234           0 :                 if (r < 0)
     235           0 :                         return r;
     236           0 :                 else if (r > 0)
     237           0 :                         continue;
     238             : 
     239           0 :                 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
     240           0 :                 if (r < 0)
     241           0 :                         return r;
     242           0 :                 else if (r > 0)
     243           0 :                         continue;
     244             : 
     245           0 :                 r = parse_field(data, length, "_PID=", &pid, &pid_len);
     246           0 :                 if (r < 0)
     247           0 :                         return r;
     248           0 :                 else if (r > 0)
     249           0 :                         continue;
     250             : 
     251           0 :                 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
     252           0 :                 if (r < 0)
     253           0 :                         return r;
     254           0 :                 else if (r > 0)
     255           0 :                         continue;
     256             : 
     257           0 :                 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
     258           0 :                 if (r < 0)
     259           0 :                         return r;
     260           0 :                 else if (r > 0)
     261           0 :                         continue;
     262             : 
     263           0 :                 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
     264           0 :                 if (r < 0)
     265           0 :                         return r;
     266           0 :                 else if (r > 0)
     267           0 :                         continue;
     268             : 
     269           0 :                 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
     270           0 :                 if (r < 0)
     271           0 :                         return r;
     272             :         }
     273             : 
     274           0 :         if (r < 0)
     275           0 :                 return log_error_errno(r, "Failed to get journal fields: %m");
     276             : 
     277           0 :         if (!message) {
     278           0 :                 log_debug("Skipping message without MESSAGE= field.");
     279           0 :                 return 0;
     280             :         }
     281             : 
     282           0 :         if (!(flags & OUTPUT_SHOW_ALL))
     283           0 :                 strip_tab_ansi(&message, &message_len);
     284             : 
     285           0 :         if (priority_len == 1 && *priority >= '0' && *priority <= '7')
     286           0 :                 p = *priority - '0';
     287             : 
     288           0 :         if (mode == OUTPUT_SHORT_MONOTONIC) {
     289             :                 uint64_t t;
     290             :                 sd_id128_t boot_id;
     291             : 
     292           0 :                 r = -ENOENT;
     293             : 
     294           0 :                 if (monotonic)
     295           0 :                         r = safe_atou64(monotonic, &t);
     296             : 
     297           0 :                 if (r < 0)
     298           0 :                         r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
     299             : 
     300           0 :                 if (r < 0)
     301           0 :                         return log_error_errno(r, "Failed to get monotonic timestamp: %m");
     302             : 
     303           0 :                 fprintf(f, "[%5llu.%06llu]",
     304           0 :                         (unsigned long long) (t / USEC_PER_SEC),
     305           0 :                         (unsigned long long) (t % USEC_PER_SEC));
     306             : 
     307           0 :                 n += 1 + 5 + 1 + 6 + 1;
     308             : 
     309             :         } else {
     310             :                 char buf[64];
     311             :                 uint64_t x;
     312             :                 time_t t;
     313             :                 struct tm tm;
     314             :                 struct tm *(*gettime_r)(const time_t *, struct tm *);
     315             : 
     316           0 :                 r = -ENOENT;
     317           0 :                 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
     318             : 
     319           0 :                 if (realtime)
     320           0 :                         r = safe_atou64(realtime, &x);
     321             : 
     322           0 :                 if (r < 0)
     323           0 :                         r = sd_journal_get_realtime_usec(j, &x);
     324             : 
     325           0 :                 if (r < 0)
     326           0 :                         return log_error_errno(r, "Failed to get realtime timestamp: %m");
     327             : 
     328           0 :                 t = (time_t) (x / USEC_PER_SEC);
     329             : 
     330           0 :                 switch(mode) {
     331             :                 case OUTPUT_SHORT_ISO:
     332           0 :                         r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
     333           0 :                         break;
     334             :                 case OUTPUT_SHORT_PRECISE:
     335           0 :                         r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
     336           0 :                         if (r > 0) {
     337           0 :                                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
     338           0 :                                          ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
     339             :                         }
     340           0 :                         break;
     341             :                 default:
     342           0 :                         r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
     343             :                 }
     344             : 
     345           0 :                 if (r <= 0) {
     346           0 :                         log_error("Failed to format time.");
     347           0 :                         return -EINVAL;
     348             :                 }
     349             : 
     350           0 :                 fputs(buf, f);
     351           0 :                 n += strlen(buf);
     352             :         }
     353             : 
     354           0 :         if (hostname && shall_print(hostname, hostname_len, flags)) {
     355           0 :                 fprintf(f, " %.*s", (int) hostname_len, hostname);
     356           0 :                 n += hostname_len + 1;
     357             :         }
     358             : 
     359           0 :         if (identifier && shall_print(identifier, identifier_len, flags)) {
     360           0 :                 fprintf(f, " %.*s", (int) identifier_len, identifier);
     361           0 :                 n += identifier_len + 1;
     362           0 :         } else if (comm && shall_print(comm, comm_len, flags)) {
     363           0 :                 fprintf(f, " %.*s", (int) comm_len, comm);
     364           0 :                 n += comm_len + 1;
     365             :         } else
     366           0 :                 fputs(" unknown", f);
     367             : 
     368           0 :         if (pid && shall_print(pid, pid_len, flags)) {
     369           0 :                 fprintf(f, "[%.*s]", (int) pid_len, pid);
     370           0 :                 n += pid_len + 2;
     371           0 :         } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
     372           0 :                 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
     373           0 :                 n += fake_pid_len + 2;
     374             :         }
     375             : 
     376           0 :         if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
     377             :                 char bytes[FORMAT_BYTES_MAX];
     378           0 :                 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
     379             :         } else {
     380           0 :                 fputs(": ", f);
     381           0 :                 ellipsized |=
     382           0 :                         print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
     383             :         }
     384             : 
     385           0 :         if (flags & OUTPUT_CATALOG)
     386           0 :                 print_catalog(f, j);
     387             : 
     388           0 :         return ellipsized;
     389             : }
     390             : 
     391           0 : static int output_verbose(
     392             :                 FILE *f,
     393             :                 sd_journal *j,
     394             :                 OutputMode mode,
     395             :                 unsigned n_columns,
     396             :                 OutputFlags flags) {
     397             : 
     398             :         const void *data;
     399             :         size_t length;
     400           0 :         _cleanup_free_ char *cursor = NULL;
     401             :         uint64_t realtime;
     402             :         char ts[FORMAT_TIMESTAMP_MAX + 7];
     403             :         int r;
     404             : 
     405           0 :         assert(f);
     406           0 :         assert(j);
     407             : 
     408           0 :         sd_journal_set_data_threshold(j, 0);
     409             : 
     410           0 :         r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
     411           0 :         if (r == -ENOENT)
     412           0 :                 log_debug("Source realtime timestamp not found");
     413           0 :         else if (r < 0)
     414           0 :                 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
     415             :         else {
     416           0 :                 _cleanup_free_ char *value = NULL;
     417             :                 size_t size;
     418             : 
     419           0 :                 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
     420           0 :                 if (r < 0)
     421           0 :                         log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
     422             :                 else {
     423           0 :                         r = safe_atou64(value, &realtime);
     424           0 :                         if (r < 0)
     425           0 :                                 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
     426             :                 }
     427             :         }
     428             : 
     429           0 :         if (r < 0) {
     430           0 :                 r = sd_journal_get_realtime_usec(j, &realtime);
     431           0 :                 if (r < 0)
     432           0 :                         return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
     433             :         }
     434             : 
     435           0 :         r = sd_journal_get_cursor(j, &cursor);
     436           0 :         if (r < 0)
     437           0 :                 return log_error_errno(r, "Failed to get cursor: %m");
     438             : 
     439           0 :         fprintf(f, "%s [%s]\n",
     440           0 :                 flags & OUTPUT_UTC ?
     441           0 :                 format_timestamp_us_utc(ts, sizeof(ts), realtime) :
     442           0 :                 format_timestamp_us(ts, sizeof(ts), realtime),
     443             :                 cursor);
     444             : 
     445           0 :         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
     446             :                 const char *c;
     447             :                 int fieldlen;
     448           0 :                 const char *on = "", *off = "";
     449             : 
     450           0 :                 c = memchr(data, '=', length);
     451           0 :                 if (!c) {
     452           0 :                         log_error("Invalid field.");
     453           0 :                         return -EINVAL;
     454             :                 }
     455           0 :                 fieldlen = c - (const char*) data;
     456             : 
     457           0 :                 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
     458           0 :                         on = ANSI_HIGHLIGHT_ON;
     459           0 :                         off = ANSI_HIGHLIGHT_OFF;
     460             :                 }
     461             : 
     462           0 :                 if (flags & OUTPUT_SHOW_ALL ||
     463           0 :                     (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
     464           0 :                      && utf8_is_printable(data, length))) {
     465           0 :                         fprintf(f, "    %s%.*s=", on, fieldlen, (const char*)data);
     466           0 :                         print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
     467           0 :                         fputs(off, f);
     468             :                 } else {
     469             :                         char bytes[FORMAT_BYTES_MAX];
     470             : 
     471           0 :                         fprintf(f, "    %s%.*s=[%s blob data]%s\n",
     472             :                                 on,
     473           0 :                                 (int) (c - (const char*) data),
     474             :                                 (const char*) data,
     475           0 :                                 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
     476             :                                 off);
     477             :                 }
     478             :         }
     479             : 
     480           0 :         if (r < 0)
     481           0 :                 return r;
     482             : 
     483           0 :         if (flags & OUTPUT_CATALOG)
     484           0 :                 print_catalog(f, j);
     485             : 
     486           0 :         return 0;
     487             : }
     488             : 
     489           0 : static int output_export(
     490             :                 FILE *f,
     491             :                 sd_journal *j,
     492             :                 OutputMode mode,
     493             :                 unsigned n_columns,
     494             :                 OutputFlags flags) {
     495             : 
     496             :         sd_id128_t boot_id;
     497             :         char sid[33];
     498             :         int r;
     499             :         usec_t realtime, monotonic;
     500           0 :         _cleanup_free_ char *cursor = NULL;
     501             :         const void *data;
     502             :         size_t length;
     503             : 
     504           0 :         assert(j);
     505             : 
     506           0 :         sd_journal_set_data_threshold(j, 0);
     507             : 
     508           0 :         r = sd_journal_get_realtime_usec(j, &realtime);
     509           0 :         if (r < 0)
     510           0 :                 return log_error_errno(r, "Failed to get realtime timestamp: %m");
     511             : 
     512           0 :         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
     513           0 :         if (r < 0)
     514           0 :                 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
     515             : 
     516           0 :         r = sd_journal_get_cursor(j, &cursor);
     517           0 :         if (r < 0)
     518           0 :                 return log_error_errno(r, "Failed to get cursor: %m");
     519             : 
     520           0 :         fprintf(f,
     521             :                 "__CURSOR=%s\n"
     522             :                 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
     523             :                 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
     524             :                 "_BOOT_ID=%s\n",
     525             :                 cursor,
     526             :                 realtime,
     527             :                 monotonic,
     528             :                 sd_id128_to_string(boot_id, sid));
     529             : 
     530           0 :         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
     531             : 
     532             :                 /* We already printed the boot id, from the data in
     533             :                  * the header, hence let's suppress it here */
     534           0 :                 if (length >= 9 &&
     535           0 :                     startswith(data, "_BOOT_ID="))
     536           0 :                         continue;
     537             : 
     538           0 :                 if (utf8_is_printable_newline(data, length, false))
     539           0 :                         fwrite(data, length, 1, f);
     540             :                 else {
     541             :                         const char *c;
     542             :                         uint64_t le64;
     543             : 
     544           0 :                         c = memchr(data, '=', length);
     545           0 :                         if (!c) {
     546           0 :                                 log_error("Invalid field.");
     547           0 :                                 return -EINVAL;
     548             :                         }
     549             : 
     550           0 :                         fwrite(data, c - (const char*) data, 1, f);
     551           0 :                         fputc('\n', f);
     552           0 :                         le64 = htole64(length - (c - (const char*) data) - 1);
     553           0 :                         fwrite(&le64, sizeof(le64), 1, f);
     554           0 :                         fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
     555             :                 }
     556             : 
     557           0 :                 fputc('\n', f);
     558             :         }
     559             : 
     560           0 :         if (r < 0)
     561           0 :                 return r;
     562             : 
     563           0 :         fputc('\n', f);
     564             : 
     565           0 :         return 0;
     566             : }
     567             : 
     568           0 : void json_escape(
     569             :                 FILE *f,
     570             :                 const char* p,
     571             :                 size_t l,
     572             :                 OutputFlags flags) {
     573             : 
     574           0 :         assert(f);
     575           0 :         assert(p);
     576             : 
     577           0 :         if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
     578             : 
     579           0 :                 fputs("null", f);
     580             : 
     581           0 :         else if (!utf8_is_printable(p, l)) {
     582           0 :                 bool not_first = false;
     583             : 
     584           0 :                 fputs("[ ", f);
     585             : 
     586           0 :                 while (l > 0) {
     587           0 :                         if (not_first)
     588           0 :                                 fprintf(f, ", %u", (uint8_t) *p);
     589             :                         else {
     590           0 :                                 not_first = true;
     591           0 :                                 fprintf(f, "%u", (uint8_t) *p);
     592             :                         }
     593             : 
     594           0 :                         p++;
     595           0 :                         l--;
     596             :                 }
     597             : 
     598           0 :                 fputs(" ]", f);
     599             :         } else {
     600           0 :                 fputc('\"', f);
     601             : 
     602           0 :                 while (l > 0) {
     603           0 :                         if (*p == '"' || *p == '\\') {
     604           0 :                                 fputc('\\', f);
     605           0 :                                 fputc(*p, f);
     606           0 :                         } else if (*p == '\n')
     607           0 :                                 fputs("\\n", f);
     608           0 :                         else if (*p < ' ')
     609           0 :                                 fprintf(f, "\\u%04x", *p);
     610             :                         else
     611           0 :                                 fputc(*p, f);
     612             : 
     613           0 :                         p++;
     614           0 :                         l--;
     615             :                 }
     616             : 
     617           0 :                 fputc('\"', f);
     618             :         }
     619           0 : }
     620             : 
     621           0 : static int output_json(
     622             :                 FILE *f,
     623             :                 sd_journal *j,
     624             :                 OutputMode mode,
     625             :                 unsigned n_columns,
     626             :                 OutputFlags flags) {
     627             : 
     628             :         uint64_t realtime, monotonic;
     629           0 :         _cleanup_free_ char *cursor = NULL;
     630             :         const void *data;
     631             :         size_t length;
     632             :         sd_id128_t boot_id;
     633             :         char sid[33], *k;
     634             :         int r;
     635           0 :         Hashmap *h = NULL;
     636             :         bool done, separator;
     637             : 
     638           0 :         assert(j);
     639             : 
     640           0 :         sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
     641             : 
     642           0 :         r = sd_journal_get_realtime_usec(j, &realtime);
     643           0 :         if (r < 0)
     644           0 :                 return log_error_errno(r, "Failed to get realtime timestamp: %m");
     645             : 
     646           0 :         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
     647           0 :         if (r < 0)
     648           0 :                 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
     649             : 
     650           0 :         r = sd_journal_get_cursor(j, &cursor);
     651           0 :         if (r < 0)
     652           0 :                 return log_error_errno(r, "Failed to get cursor: %m");
     653             : 
     654           0 :         if (mode == OUTPUT_JSON_PRETTY)
     655           0 :                 fprintf(f,
     656             :                         "{\n"
     657             :                         "\t\"__CURSOR\" : \"%s\",\n"
     658             :                         "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
     659             :                         "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
     660             :                         "\t\"_BOOT_ID\" : \"%s\"",
     661             :                         cursor,
     662             :                         realtime,
     663             :                         monotonic,
     664             :                         sd_id128_to_string(boot_id, sid));
     665             :         else {
     666           0 :                 if (mode == OUTPUT_JSON_SSE)
     667           0 :                         fputs("data: ", f);
     668             : 
     669           0 :                 fprintf(f,
     670             :                         "{ \"__CURSOR\" : \"%s\", "
     671             :                         "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
     672             :                         "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
     673             :                         "\"_BOOT_ID\" : \"%s\"",
     674             :                         cursor,
     675             :                         realtime,
     676             :                         monotonic,
     677             :                         sd_id128_to_string(boot_id, sid));
     678             :         }
     679             : 
     680           0 :         h = hashmap_new(&string_hash_ops);
     681           0 :         if (!h)
     682           0 :                 return log_oom();
     683             : 
     684             :         /* First round, iterate through the entry and count how often each field appears */
     685           0 :         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
     686             :                 const char *eq;
     687             :                 char *n;
     688             :                 unsigned u;
     689             : 
     690           0 :                 if (length >= 9 &&
     691           0 :                     memcmp(data, "_BOOT_ID=", 9) == 0)
     692           0 :                         continue;
     693             : 
     694           0 :                 eq = memchr(data, '=', length);
     695           0 :                 if (!eq)
     696           0 :                         continue;
     697             : 
     698           0 :                 n = strndup(data, eq - (const char*) data);
     699           0 :                 if (!n) {
     700           0 :                         r = log_oom();
     701           0 :                         goto finish;
     702             :                 }
     703             : 
     704           0 :                 u = PTR_TO_UINT(hashmap_get(h, n));
     705           0 :                 if (u == 0) {
     706           0 :                         r = hashmap_put(h, n, UINT_TO_PTR(1));
     707           0 :                         if (r < 0) {
     708           0 :                                 free(n);
     709           0 :                                 log_oom();
     710           0 :                                 goto finish;
     711             :                         }
     712             :                 } else {
     713           0 :                         r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
     714           0 :                         free(n);
     715           0 :                         if (r < 0) {
     716           0 :                                 log_oom();
     717           0 :                                 goto finish;
     718             :                         }
     719             :                 }
     720             :         }
     721             : 
     722           0 :         if (r < 0)
     723           0 :                 return r;
     724             : 
     725           0 :         separator = true;
     726             :         do {
     727           0 :                 done = true;
     728             : 
     729           0 :                 SD_JOURNAL_FOREACH_DATA(j, data, length) {
     730             :                         const char *eq;
     731             :                         char *kk, *n;
     732             :                         size_t m;
     733             :                         unsigned u;
     734             : 
     735             :                         /* We already printed the boot id, from the data in
     736             :                          * the header, hence let's suppress it here */
     737           0 :                         if (length >= 9 &&
     738           0 :                             memcmp(data, "_BOOT_ID=", 9) == 0)
     739           0 :                                 continue;
     740             : 
     741           0 :                         eq = memchr(data, '=', length);
     742           0 :                         if (!eq)
     743           0 :                                 continue;
     744             : 
     745           0 :                         if (separator) {
     746           0 :                                 if (mode == OUTPUT_JSON_PRETTY)
     747           0 :                                         fputs(",\n\t", f);
     748             :                                 else
     749           0 :                                         fputs(", ", f);
     750             :                         }
     751             : 
     752           0 :                         m = eq - (const char*) data;
     753             : 
     754           0 :                         n = strndup(data, m);
     755           0 :                         if (!n) {
     756           0 :                                 r = log_oom();
     757           0 :                                 goto finish;
     758             :                         }
     759             : 
     760           0 :                         u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
     761           0 :                         if (u == 0) {
     762             :                                 /* We already printed this, let's jump to the next */
     763           0 :                                 free(n);
     764           0 :                                 separator = false;
     765             : 
     766           0 :                                 continue;
     767           0 :                         } else if (u == 1) {
     768             :                                 /* Field only appears once, output it directly */
     769             : 
     770           0 :                                 json_escape(f, data, m, flags);
     771           0 :                                 fputs(" : ", f);
     772             : 
     773           0 :                                 json_escape(f, eq + 1, length - m - 1, flags);
     774             : 
     775           0 :                                 hashmap_remove(h, n);
     776           0 :                                 free(kk);
     777           0 :                                 free(n);
     778             : 
     779           0 :                                 separator = true;
     780             : 
     781           0 :                                 continue;
     782             : 
     783             :                         } else {
     784             :                                 /* Field appears multiple times, output it as array */
     785           0 :                                 json_escape(f, data, m, flags);
     786           0 :                                 fputs(" : [ ", f);
     787           0 :                                 json_escape(f, eq + 1, length - m - 1, flags);
     788             : 
     789             :                                 /* Iterate through the end of the list */
     790             : 
     791           0 :                                 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
     792           0 :                                         if (length < m + 1)
     793           0 :                                                 continue;
     794             : 
     795           0 :                                         if (memcmp(data, n, m) != 0)
     796           0 :                                                 continue;
     797             : 
     798           0 :                                         if (((const char*) data)[m] != '=')
     799           0 :                                                 continue;
     800             : 
     801           0 :                                         fputs(", ", f);
     802           0 :                                         json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
     803             :                                 }
     804             : 
     805           0 :                                 fputs(" ]", f);
     806             : 
     807           0 :                                 hashmap_remove(h, n);
     808           0 :                                 free(kk);
     809           0 :                                 free(n);
     810             : 
     811             :                                 /* Iterate data fields form the beginning */
     812           0 :                                 done = false;
     813           0 :                                 separator = true;
     814             : 
     815           0 :                                 break;
     816             :                         }
     817             :                 }
     818             : 
     819           0 :         } while (!done);
     820             : 
     821           0 :         if (mode == OUTPUT_JSON_PRETTY)
     822           0 :                 fputs("\n}\n", f);
     823           0 :         else if (mode == OUTPUT_JSON_SSE)
     824           0 :                 fputs("}\n\n", f);
     825             :         else
     826           0 :                 fputs(" }\n", f);
     827             : 
     828           0 :         r = 0;
     829             : 
     830             : finish:
     831           0 :         while ((k = hashmap_steal_first_key(h)))
     832           0 :                 free(k);
     833             : 
     834           0 :         hashmap_free(h);
     835             : 
     836           0 :         return r;
     837             : }
     838             : 
     839           0 : static int output_cat(
     840             :                 FILE *f,
     841             :                 sd_journal *j,
     842             :                 OutputMode mode,
     843             :                 unsigned n_columns,
     844             :                 OutputFlags flags) {
     845             : 
     846             :         const void *data;
     847             :         size_t l;
     848             :         int r;
     849             : 
     850           0 :         assert(j);
     851           0 :         assert(f);
     852             : 
     853           0 :         sd_journal_set_data_threshold(j, 0);
     854             : 
     855           0 :         r = sd_journal_get_data(j, "MESSAGE", &data, &l);
     856           0 :         if (r < 0) {
     857             :                 /* An entry without MESSAGE=? */
     858           0 :                 if (r == -ENOENT)
     859           0 :                         return 0;
     860             : 
     861           0 :                 return log_error_errno(r, "Failed to get data: %m");
     862             :         }
     863             : 
     864           0 :         assert(l >= 8);
     865             : 
     866           0 :         fwrite((const char*) data + 8, 1, l - 8, f);
     867           0 :         fputc('\n', f);
     868             : 
     869           0 :         return 0;
     870             : }
     871             : 
     872             : static int (*output_funcs[_OUTPUT_MODE_MAX])(
     873             :                 FILE *f,
     874             :                 sd_journal*j,
     875             :                 OutputMode mode,
     876             :                 unsigned n_columns,
     877             :                 OutputFlags flags) = {
     878             : 
     879             :         [OUTPUT_SHORT] = output_short,
     880             :         [OUTPUT_SHORT_ISO] = output_short,
     881             :         [OUTPUT_SHORT_PRECISE] = output_short,
     882             :         [OUTPUT_SHORT_MONOTONIC] = output_short,
     883             :         [OUTPUT_VERBOSE] = output_verbose,
     884             :         [OUTPUT_EXPORT] = output_export,
     885             :         [OUTPUT_JSON] = output_json,
     886             :         [OUTPUT_JSON_PRETTY] = output_json,
     887             :         [OUTPUT_JSON_SSE] = output_json,
     888             :         [OUTPUT_CAT] = output_cat
     889             : };
     890             : 
     891           0 : int output_journal(
     892             :                 FILE *f,
     893             :                 sd_journal *j,
     894             :                 OutputMode mode,
     895             :                 unsigned n_columns,
     896             :                 OutputFlags flags,
     897             :                 bool *ellipsized) {
     898             : 
     899             :         int ret;
     900           0 :         assert(mode >= 0);
     901           0 :         assert(mode < _OUTPUT_MODE_MAX);
     902             : 
     903           0 :         if (n_columns <= 0)
     904           0 :                 n_columns = columns();
     905             : 
     906           0 :         ret = output_funcs[mode](f, j, mode, n_columns, flags);
     907           0 :         fflush(stdout);
     908             : 
     909           0 :         if (ellipsized && ret > 0)
     910           0 :                 *ellipsized = true;
     911             : 
     912           0 :         return ret;
     913             : }
     914             : 
     915           0 : static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
     916           0 :         assert(f);
     917           0 :         assert(flags);
     918             : 
     919           0 :         if (!(*flags & OUTPUT_BEGIN_NEWLINE))
     920           0 :                 return 0;
     921             : 
     922             :         /* Print a beginning new line if that's request, but only once
     923             :          * on the first line we print. */
     924             : 
     925           0 :         fputc('\n', f);
     926           0 :         *flags &= ~OUTPUT_BEGIN_NEWLINE;
     927           0 :         return 0;
     928             : }
     929             : 
     930           0 : static int show_journal(FILE *f,
     931             :                         sd_journal *j,
     932             :                         OutputMode mode,
     933             :                         unsigned n_columns,
     934             :                         usec_t not_before,
     935             :                         unsigned how_many,
     936             :                         OutputFlags flags,
     937             :                         bool *ellipsized) {
     938             : 
     939             :         int r;
     940           0 :         unsigned line = 0;
     941           0 :         bool need_seek = false;
     942           0 :         int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
     943             : 
     944           0 :         assert(j);
     945           0 :         assert(mode >= 0);
     946           0 :         assert(mode < _OUTPUT_MODE_MAX);
     947             : 
     948             :         /* Seek to end */
     949           0 :         r = sd_journal_seek_tail(j);
     950           0 :         if (r < 0)
     951           0 :                 return log_error_errno(r, "Failed to seek to tail: %m");
     952             : 
     953           0 :         r = sd_journal_previous_skip(j, how_many);
     954           0 :         if (r < 0)
     955           0 :                 return log_error_errno(r, "Failed to skip previous: %m");
     956             : 
     957             :         for (;;) {
     958             :                 for (;;) {
     959             :                         usec_t usec;
     960             : 
     961           0 :                         if (need_seek) {
     962           0 :                                 r = sd_journal_next(j);
     963           0 :                                 if (r < 0)
     964           0 :                                         return log_error_errno(r, "Failed to iterate through journal: %m");
     965             :                         }
     966             : 
     967           0 :                         if (r == 0)
     968           0 :                                 break;
     969             : 
     970           0 :                         need_seek = true;
     971             : 
     972           0 :                         if (not_before > 0) {
     973           0 :                                 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
     974             : 
     975             :                                 /* -ESTALE is returned if the
     976             :                                    timestamp is not from this boot */
     977           0 :                                 if (r == -ESTALE)
     978           0 :                                         continue;
     979           0 :                                 else if (r < 0)
     980           0 :                                         return log_error_errno(r, "Failed to get journal time: %m");
     981             : 
     982           0 :                                 if (usec < not_before)
     983           0 :                                         continue;
     984             :                         }
     985             : 
     986           0 :                         line ++;
     987           0 :                         maybe_print_begin_newline(f, &flags);
     988             : 
     989           0 :                         r = output_journal(f, j, mode, n_columns, flags, ellipsized);
     990           0 :                         if (r < 0)
     991           0 :                                 return r;
     992           0 :                 }
     993             : 
     994           0 :                 if (warn_cutoff && line < how_many && not_before > 0) {
     995             :                         sd_id128_t boot_id;
     996           0 :                         usec_t cutoff = 0;
     997             : 
     998             :                         /* Check whether the cutoff line is too early */
     999             : 
    1000           0 :                         r = sd_id128_get_boot(&boot_id);
    1001           0 :                         if (r < 0)
    1002           0 :                                 return log_error_errno(r, "Failed to get boot id: %m");
    1003             : 
    1004           0 :                         r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
    1005           0 :                         if (r < 0)
    1006           0 :                                 return log_error_errno(r, "Failed to get journal cutoff time: %m");
    1007             : 
    1008           0 :                         if (r > 0 && not_before < cutoff) {
    1009           0 :                                 maybe_print_begin_newline(f, &flags);
    1010           0 :                                 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
    1011             :                         }
    1012             : 
    1013           0 :                         warn_cutoff = false;
    1014             :                 }
    1015             : 
    1016           0 :                 if (!(flags & OUTPUT_FOLLOW))
    1017           0 :                         break;
    1018             : 
    1019           0 :                 r = sd_journal_wait(j, USEC_INFINITY);
    1020           0 :                 if (r < 0)
    1021           0 :                         return log_error_errno(r, "Failed to wait for journal: %m");
    1022             : 
    1023           0 :         }
    1024             : 
    1025           0 :         return 0;
    1026             : }
    1027             : 
    1028           0 : int add_matches_for_unit(sd_journal *j, const char *unit) {
    1029             :         int r;
    1030             :         char *m1, *m2, *m3, *m4;
    1031             : 
    1032           0 :         assert(j);
    1033           0 :         assert(unit);
    1034             : 
    1035           0 :         m1 = strjoina("_SYSTEMD_UNIT=", unit);
    1036           0 :         m2 = strjoina("COREDUMP_UNIT=", unit);
    1037           0 :         m3 = strjoina("UNIT=", unit);
    1038           0 :         m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
    1039             : 
    1040           0 :         (void)(
    1041             :             /* Look for messages from the service itself */
    1042           0 :             (r = sd_journal_add_match(j, m1, 0)) ||
    1043             : 
    1044             :             /* Look for coredumps of the service */
    1045           0 :             (r = sd_journal_add_disjunction(j)) ||
    1046           0 :             (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
    1047           0 :             (r = sd_journal_add_match(j, "_UID=0", 0)) ||
    1048           0 :             (r = sd_journal_add_match(j, m2, 0)) ||
    1049             : 
    1050             :              /* Look for messages from PID 1 about this service */
    1051           0 :             (r = sd_journal_add_disjunction(j)) ||
    1052           0 :             (r = sd_journal_add_match(j, "_PID=1", 0)) ||
    1053           0 :             (r = sd_journal_add_match(j, m3, 0)) ||
    1054             : 
    1055             :             /* Look for messages from authorized daemons about this service */
    1056           0 :             (r = sd_journal_add_disjunction(j)) ||
    1057           0 :             (r = sd_journal_add_match(j, "_UID=0", 0)) ||
    1058             :             (r = sd_journal_add_match(j, m4, 0))
    1059             :         );
    1060             : 
    1061           0 :         if (r == 0 && endswith(unit, ".slice")) {
    1062           0 :                 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
    1063             : 
    1064             :                 /* Show all messages belonging to a slice */
    1065           0 :                 (void)(
    1066           0 :                         (r = sd_journal_add_disjunction(j)) ||
    1067             :                         (r = sd_journal_add_match(j, m5, 0))
    1068             :                         );
    1069             :         }
    1070             : 
    1071           0 :         return r;
    1072             : }
    1073             : 
    1074           0 : int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
    1075             :         int r;
    1076             :         char *m1, *m2, *m3, *m4;
    1077             :         char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
    1078             : 
    1079           0 :         assert(j);
    1080           0 :         assert(unit);
    1081             : 
    1082           0 :         m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
    1083           0 :         m2 = strjoina("USER_UNIT=", unit);
    1084           0 :         m3 = strjoina("COREDUMP_USER_UNIT=", unit);
    1085           0 :         m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
    1086           0 :         sprintf(muid, "_UID="UID_FMT, uid);
    1087             : 
    1088           0 :         (void) (
    1089             :                 /* Look for messages from the user service itself */
    1090           0 :                 (r = sd_journal_add_match(j, m1, 0)) ||
    1091           0 :                 (r = sd_journal_add_match(j, muid, 0)) ||
    1092             : 
    1093             :                 /* Look for messages from systemd about this service */
    1094           0 :                 (r = sd_journal_add_disjunction(j)) ||
    1095           0 :                 (r = sd_journal_add_match(j, m2, 0)) ||
    1096           0 :                 (r = sd_journal_add_match(j, muid, 0)) ||
    1097             : 
    1098             :                 /* Look for coredumps of the service */
    1099           0 :                 (r = sd_journal_add_disjunction(j)) ||
    1100           0 :                 (r = sd_journal_add_match(j, m3, 0)) ||
    1101           0 :                 (r = sd_journal_add_match(j, muid, 0)) ||
    1102           0 :                 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
    1103             : 
    1104             :                 /* Look for messages from authorized daemons about this service */
    1105           0 :                 (r = sd_journal_add_disjunction(j)) ||
    1106           0 :                 (r = sd_journal_add_match(j, m4, 0)) ||
    1107           0 :                 (r = sd_journal_add_match(j, muid, 0)) ||
    1108             :                 (r = sd_journal_add_match(j, "_UID=0", 0))
    1109             :         );
    1110             : 
    1111           0 :         if (r == 0 && endswith(unit, ".slice")) {
    1112           0 :                 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
    1113             : 
    1114             :                 /* Show all messages belonging to a slice */
    1115           0 :                 (void)(
    1116           0 :                         (r = sd_journal_add_disjunction(j)) ||
    1117           0 :                         (r = sd_journal_add_match(j, m5, 0)) ||
    1118             :                         (r = sd_journal_add_match(j, muid, 0))
    1119             :                         );
    1120             :         }
    1121             : 
    1122           0 :         return r;
    1123             : }
    1124             : 
    1125           0 : static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
    1126           0 :         _cleanup_close_pair_ int pair[2] = { -1, -1 };
    1127           0 :         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
    1128             :         pid_t pid, child;
    1129             :         siginfo_t si;
    1130             :         char buf[37];
    1131             :         ssize_t k;
    1132             :         int r;
    1133             : 
    1134           0 :         assert(machine);
    1135           0 :         assert(boot_id);
    1136             : 
    1137           0 :         if (!machine_name_is_valid(machine))
    1138           0 :                 return -EINVAL;
    1139             : 
    1140           0 :         r = container_get_leader(machine, &pid);
    1141           0 :         if (r < 0)
    1142           0 :                 return r;
    1143             : 
    1144           0 :         r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
    1145           0 :         if (r < 0)
    1146           0 :                 return r;
    1147             : 
    1148           0 :         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
    1149           0 :                 return -errno;
    1150             : 
    1151           0 :         child = fork();
    1152           0 :         if (child < 0)
    1153           0 :                 return -errno;
    1154             : 
    1155           0 :         if (child == 0) {
    1156             :                 int fd;
    1157             : 
    1158           0 :                 pair[0] = safe_close(pair[0]);
    1159             : 
    1160           0 :                 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
    1161           0 :                 if (r < 0)
    1162           0 :                         _exit(EXIT_FAILURE);
    1163             : 
    1164           0 :                 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
    1165           0 :                 if (fd < 0)
    1166           0 :                         _exit(EXIT_FAILURE);
    1167             : 
    1168           0 :                 r = loop_read_exact(fd, buf, 36, false);
    1169           0 :                 safe_close(fd);
    1170           0 :                 if (r < 0)
    1171           0 :                         _exit(EXIT_FAILURE);
    1172             : 
    1173           0 :                 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
    1174           0 :                 if (k != 36)
    1175           0 :                         _exit(EXIT_FAILURE);
    1176             : 
    1177           0 :                 _exit(EXIT_SUCCESS);
    1178             :         }
    1179             : 
    1180           0 :         pair[1] = safe_close(pair[1]);
    1181             : 
    1182           0 :         r = wait_for_terminate(child, &si);
    1183           0 :         if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
    1184           0 :                 return r < 0 ? r : -EIO;
    1185             : 
    1186           0 :         k = recv(pair[0], buf, 36, 0);
    1187           0 :         if (k != 36)
    1188           0 :                 return -EIO;
    1189             : 
    1190           0 :         buf[36] = 0;
    1191           0 :         r = sd_id128_from_string(buf, boot_id);
    1192           0 :         if (r < 0)
    1193           0 :                 return r;
    1194             : 
    1195           0 :         return 0;
    1196             : }
    1197             : 
    1198           0 : int add_match_this_boot(sd_journal *j, const char *machine) {
    1199           0 :         char match[9+32+1] = "_BOOT_ID=";
    1200             :         sd_id128_t boot_id;
    1201             :         int r;
    1202             : 
    1203           0 :         assert(j);
    1204             : 
    1205           0 :         if (machine) {
    1206           0 :                 r = get_boot_id_for_machine(machine, &boot_id);
    1207           0 :                 if (r < 0)
    1208           0 :                         return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
    1209             :         } else {
    1210           0 :                 r = sd_id128_get_boot(&boot_id);
    1211           0 :                 if (r < 0)
    1212           0 :                         return log_error_errno(r, "Failed to get boot id: %m");
    1213             :         }
    1214             : 
    1215           0 :         sd_id128_to_string(boot_id, match + 9);
    1216           0 :         r = sd_journal_add_match(j, match, strlen(match));
    1217           0 :         if (r < 0)
    1218           0 :                 return log_error_errno(r, "Failed to add match: %m");
    1219             : 
    1220           0 :         r = sd_journal_add_conjunction(j);
    1221           0 :         if (r < 0)
    1222           0 :                 return log_error_errno(r, "Failed to add conjunction: %m");
    1223             : 
    1224           0 :         return 0;
    1225             : }
    1226             : 
    1227           0 : int show_journal_by_unit(
    1228             :                 FILE *f,
    1229             :                 const char *unit,
    1230             :                 OutputMode mode,
    1231             :                 unsigned n_columns,
    1232             :                 usec_t not_before,
    1233             :                 unsigned how_many,
    1234             :                 uid_t uid,
    1235             :                 OutputFlags flags,
    1236             :                 int journal_open_flags,
    1237             :                 bool system_unit,
    1238             :                 bool *ellipsized) {
    1239             : 
    1240           0 :         _cleanup_journal_close_ sd_journal*j = NULL;
    1241             :         int r;
    1242             : 
    1243           0 :         assert(mode >= 0);
    1244           0 :         assert(mode < _OUTPUT_MODE_MAX);
    1245           0 :         assert(unit);
    1246             : 
    1247           0 :         if (how_many <= 0)
    1248           0 :                 return 0;
    1249             : 
    1250           0 :         r = sd_journal_open(&j, journal_open_flags);
    1251           0 :         if (r < 0)
    1252           0 :                 return log_error_errno(r, "Failed to open journal: %m");
    1253             : 
    1254           0 :         r = add_match_this_boot(j, NULL);
    1255           0 :         if (r < 0)
    1256           0 :                 return r;
    1257             : 
    1258           0 :         if (system_unit)
    1259           0 :                 r = add_matches_for_unit(j, unit);
    1260             :         else
    1261           0 :                 r = add_matches_for_user_unit(j, unit, uid);
    1262           0 :         if (r < 0)
    1263           0 :                 return log_error_errno(r, "Failed to add unit matches: %m");
    1264             : 
    1265           0 :         if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
    1266           0 :                 _cleanup_free_ char *filter;
    1267             : 
    1268           0 :                 filter = journal_make_match_string(j);
    1269           0 :                 if (!filter)
    1270           0 :                         return log_oom();
    1271             : 
    1272           0 :                 log_debug("Journal filter: %s", filter);
    1273             :         }
    1274             : 
    1275           0 :         return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
    1276             : }
    1277             : 
    1278             : static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
    1279             :         [OUTPUT_SHORT] = "short",
    1280             :         [OUTPUT_SHORT_ISO] = "short-iso",
    1281             :         [OUTPUT_SHORT_PRECISE] = "short-precise",
    1282             :         [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
    1283             :         [OUTPUT_VERBOSE] = "verbose",
    1284             :         [OUTPUT_EXPORT] = "export",
    1285             :         [OUTPUT_JSON] = "json",
    1286             :         [OUTPUT_JSON_PRETTY] = "json-pretty",
    1287             :         [OUTPUT_JSON_SSE] = "json-sse",
    1288             :         [OUTPUT_CAT] = "cat"
    1289             : };
    1290             : 
    1291          24 : DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);

Generated by: LCOV version 1.11