chiark / gitweb /
journalctl: add --verify-seed= switch to specify seed value
[elogind.git] / src / journal / journalctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 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 <fcntl.h>
23 #include <errno.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/poll.h>
30 #include <time.h>
31 #include <getopt.h>
32 #include <sys/stat.h>
33
34 #include <systemd/sd-journal.h>
35
36 #include "log.h"
37 #include "util.h"
38 #include "path-util.h"
39 #include "build.h"
40 #include "pager.h"
41 #include "logs-show.h"
42 #include "strv.h"
43 #include "journal-internal.h"
44 #include "journal-def.h"
45 #include "journal-verify.h"
46 #include "journal-authenticate.h"
47 #include "fsprg.h"
48
49 #define DEFAULT_FSPRG_INTERVAL_USEC (15*USEC_PER_MINUTE)
50
51 static OutputMode arg_output = OUTPUT_SHORT;
52 static bool arg_follow = false;
53 static bool arg_show_all = false;
54 static bool arg_no_pager = false;
55 static int arg_lines = -1;
56 static bool arg_no_tail = false;
57 static bool arg_quiet = false;
58 static bool arg_local = false;
59 static bool arg_this_boot = false;
60 static const char *arg_directory = NULL;
61 static int arg_priorities = 0xFF;
62 static const char *arg_verify_seed = NULL;
63
64 static enum {
65         ACTION_SHOW,
66         ACTION_NEW_ID128,
67         ACTION_PRINT_HEADER,
68         ACTION_SETUP_KEYS,
69         ACTION_VERIFY
70 } arg_action = ACTION_SHOW;
71
72 static int help(void) {
73
74         printf("%s [OPTIONS...] [MATCH]\n\n"
75                "Send control commands to or query the journal.\n\n"
76                "  -h --help              Show this help\n"
77                "     --version           Show package version\n"
78                "     --no-pager          Do not pipe output into a pager\n"
79                "  -a --all               Show all fields, including long and unprintable\n"
80                "  -f --follow            Follow journal\n"
81                "  -n --lines=INTEGER     Journal entries to show\n"
82                "     --no-tail           Show all lines, even in follow mode\n"
83                "  -o --output=STRING     Change journal output mode (short, short-monotonic,\n"
84                "                         verbose, export, json, cat)\n"
85                "  -q --quiet             Don't show privilege warning\n"
86                "  -l --local             Only local entries\n"
87                "  -b --this-boot         Show data only from current boot\n"
88                "  -D --directory=PATH    Show journal files from directory\n"
89                "  -p --priority=RANGE    Show only messages within the specified priority range\n\n"
90                "Commands:\n"
91                "     --new-id128         Generate a new 128 Bit ID\n"
92                "     --header            Show journal header information\n"
93                "     --verify            Verify journal file consistency\n"
94                "     --verify-seed=SEED  Specify FSPRG seed for verification\n"
95                "     --setup-keys        Generate new FSPRG key and seed\n",
96                program_invocation_short_name);
97
98         return 0;
99 }
100
101 static int parse_argv(int argc, char *argv[]) {
102
103         enum {
104                 ARG_VERSION = 0x100,
105                 ARG_NO_PAGER,
106                 ARG_NO_TAIL,
107                 ARG_NEW_ID128,
108                 ARG_HEADER,
109                 ARG_SETUP_KEYS,
110                 ARG_VERIFY,
111                 ARG_VERIFY_SEED
112         };
113
114         static const struct option options[] = {
115                 { "help",        no_argument,       NULL, 'h'             },
116                 { "version" ,    no_argument,       NULL, ARG_VERSION     },
117                 { "no-pager",    no_argument,       NULL, ARG_NO_PAGER    },
118                 { "follow",      no_argument,       NULL, 'f'             },
119                 { "output",      required_argument, NULL, 'o'             },
120                 { "all",         no_argument,       NULL, 'a'             },
121                 { "lines",       required_argument, NULL, 'n'             },
122                 { "no-tail",     no_argument,       NULL, ARG_NO_TAIL     },
123                 { "new-id128",   no_argument,       NULL, ARG_NEW_ID128   },
124                 { "quiet",       no_argument,       NULL, 'q'             },
125                 { "local",       no_argument,       NULL, 'l'             },
126                 { "this-boot",   no_argument,       NULL, 'b'             },
127                 { "directory",   required_argument, NULL, 'D'             },
128                 { "header",      no_argument,       NULL, ARG_HEADER      },
129                 { "priority",    no_argument,       NULL, 'p'             },
130                 { "setup-keys",  no_argument,       NULL, ARG_SETUP_KEYS  },
131                 { "verify",      no_argument,       NULL, ARG_VERIFY      },
132                 { "verify-seed", required_argument, NULL, ARG_VERIFY_SEED },
133                 { NULL,          0,                 NULL, 0               }
134         };
135
136         int c, r;
137
138         assert(argc >= 0);
139         assert(argv);
140
141         while ((c = getopt_long(argc, argv, "hfo:an:qlbD:p:", options, NULL)) >= 0) {
142
143                 switch (c) {
144
145                 case 'h':
146                         help();
147                         return 0;
148
149                 case ARG_VERSION:
150                         puts(PACKAGE_STRING);
151                         puts(DISTRIBUTION);
152                         puts(SYSTEMD_FEATURES);
153                         return 0;
154
155                 case ARG_NO_PAGER:
156                         arg_no_pager = true;
157                         break;
158
159                 case 'f':
160                         arg_follow = true;
161                         break;
162
163                 case 'o':
164                         arg_output =  output_mode_from_string(optarg);
165                         if (arg_output < 0) {
166                                 log_error("Unknown output '%s'.", optarg);
167                                 return -EINVAL;
168                         }
169
170                         break;
171
172                 case 'a':
173                         arg_show_all = true;
174                         break;
175
176                 case 'n':
177                         r = safe_atoi(optarg, &arg_lines);
178                         if (r < 0 || arg_lines < 0) {
179                                 log_error("Failed to parse lines '%s'", optarg);
180                                 return -EINVAL;
181                         }
182                         break;
183
184                 case ARG_NO_TAIL:
185                         arg_no_tail = true;
186                         break;
187
188                 case ARG_NEW_ID128:
189                         arg_action = ACTION_NEW_ID128;
190                         break;
191
192                 case 'q':
193                         arg_quiet = true;
194                         break;
195
196                 case 'l':
197                         arg_local = true;
198                         break;
199
200                 case 'b':
201                         arg_this_boot = true;
202                         break;
203
204                 case 'D':
205                         arg_directory = optarg;
206                         break;
207
208                 case ARG_HEADER:
209                         arg_action = ACTION_PRINT_HEADER;
210                         break;
211
212                 case ARG_SETUP_KEYS:
213                         arg_action = ACTION_SETUP_KEYS;
214                         break;
215
216                 case ARG_VERIFY:
217                         arg_action = ACTION_VERIFY;
218                         break;
219
220                 case ARG_VERIFY_SEED:
221                         arg_action = ACTION_VERIFY;
222                         arg_verify_seed = optarg;
223                         break;
224
225                 case 'p': {
226                         const char *dots;
227
228                         dots = strstr(optarg, "..");
229                         if (dots) {
230                                 char *a;
231                                 int from, to, i;
232
233                                 /* a range */
234                                 a = strndup(optarg, dots - optarg);
235                                 if (!a)
236                                         return log_oom();
237
238                                 from = log_level_from_string(a);
239                                 to = log_level_from_string(dots + 2);
240                                 free(a);
241
242                                 if (from < 0 || to < 0) {
243                                         log_error("Failed to parse log level range %s", optarg);
244                                         return -EINVAL;
245                                 }
246
247                                 arg_priorities = 0;
248
249                                 if (from < to) {
250                                         for (i = from; i <= to; i++)
251                                                 arg_priorities |= 1 << i;
252                                 } else {
253                                         for (i = to; i <= from; i++)
254                                                 arg_priorities |= 1 << i;
255                                 }
256
257                         } else {
258                                 int p, i;
259
260                                 p = log_level_from_string(optarg);
261                                 if (p < 0) {
262                                         log_error("Unknown log level %s", optarg);
263                                         return -EINVAL;
264                                 }
265
266                                 arg_priorities = 0;
267
268                                 for (i = 0; i <= p; i++)
269                                         arg_priorities |= 1 << i;
270                         }
271
272                         break;
273                 }
274
275                 case '?':
276                         return -EINVAL;
277
278                 default:
279                         log_error("Unknown option code %c", c);
280                         return -EINVAL;
281                 }
282         }
283
284         if (arg_follow && !arg_no_tail && arg_lines < 0)
285                 arg_lines = 10;
286
287         return 1;
288 }
289
290 static bool on_tty(void) {
291         static int t = -1;
292
293         /* Note that this is invoked relatively early, before we start
294          * the pager. That means the value we return reflects whether
295          * we originally were started on a tty, not if we currently
296          * are. But this is intended, since we want colour and so on
297          * when run in our own pager. */
298
299         if (_unlikely_(t < 0))
300                 t = isatty(STDOUT_FILENO) > 0;
301
302         return t;
303 }
304
305 static int generate_new_id128(void) {
306         sd_id128_t id;
307         int r;
308         unsigned i;
309
310         r = sd_id128_randomize(&id);
311         if (r < 0) {
312                 log_error("Failed to generate ID: %s", strerror(-r));
313                 return r;
314         }
315
316         printf("As string:\n"
317                SD_ID128_FORMAT_STR "\n\n"
318                "As UUID:\n"
319                "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
320                "As macro:\n"
321               "#define MESSAGE_XYZ SD_ID128_MAKE(",
322                SD_ID128_FORMAT_VAL(id),
323                SD_ID128_FORMAT_VAL(id));
324
325         for (i = 0; i < 16; i++)
326                 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
327
328         fputs(")\n", stdout);
329
330         return 0;
331 }
332
333 static int add_matches(sd_journal *j, char **args) {
334         char **i;
335         int r;
336
337         assert(j);
338
339         STRV_FOREACH(i, args) {
340
341                 if (streq(*i, "+"))
342                         r = sd_journal_add_disjunction(j);
343                 else if (path_is_absolute(*i)) {
344                         char *p, *t = NULL;
345                         const char *path;
346                         struct stat st;
347
348                         p = canonicalize_file_name(*i);
349                         path = p ? p : *i;
350
351                         if (stat(path, &st) < 0)  {
352                                 free(p);
353                                 log_error("Couldn't stat file: %m");
354                                 return -errno;
355                         }
356
357                         if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
358                                 t = strappend("_EXE=", path);
359                         else if (S_ISCHR(st.st_mode))
360                                 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
361                         else if (S_ISBLK(st.st_mode))
362                                 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
363                         else {
364                                 free(p);
365                                 log_error("File is not a device node, regular file or is not executable: %s", *i);
366                                 return -EINVAL;
367                         }
368
369                         free(p);
370
371                         if (!t)
372                                 return log_oom();
373
374                         r = sd_journal_add_match(j, t, 0);
375                         free(t);
376                 } else
377                         r = sd_journal_add_match(j, *i, 0);
378
379                 if (r < 0) {
380                         log_error("Failed to add match '%s': %s", *i, strerror(-r));
381                         return r;
382                 }
383         }
384
385         return 0;
386 }
387
388 static int add_this_boot(sd_journal *j) {
389         char match[9+32+1] = "_BOOT_ID=";
390         sd_id128_t boot_id;
391         int r;
392
393         assert(j);
394
395         if (!arg_this_boot)
396                 return 0;
397
398         r = sd_id128_get_boot(&boot_id);
399         if (r < 0) {
400                 log_error("Failed to get boot id: %s", strerror(-r));
401                 return r;
402         }
403
404         sd_id128_to_string(boot_id, match + 9);
405         r = sd_journal_add_match(j, match, strlen(match));
406         if (r < 0) {
407                 log_error("Failed to add match: %s", strerror(-r));
408                 return r;
409         }
410
411         return 0;
412 }
413
414 static int add_priorities(sd_journal *j) {
415         char match[] = "PRIORITY=0";
416         int i, r;
417
418         assert(j);
419
420         if (arg_priorities == 0xFF)
421                 return 0;
422
423         for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
424                 if (arg_priorities & (1 << i)) {
425                         match[sizeof(match)-2] = '0' + i;
426
427                         log_info("adding match %s", match);
428
429                         r = sd_journal_add_match(j, match, strlen(match));
430                         if (r < 0) {
431                                 log_error("Failed to add match: %s", strerror(-r));
432                                 return r;
433                         }
434                 }
435
436         return 0;
437 }
438
439 static int setup_keys(void) {
440 #ifdef HAVE_GCRYPT
441         size_t mpk_size, seed_size, state_size, i;
442         uint8_t *mpk, *seed, *state;
443         ssize_t l;
444         int fd = -1, r;
445         sd_id128_t machine, boot;
446         char *p = NULL, *k = NULL;
447         struct FSPRGHeader h;
448         uint64_t n, interval;
449
450         r = sd_id128_get_machine(&machine);
451         if (r < 0) {
452                 log_error("Failed to get machine ID: %s", strerror(-r));
453                 return r;
454         }
455
456         r = sd_id128_get_boot(&boot);
457         if (r < 0) {
458                 log_error("Failed to get boot ID: %s", strerror(-r));
459                 return r;
460         }
461
462         if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fsprg",
463                      SD_ID128_FORMAT_VAL(machine)) < 0)
464                 return log_oom();
465
466         if (access(p, F_OK) >= 0) {
467                 log_error("Evolving key file %s exists already.", p);
468                 r = -EEXIST;
469                 goto finish;
470         }
471
472         if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fsprg.tmp.XXXXXX",
473                      SD_ID128_FORMAT_VAL(machine)) < 0) {
474                 r = log_oom();
475                 goto finish;
476         }
477
478         mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
479         mpk = alloca(mpk_size);
480
481         seed_size = FSPRG_RECOMMENDED_SEEDLEN;
482         seed = alloca(seed_size);
483
484         state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
485         state = alloca(state_size);
486
487         fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
488         if (fd < 0) {
489                 log_error("Failed to open /dev/random: %m");
490                 r = -errno;
491                 goto finish;
492         }
493
494         log_info("Generating seed...");
495         l = loop_read(fd, seed, seed_size, true);
496         if (l < 0 || (size_t) l != seed_size) {
497                 log_error("Failed to read random seed: %s", strerror(EIO));
498                 r = -EIO;
499                 goto finish;
500         }
501
502         log_info("Generating key pair...");
503         FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
504
505         log_info("Generating evolving key...");
506         FSPRG_GenState0(state, mpk, seed, seed_size);
507
508         interval = DEFAULT_FSPRG_INTERVAL_USEC;
509         n = now(CLOCK_REALTIME);
510         n /= interval;
511
512         close_nointr_nofail(fd);
513         fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
514         if (fd < 0) {
515                 log_error("Failed to open %s: %m", k);
516                 r = -errno;
517                 goto finish;
518         }
519
520         zero(h);
521         memcpy(h.signature, "KSHHRHLP", 8);
522         h.machine_id = machine;
523         h.boot_id = boot;
524         h.header_size = htole64(sizeof(h));
525         h.fsprg_start_usec = htole64(n * interval);
526         h.fsprg_interval_usec = htole64(interval);
527         h.secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
528         h.state_size = htole64(state_size);
529
530         l = loop_write(fd, &h, sizeof(h), false);
531         if (l < 0 || (size_t) l != sizeof(h)) {
532                 log_error("Failed to write header: %s", strerror(EIO));
533                 r = -EIO;
534                 goto finish;
535         }
536
537         l = loop_write(fd, state, state_size, false);
538         if (l < 0 || (size_t) l != state_size) {
539                 log_error("Failed to write state: %s", strerror(EIO));
540                 r = -EIO;
541                 goto finish;
542         }
543
544         if (link(k, p) < 0) {
545                 log_error("Failed to link file: %m");
546                 r = -errno;
547                 goto finish;
548         }
549
550         if (isatty(STDOUT_FILENO)) {
551                 fprintf(stderr,
552                         "\n"
553                         "The new key pair has been generated. The evolving key has been written to the\n"
554                         "following file. It will be used to protect local journal files. This file\n"
555                         "should be kept secret. It should not be used on multiple hosts.\n"
556                         "\n"
557                         "\t%s\n"
558                         "\n"
559                         "Please write down the following " ANSI_HIGHLIGHT_ON "secret" ANSI_HIGHLIGHT_OFF " seed value. It should not be stored\n"
560                         "locally on disk, and may be used to verify journal files from this host.\n"
561                         "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
562                 fflush(stderr);
563         }
564         for (i = 0; i < seed_size; i++) {
565                 if (i > 0 && i % 3 == 0)
566                         putchar('-');
567                 printf("%02x", ((uint8_t*) seed)[i]);
568         }
569
570         printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) interval);
571
572         if (isatty(STDOUT_FILENO))
573                 fputs(ANSI_HIGHLIGHT_OFF "\n", stderr);
574
575         r = 0;
576
577 finish:
578         if (fd >= 0)
579                 close_nointr_nofail(fd);
580
581         if (k) {
582                 unlink(k);
583                 free(k);
584         }
585
586         free(p);
587
588         return r;
589 #else
590         log_error("Forward-secure journal verification not available.");
591 #endif
592 }
593
594 static int verify(sd_journal *j) {
595         int r = 0;
596         Iterator i;
597         JournalFile *f;
598
599         assert(j);
600
601         HASHMAP_FOREACH(f, j->files, i) {
602                 int k;
603
604                 if (!arg_verify_seed && journal_file_fsprg_enabled(f))
605                         log_warning("Journal file %s has authentication enabled but verification seed has not been passed using --verify-seed=.", f->path);
606
607                 k = journal_file_verify(f, arg_verify_seed);
608                 if (k < 0) {
609                         log_warning("FAIL: %s (%s)", f->path, strerror(-k));
610                         r = -r;
611                 } else
612                         log_info("PASS: %s", f->path);
613         }
614
615         return r;
616 }
617
618 int main(int argc, char *argv[]) {
619         int r;
620         sd_journal *j = NULL;
621         unsigned line = 0;
622         bool need_seek = false;
623         sd_id128_t previous_boot_id;
624         bool previous_boot_id_valid = false;
625         bool have_pager;
626
627         log_parse_environment();
628         log_open();
629
630         r = parse_argv(argc, argv);
631         if (r <= 0)
632                 goto finish;
633
634         if (arg_action == ACTION_NEW_ID128) {
635                 r = generate_new_id128();
636                 goto finish;
637         }
638
639         if (arg_action == ACTION_SETUP_KEYS) {
640                 r = setup_keys();
641                 goto finish;
642         }
643
644         if (arg_directory)
645                 r = sd_journal_open_directory(&j, arg_directory, 0);
646         else
647                 r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0);
648
649         if (r < 0) {
650                 log_error("Failed to open journal: %s", strerror(-r));
651                 goto finish;
652         }
653
654         if (arg_action == ACTION_VERIFY) {
655                 r = verify(j);
656                 goto finish;
657         }
658
659         if (arg_action == ACTION_PRINT_HEADER) {
660                 journal_print_header(j);
661                 r = 0;
662                 goto finish;
663         }
664
665 #ifdef HAVE_ACL
666         if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
667                 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
668 #endif
669
670         r = add_this_boot(j);
671         if (r < 0)
672                 goto finish;
673
674         r = add_matches(j, argv + optind);
675         if (r < 0)
676                 goto finish;
677
678         r = add_priorities(j);
679         if (r < 0)
680                 goto finish;
681
682         if (!arg_quiet) {
683                 usec_t start, end;
684                 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
685
686                 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
687                 if (r < 0) {
688                         log_error("Failed to get cutoff: %s", strerror(-r));
689                         goto finish;
690                 }
691
692                 if (r > 0) {
693                         if (arg_follow)
694                                 printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start));
695                         else
696                                 printf("Logs begin at %s, end at %s.\n",
697                                        format_timestamp(start_buf, sizeof(start_buf), start),
698                                        format_timestamp(end_buf, sizeof(end_buf), end));
699                 }
700         }
701
702         if (arg_lines >= 0) {
703                 r = sd_journal_seek_tail(j);
704                 if (r < 0) {
705                         log_error("Failed to seek to tail: %s", strerror(-r));
706                         goto finish;
707                 }
708
709                 r = sd_journal_previous_skip(j, arg_lines);
710         } else {
711                 r = sd_journal_seek_head(j);
712                 if (r < 0) {
713                         log_error("Failed to seek to head: %s", strerror(-r));
714                         goto finish;
715                 }
716
717                 r = sd_journal_next(j);
718         }
719
720         if (r < 0) {
721                 log_error("Failed to iterate through journal: %s", strerror(-r));
722                 goto finish;
723         }
724
725         on_tty();
726         have_pager = !arg_no_pager && !arg_follow && pager_open();
727
728         if (arg_output == OUTPUT_JSON) {
729                 fputc('[', stdout);
730                 fflush(stdout);
731         }
732
733         for (;;) {
734                 for (;;) {
735                         sd_id128_t boot_id;
736                         int flags =
737                                 arg_show_all * OUTPUT_SHOW_ALL |
738                                 have_pager * OUTPUT_FULL_WIDTH |
739                                 on_tty() * OUTPUT_COLOR;
740
741                         if (need_seek) {
742                                 r = sd_journal_next(j);
743                                 if (r < 0) {
744                                         log_error("Failed to iterate through journal: %s", strerror(-r));
745                                         goto finish;
746                                 }
747                         }
748
749                         if (r == 0)
750                                 break;
751
752                         r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
753                         if (r >= 0) {
754                                 if (previous_boot_id_valid &&
755                                     !sd_id128_equal(boot_id, previous_boot_id))
756                                         printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n");
757
758                                 previous_boot_id = boot_id;
759                                 previous_boot_id_valid = true;
760                         }
761
762                         line ++;
763
764                         r = output_journal(j, arg_output, line, 0, flags);
765                         if (r < 0)
766                                 goto finish;
767
768                         need_seek = true;
769                 }
770
771                 if (!arg_follow)
772                         break;
773
774                 r = sd_journal_wait(j, (uint64_t) -1);
775                 if (r < 0) {
776                         log_error("Couldn't wait for log event: %s", strerror(-r));
777                         goto finish;
778                 }
779         }
780
781         if (arg_output == OUTPUT_JSON)
782                 fputs("\n]\n", stdout);
783
784 finish:
785         if (j)
786                 sd_journal_close(j);
787
788         pager_close();
789
790         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
791 }