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 : }
|