]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/sd-journal.c
tty-ask-password: Split out password sending
[thirdparty/systemd.git] / src / journal / sd-journal.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 <errno.h>
23 #include <fcntl.h>
24 #include <linux/magic.h>
25 #include <poll.h>
26 #include <stddef.h>
27 #include <sys/inotify.h>
28 #include <sys/vfs.h>
29 #include <unistd.h>
30
31 #include "sd-journal.h"
32
33 #include "alloc-util.h"
34 #include "catalog.h"
35 #include "compress.h"
36 #include "dirent-util.h"
37 #include "fd-util.h"
38 #include "fileio.h"
39 #include "formats-util.h"
40 #include "fs-util.h"
41 #include "hashmap.h"
42 #include "hostname-util.h"
43 #include "io-util.h"
44 #include "journal-def.h"
45 #include "journal-file.h"
46 #include "journal-internal.h"
47 #include "list.h"
48 #include "lookup3.h"
49 #include "missing.h"
50 #include "path-util.h"
51 #include "replace-var.h"
52 #include "stat-util.h"
53 #include "stdio-util.h"
54 #include "string-util.h"
55 #include "strv.h"
56
57 #define JOURNAL_FILES_MAX 7168
58
59 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
60
61 #define REPLACE_VAR_MAX 256
62
63 #define DEFAULT_DATA_THRESHOLD (64*1024)
64
65 static void remove_file_real(sd_journal *j, JournalFile *f);
66
67 static bool journal_pid_changed(sd_journal *j) {
68 assert(j);
69
70 /* We don't support people creating a journal object and
71 * keeping it around over a fork(). Let's complain. */
72
73 return j->original_pid != getpid();
74 }
75
76 static int journal_put_error(sd_journal *j, int r, const char *path) {
77 char *copy;
78 int k;
79
80 /* Memorize an error we encountered, and store which
81 * file/directory it was generated from. Note that we store
82 * only *one* path per error code, as the error code is the
83 * key into the hashmap, and the path is the value. This means
84 * we keep track only of all error kinds, but not of all error
85 * locations. This has the benefit that the hashmap cannot
86 * grow beyond bounds.
87 *
88 * We return an error here only if we didn't manage to
89 * memorize the real error. */
90
91 if (r >= 0)
92 return r;
93
94 k = hashmap_ensure_allocated(&j->errors, NULL);
95 if (k < 0)
96 return k;
97
98 if (path) {
99 copy = strdup(path);
100 if (!copy)
101 return -ENOMEM;
102 } else
103 copy = NULL;
104
105 k = hashmap_put(j->errors, INT_TO_PTR(r), copy);
106 if (k < 0) {
107 free(copy);
108
109 if (k == -EEXIST)
110 return 0;
111
112 return k;
113 }
114
115 return 0;
116 }
117
118 static void detach_location(sd_journal *j) {
119 Iterator i;
120 JournalFile *f;
121
122 assert(j);
123
124 j->current_file = NULL;
125 j->current_field = 0;
126
127 ORDERED_HASHMAP_FOREACH(f, j->files, i)
128 journal_file_reset_location(f);
129 }
130
131 static void reset_location(sd_journal *j) {
132 assert(j);
133
134 detach_location(j);
135 zero(j->current_location);
136 }
137
138 static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
139 assert(l);
140 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
141 assert(f);
142 assert(o->object.type == OBJECT_ENTRY);
143
144 l->type = type;
145 l->seqnum = le64toh(o->entry.seqnum);
146 l->seqnum_id = f->header->seqnum_id;
147 l->realtime = le64toh(o->entry.realtime);
148 l->monotonic = le64toh(o->entry.monotonic);
149 l->boot_id = o->entry.boot_id;
150 l->xor_hash = le64toh(o->entry.xor_hash);
151
152 l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
153 }
154
155 static void set_location(sd_journal *j, JournalFile *f, Object *o) {
156 assert(j);
157 assert(f);
158 assert(o);
159
160 init_location(&j->current_location, LOCATION_DISCRETE, f, o);
161
162 j->current_file = f;
163 j->current_field = 0;
164
165 /* Let f know its candidate entry was picked. */
166 assert(f->location_type == LOCATION_SEEK);
167 f->location_type = LOCATION_DISCRETE;
168 }
169
170 static int match_is_valid(const void *data, size_t size) {
171 const char *b, *p;
172
173 assert(data);
174
175 if (size < 2)
176 return false;
177
178 if (startswith(data, "__"))
179 return false;
180
181 b = data;
182 for (p = b; p < b + size; p++) {
183
184 if (*p == '=')
185 return p > b;
186
187 if (*p == '_')
188 continue;
189
190 if (*p >= 'A' && *p <= 'Z')
191 continue;
192
193 if (*p >= '0' && *p <= '9')
194 continue;
195
196 return false;
197 }
198
199 return false;
200 }
201
202 static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
203 const uint8_t *a = _a, *b = _b;
204 size_t j;
205
206 for (j = 0; j < s && j < t; j++) {
207
208 if (a[j] != b[j])
209 return false;
210
211 if (a[j] == '=')
212 return true;
213 }
214
215 assert_not_reached("\"=\" not found");
216 }
217
218 static Match *match_new(Match *p, MatchType t) {
219 Match *m;
220
221 m = new0(Match, 1);
222 if (!m)
223 return NULL;
224
225 m->type = t;
226
227 if (p) {
228 m->parent = p;
229 LIST_PREPEND(matches, p->matches, m);
230 }
231
232 return m;
233 }
234
235 static void match_free(Match *m) {
236 assert(m);
237
238 while (m->matches)
239 match_free(m->matches);
240
241 if (m->parent)
242 LIST_REMOVE(matches, m->parent->matches, m);
243
244 free(m->data);
245 free(m);
246 }
247
248 static void match_free_if_empty(Match *m) {
249 if (!m || m->matches)
250 return;
251
252 match_free(m);
253 }
254
255 _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
256 Match *l3, *l4, *add_here = NULL, *m;
257 le64_t le_hash;
258
259 assert_return(j, -EINVAL);
260 assert_return(!journal_pid_changed(j), -ECHILD);
261 assert_return(data, -EINVAL);
262
263 if (size == 0)
264 size = strlen(data);
265
266 assert_return(match_is_valid(data, size), -EINVAL);
267
268 /* level 0: AND term
269 * level 1: OR terms
270 * level 2: AND terms
271 * level 3: OR terms
272 * level 4: concrete matches */
273
274 if (!j->level0) {
275 j->level0 = match_new(NULL, MATCH_AND_TERM);
276 if (!j->level0)
277 return -ENOMEM;
278 }
279
280 if (!j->level1) {
281 j->level1 = match_new(j->level0, MATCH_OR_TERM);
282 if (!j->level1)
283 return -ENOMEM;
284 }
285
286 if (!j->level2) {
287 j->level2 = match_new(j->level1, MATCH_AND_TERM);
288 if (!j->level2)
289 return -ENOMEM;
290 }
291
292 assert(j->level0->type == MATCH_AND_TERM);
293 assert(j->level1->type == MATCH_OR_TERM);
294 assert(j->level2->type == MATCH_AND_TERM);
295
296 le_hash = htole64(hash64(data, size));
297
298 LIST_FOREACH(matches, l3, j->level2->matches) {
299 assert(l3->type == MATCH_OR_TERM);
300
301 LIST_FOREACH(matches, l4, l3->matches) {
302 assert(l4->type == MATCH_DISCRETE);
303
304 /* Exactly the same match already? Then ignore
305 * this addition */
306 if (l4->le_hash == le_hash &&
307 l4->size == size &&
308 memcmp(l4->data, data, size) == 0)
309 return 0;
310
311 /* Same field? Then let's add this to this OR term */
312 if (same_field(data, size, l4->data, l4->size)) {
313 add_here = l3;
314 break;
315 }
316 }
317
318 if (add_here)
319 break;
320 }
321
322 if (!add_here) {
323 add_here = match_new(j->level2, MATCH_OR_TERM);
324 if (!add_here)
325 goto fail;
326 }
327
328 m = match_new(add_here, MATCH_DISCRETE);
329 if (!m)
330 goto fail;
331
332 m->le_hash = le_hash;
333 m->size = size;
334 m->data = memdup(data, size);
335 if (!m->data)
336 goto fail;
337
338 detach_location(j);
339
340 return 0;
341
342 fail:
343 match_free_if_empty(add_here);
344 match_free_if_empty(j->level2);
345 match_free_if_empty(j->level1);
346 match_free_if_empty(j->level0);
347
348 return -ENOMEM;
349 }
350
351 _public_ int sd_journal_add_conjunction(sd_journal *j) {
352 assert_return(j, -EINVAL);
353 assert_return(!journal_pid_changed(j), -ECHILD);
354
355 if (!j->level0)
356 return 0;
357
358 if (!j->level1)
359 return 0;
360
361 if (!j->level1->matches)
362 return 0;
363
364 j->level1 = NULL;
365 j->level2 = NULL;
366
367 return 0;
368 }
369
370 _public_ int sd_journal_add_disjunction(sd_journal *j) {
371 assert_return(j, -EINVAL);
372 assert_return(!journal_pid_changed(j), -ECHILD);
373
374 if (!j->level0)
375 return 0;
376
377 if (!j->level1)
378 return 0;
379
380 if (!j->level2)
381 return 0;
382
383 if (!j->level2->matches)
384 return 0;
385
386 j->level2 = NULL;
387 return 0;
388 }
389
390 static char *match_make_string(Match *m) {
391 char *p, *r;
392 Match *i;
393 bool enclose = false;
394
395 if (!m)
396 return strdup("none");
397
398 if (m->type == MATCH_DISCRETE)
399 return strndup(m->data, m->size);
400
401 p = NULL;
402 LIST_FOREACH(matches, i, m->matches) {
403 char *t, *k;
404
405 t = match_make_string(i);
406 if (!t) {
407 free(p);
408 return NULL;
409 }
410
411 if (p) {
412 k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t, NULL);
413 free(p);
414 free(t);
415
416 if (!k)
417 return NULL;
418
419 p = k;
420
421 enclose = true;
422 } else
423 p = t;
424 }
425
426 if (enclose) {
427 r = strjoin("(", p, ")", NULL);
428 free(p);
429 return r;
430 }
431
432 return p;
433 }
434
435 char *journal_make_match_string(sd_journal *j) {
436 assert(j);
437
438 return match_make_string(j->level0);
439 }
440
441 _public_ void sd_journal_flush_matches(sd_journal *j) {
442 if (!j)
443 return;
444
445 if (j->level0)
446 match_free(j->level0);
447
448 j->level0 = j->level1 = j->level2 = NULL;
449
450 detach_location(j);
451 }
452
453 _pure_ static int compare_with_location(JournalFile *f, Location *l) {
454 assert(f);
455 assert(l);
456 assert(f->location_type == LOCATION_SEEK);
457 assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
458
459 if (l->monotonic_set &&
460 sd_id128_equal(f->current_boot_id, l->boot_id) &&
461 l->realtime_set &&
462 f->current_realtime == l->realtime &&
463 l->xor_hash_set &&
464 f->current_xor_hash == l->xor_hash)
465 return 0;
466
467 if (l->seqnum_set &&
468 sd_id128_equal(f->header->seqnum_id, l->seqnum_id)) {
469
470 if (f->current_seqnum < l->seqnum)
471 return -1;
472 if (f->current_seqnum > l->seqnum)
473 return 1;
474 }
475
476 if (l->monotonic_set &&
477 sd_id128_equal(f->current_boot_id, l->boot_id)) {
478
479 if (f->current_monotonic < l->monotonic)
480 return -1;
481 if (f->current_monotonic > l->monotonic)
482 return 1;
483 }
484
485 if (l->realtime_set) {
486
487 if (f->current_realtime < l->realtime)
488 return -1;
489 if (f->current_realtime > l->realtime)
490 return 1;
491 }
492
493 if (l->xor_hash_set) {
494
495 if (f->current_xor_hash < l->xor_hash)
496 return -1;
497 if (f->current_xor_hash > l->xor_hash)
498 return 1;
499 }
500
501 return 0;
502 }
503
504 static int next_for_match(
505 sd_journal *j,
506 Match *m,
507 JournalFile *f,
508 uint64_t after_offset,
509 direction_t direction,
510 Object **ret,
511 uint64_t *offset) {
512
513 int r;
514 uint64_t np = 0;
515 Object *n;
516
517 assert(j);
518 assert(m);
519 assert(f);
520
521 if (m->type == MATCH_DISCRETE) {
522 uint64_t dp;
523
524 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
525 if (r <= 0)
526 return r;
527
528 return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset);
529
530 } else if (m->type == MATCH_OR_TERM) {
531 Match *i;
532
533 /* Find the earliest match beyond after_offset */
534
535 LIST_FOREACH(matches, i, m->matches) {
536 uint64_t cp;
537
538 r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
539 if (r < 0)
540 return r;
541 else if (r > 0) {
542 if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
543 np = cp;
544 }
545 }
546
547 if (np == 0)
548 return 0;
549
550 } else if (m->type == MATCH_AND_TERM) {
551 Match *i, *last_moved;
552
553 /* Always jump to the next matching entry and repeat
554 * this until we find an offset that matches for all
555 * matches. */
556
557 if (!m->matches)
558 return 0;
559
560 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
561 if (r <= 0)
562 return r;
563
564 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
565 last_moved = m->matches;
566
567 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
568 uint64_t cp;
569
570 r = next_for_match(j, i, f, np, direction, NULL, &cp);
571 if (r <= 0)
572 return r;
573
574 assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
575 if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
576 np = cp;
577 last_moved = i;
578 }
579 }
580 }
581
582 assert(np > 0);
583
584 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
585 if (r < 0)
586 return r;
587
588 if (ret)
589 *ret = n;
590 if (offset)
591 *offset = np;
592
593 return 1;
594 }
595
596 static int find_location_for_match(
597 sd_journal *j,
598 Match *m,
599 JournalFile *f,
600 direction_t direction,
601 Object **ret,
602 uint64_t *offset) {
603
604 int r;
605
606 assert(j);
607 assert(m);
608 assert(f);
609
610 if (m->type == MATCH_DISCRETE) {
611 uint64_t dp;
612
613 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
614 if (r <= 0)
615 return r;
616
617 /* FIXME: missing: find by monotonic */
618
619 if (j->current_location.type == LOCATION_HEAD)
620 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
621 if (j->current_location.type == LOCATION_TAIL)
622 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset);
623 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
624 return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
625 if (j->current_location.monotonic_set) {
626 r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
627 if (r != -ENOENT)
628 return r;
629 }
630 if (j->current_location.realtime_set)
631 return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
632
633 return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset);
634
635 } else if (m->type == MATCH_OR_TERM) {
636 uint64_t np = 0;
637 Object *n;
638 Match *i;
639
640 /* Find the earliest match */
641
642 LIST_FOREACH(matches, i, m->matches) {
643 uint64_t cp;
644
645 r = find_location_for_match(j, i, f, direction, NULL, &cp);
646 if (r < 0)
647 return r;
648 else if (r > 0) {
649 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
650 np = cp;
651 }
652 }
653
654 if (np == 0)
655 return 0;
656
657 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
658 if (r < 0)
659 return r;
660
661 if (ret)
662 *ret = n;
663 if (offset)
664 *offset = np;
665
666 return 1;
667
668 } else {
669 Match *i;
670 uint64_t np = 0;
671
672 assert(m->type == MATCH_AND_TERM);
673
674 /* First jump to the last match, and then find the
675 * next one where all matches match */
676
677 if (!m->matches)
678 return 0;
679
680 LIST_FOREACH(matches, i, m->matches) {
681 uint64_t cp;
682
683 r = find_location_for_match(j, i, f, direction, NULL, &cp);
684 if (r <= 0)
685 return r;
686
687 if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
688 np = cp;
689 }
690
691 return next_for_match(j, m, f, np, direction, ret, offset);
692 }
693 }
694
695 static int find_location_with_matches(
696 sd_journal *j,
697 JournalFile *f,
698 direction_t direction,
699 Object **ret,
700 uint64_t *offset) {
701
702 int r;
703
704 assert(j);
705 assert(f);
706 assert(ret);
707 assert(offset);
708
709 if (!j->level0) {
710 /* No matches is simple */
711
712 if (j->current_location.type == LOCATION_HEAD)
713 return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset);
714 if (j->current_location.type == LOCATION_TAIL)
715 return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset);
716 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
717 return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
718 if (j->current_location.monotonic_set) {
719 r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
720 if (r != -ENOENT)
721 return r;
722 }
723 if (j->current_location.realtime_set)
724 return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
725
726 return journal_file_next_entry(f, 0, direction, ret, offset);
727 } else
728 return find_location_for_match(j, j->level0, f, direction, ret, offset);
729 }
730
731 static int next_with_matches(
732 sd_journal *j,
733 JournalFile *f,
734 direction_t direction,
735 Object **ret,
736 uint64_t *offset) {
737
738 assert(j);
739 assert(f);
740 assert(ret);
741 assert(offset);
742
743 /* No matches is easy. We simple advance the file
744 * pointer by one. */
745 if (!j->level0)
746 return journal_file_next_entry(f, f->current_offset, direction, ret, offset);
747
748 /* If we have a match then we look for the next matching entry
749 * with an offset at least one step larger */
750 return next_for_match(j, j->level0, f,
751 direction == DIRECTION_DOWN ? f->current_offset + 1
752 : f->current_offset - 1,
753 direction, ret, offset);
754 }
755
756 static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) {
757 Object *c;
758 uint64_t cp, n_entries;
759 int r;
760
761 assert(j);
762 assert(f);
763
764 n_entries = le64toh(f->header->n_entries);
765
766 /* If we hit EOF before, we don't need to look into this file again
767 * unless direction changed or new entries appeared. */
768 if (f->last_direction == direction && f->location_type == LOCATION_TAIL &&
769 n_entries == f->last_n_entries)
770 return 0;
771
772 f->last_n_entries = n_entries;
773
774 if (f->last_direction == direction && f->current_offset > 0) {
775 /* LOCATION_SEEK here means we did the work in a previous
776 * iteration and the current location already points to a
777 * candidate entry. */
778 if (f->location_type != LOCATION_SEEK) {
779 r = next_with_matches(j, f, direction, &c, &cp);
780 if (r <= 0)
781 return r;
782
783 journal_file_save_location(f, c, cp);
784 }
785 } else {
786 f->last_direction = direction;
787
788 r = find_location_with_matches(j, f, direction, &c, &cp);
789 if (r <= 0)
790 return r;
791
792 journal_file_save_location(f, c, cp);
793 }
794
795 /* OK, we found the spot, now let's advance until an entry
796 * that is actually different from what we were previously
797 * looking at. This is necessary to handle entries which exist
798 * in two (or more) journal files, and which shall all be
799 * suppressed but one. */
800
801 for (;;) {
802 bool found;
803
804 if (j->current_location.type == LOCATION_DISCRETE) {
805 int k;
806
807 k = compare_with_location(f, &j->current_location);
808
809 found = direction == DIRECTION_DOWN ? k > 0 : k < 0;
810 } else
811 found = true;
812
813 if (found)
814 return 1;
815
816 r = next_with_matches(j, f, direction, &c, &cp);
817 if (r <= 0)
818 return r;
819
820 journal_file_save_location(f, c, cp);
821 }
822 }
823
824 static int real_journal_next(sd_journal *j, direction_t direction) {
825 JournalFile *f, *new_file = NULL;
826 Iterator i;
827 Object *o;
828 int r;
829
830 assert_return(j, -EINVAL);
831 assert_return(!journal_pid_changed(j), -ECHILD);
832
833 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
834 bool found;
835
836 r = next_beyond_location(j, f, direction);
837 if (r < 0) {
838 log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path);
839 remove_file_real(j, f);
840 continue;
841 } else if (r == 0) {
842 f->location_type = LOCATION_TAIL;
843 continue;
844 }
845
846 if (!new_file)
847 found = true;
848 else {
849 int k;
850
851 k = journal_file_compare_locations(f, new_file);
852
853 found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
854 }
855
856 if (found)
857 new_file = f;
858 }
859
860 if (!new_file)
861 return 0;
862
863 r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o);
864 if (r < 0)
865 return r;
866
867 set_location(j, new_file, o);
868
869 return 1;
870 }
871
872 _public_ int sd_journal_next(sd_journal *j) {
873 return real_journal_next(j, DIRECTION_DOWN);
874 }
875
876 _public_ int sd_journal_previous(sd_journal *j) {
877 return real_journal_next(j, DIRECTION_UP);
878 }
879
880 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
881 int c = 0, r;
882
883 assert_return(j, -EINVAL);
884 assert_return(!journal_pid_changed(j), -ECHILD);
885
886 if (skip == 0) {
887 /* If this is not a discrete skip, then at least
888 * resolve the current location */
889 if (j->current_location.type != LOCATION_DISCRETE)
890 return real_journal_next(j, direction);
891
892 return 0;
893 }
894
895 do {
896 r = real_journal_next(j, direction);
897 if (r < 0)
898 return r;
899
900 if (r == 0)
901 return c;
902
903 skip--;
904 c++;
905 } while (skip > 0);
906
907 return c;
908 }
909
910 _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
911 return real_journal_next_skip(j, DIRECTION_DOWN, skip);
912 }
913
914 _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
915 return real_journal_next_skip(j, DIRECTION_UP, skip);
916 }
917
918 _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
919 Object *o;
920 int r;
921 char bid[33], sid[33];
922
923 assert_return(j, -EINVAL);
924 assert_return(!journal_pid_changed(j), -ECHILD);
925 assert_return(cursor, -EINVAL);
926
927 if (!j->current_file || j->current_file->current_offset <= 0)
928 return -EADDRNOTAVAIL;
929
930 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
931 if (r < 0)
932 return r;
933
934 sd_id128_to_string(j->current_file->header->seqnum_id, sid);
935 sd_id128_to_string(o->entry.boot_id, bid);
936
937 if (asprintf(cursor,
938 "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
939 sid, le64toh(o->entry.seqnum),
940 bid, le64toh(o->entry.monotonic),
941 le64toh(o->entry.realtime),
942 le64toh(o->entry.xor_hash)) < 0)
943 return -ENOMEM;
944
945 return 0;
946 }
947
948 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
949 const char *word, *state;
950 size_t l;
951 unsigned long long seqnum, monotonic, realtime, xor_hash;
952 bool
953 seqnum_id_set = false,
954 seqnum_set = false,
955 boot_id_set = false,
956 monotonic_set = false,
957 realtime_set = false,
958 xor_hash_set = false;
959 sd_id128_t seqnum_id, boot_id;
960
961 assert_return(j, -EINVAL);
962 assert_return(!journal_pid_changed(j), -ECHILD);
963 assert_return(!isempty(cursor), -EINVAL);
964
965 FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
966 char *item;
967 int k = 0;
968
969 if (l < 2 || word[1] != '=')
970 return -EINVAL;
971
972 item = strndup(word, l);
973 if (!item)
974 return -ENOMEM;
975
976 switch (word[0]) {
977
978 case 's':
979 seqnum_id_set = true;
980 k = sd_id128_from_string(item+2, &seqnum_id);
981 break;
982
983 case 'i':
984 seqnum_set = true;
985 if (sscanf(item+2, "%llx", &seqnum) != 1)
986 k = -EINVAL;
987 break;
988
989 case 'b':
990 boot_id_set = true;
991 k = sd_id128_from_string(item+2, &boot_id);
992 break;
993
994 case 'm':
995 monotonic_set = true;
996 if (sscanf(item+2, "%llx", &monotonic) != 1)
997 k = -EINVAL;
998 break;
999
1000 case 't':
1001 realtime_set = true;
1002 if (sscanf(item+2, "%llx", &realtime) != 1)
1003 k = -EINVAL;
1004 break;
1005
1006 case 'x':
1007 xor_hash_set = true;
1008 if (sscanf(item+2, "%llx", &xor_hash) != 1)
1009 k = -EINVAL;
1010 break;
1011 }
1012
1013 free(item);
1014
1015 if (k < 0)
1016 return k;
1017 }
1018
1019 if ((!seqnum_set || !seqnum_id_set) &&
1020 (!monotonic_set || !boot_id_set) &&
1021 !realtime_set)
1022 return -EINVAL;
1023
1024 reset_location(j);
1025
1026 j->current_location.type = LOCATION_SEEK;
1027
1028 if (realtime_set) {
1029 j->current_location.realtime = (uint64_t) realtime;
1030 j->current_location.realtime_set = true;
1031 }
1032
1033 if (seqnum_set && seqnum_id_set) {
1034 j->current_location.seqnum = (uint64_t) seqnum;
1035 j->current_location.seqnum_id = seqnum_id;
1036 j->current_location.seqnum_set = true;
1037 }
1038
1039 if (monotonic_set && boot_id_set) {
1040 j->current_location.monotonic = (uint64_t) monotonic;
1041 j->current_location.boot_id = boot_id;
1042 j->current_location.monotonic_set = true;
1043 }
1044
1045 if (xor_hash_set) {
1046 j->current_location.xor_hash = (uint64_t) xor_hash;
1047 j->current_location.xor_hash_set = true;
1048 }
1049
1050 return 0;
1051 }
1052
1053 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1054 int r;
1055 Object *o;
1056
1057 assert_return(j, -EINVAL);
1058 assert_return(!journal_pid_changed(j), -ECHILD);
1059 assert_return(!isempty(cursor), -EINVAL);
1060
1061 if (!j->current_file || j->current_file->current_offset <= 0)
1062 return -EADDRNOTAVAIL;
1063
1064 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1065 if (r < 0)
1066 return r;
1067
1068 for(;;) {
1069 _cleanup_free_ char *item = NULL;
1070 unsigned long long ll;
1071 sd_id128_t id;
1072 int k = 0;
1073
1074 r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
1075 if (r < 0)
1076 return r;
1077
1078 if (r == 0)
1079 break;
1080
1081 if (strlen(item) < 2 || item[1] != '=')
1082 return -EINVAL;
1083
1084 switch (item[0]) {
1085
1086 case 's':
1087 k = sd_id128_from_string(item+2, &id);
1088 if (k < 0)
1089 return k;
1090 if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1091 return 0;
1092 break;
1093
1094 case 'i':
1095 if (sscanf(item+2, "%llx", &ll) != 1)
1096 return -EINVAL;
1097 if (ll != le64toh(o->entry.seqnum))
1098 return 0;
1099 break;
1100
1101 case 'b':
1102 k = sd_id128_from_string(item+2, &id);
1103 if (k < 0)
1104 return k;
1105 if (!sd_id128_equal(id, o->entry.boot_id))
1106 return 0;
1107 break;
1108
1109 case 'm':
1110 if (sscanf(item+2, "%llx", &ll) != 1)
1111 return -EINVAL;
1112 if (ll != le64toh(o->entry.monotonic))
1113 return 0;
1114 break;
1115
1116 case 't':
1117 if (sscanf(item+2, "%llx", &ll) != 1)
1118 return -EINVAL;
1119 if (ll != le64toh(o->entry.realtime))
1120 return 0;
1121 break;
1122
1123 case 'x':
1124 if (sscanf(item+2, "%llx", &ll) != 1)
1125 return -EINVAL;
1126 if (ll != le64toh(o->entry.xor_hash))
1127 return 0;
1128 break;
1129 }
1130 }
1131
1132 return 1;
1133 }
1134
1135
1136 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1137 assert_return(j, -EINVAL);
1138 assert_return(!journal_pid_changed(j), -ECHILD);
1139
1140 reset_location(j);
1141 j->current_location.type = LOCATION_SEEK;
1142 j->current_location.boot_id = boot_id;
1143 j->current_location.monotonic = usec;
1144 j->current_location.monotonic_set = true;
1145
1146 return 0;
1147 }
1148
1149 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
1150 assert_return(j, -EINVAL);
1151 assert_return(!journal_pid_changed(j), -ECHILD);
1152
1153 reset_location(j);
1154 j->current_location.type = LOCATION_SEEK;
1155 j->current_location.realtime = usec;
1156 j->current_location.realtime_set = true;
1157
1158 return 0;
1159 }
1160
1161 _public_ int sd_journal_seek_head(sd_journal *j) {
1162 assert_return(j, -EINVAL);
1163 assert_return(!journal_pid_changed(j), -ECHILD);
1164
1165 reset_location(j);
1166 j->current_location.type = LOCATION_HEAD;
1167
1168 return 0;
1169 }
1170
1171 _public_ int sd_journal_seek_tail(sd_journal *j) {
1172 assert_return(j, -EINVAL);
1173 assert_return(!journal_pid_changed(j), -ECHILD);
1174
1175 reset_location(j);
1176 j->current_location.type = LOCATION_TAIL;
1177
1178 return 0;
1179 }
1180
1181 static void check_network(sd_journal *j, int fd) {
1182 struct statfs sfs;
1183
1184 assert(j);
1185
1186 if (j->on_network)
1187 return;
1188
1189 if (fstatfs(fd, &sfs) < 0)
1190 return;
1191
1192 j->on_network =
1193 F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) ||
1194 F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) ||
1195 F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) ||
1196 F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) ||
1197 F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC);
1198 }
1199
1200 static bool file_has_type_prefix(const char *prefix, const char *filename) {
1201 const char *full, *tilded, *atted;
1202
1203 full = strjoina(prefix, ".journal");
1204 tilded = strjoina(full, "~");
1205 atted = strjoina(prefix, "@");
1206
1207 return streq(filename, full) ||
1208 streq(filename, tilded) ||
1209 startswith(filename, atted);
1210 }
1211
1212 static bool file_type_wanted(int flags, const char *filename) {
1213 assert(filename);
1214
1215 if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1216 return false;
1217
1218 /* no flags set → every type is OK */
1219 if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1220 return true;
1221
1222 if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1223 return true;
1224
1225 if (flags & SD_JOURNAL_CURRENT_USER) {
1226 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1227
1228 xsprintf(prefix, "user-"UID_FMT, getuid());
1229
1230 if (file_has_type_prefix(prefix, filename))
1231 return true;
1232 }
1233
1234 return false;
1235 }
1236
1237 static int add_any_file(sd_journal *j, const char *path) {
1238 JournalFile *f = NULL;
1239 int r, k;
1240
1241 assert(j);
1242 assert(path);
1243
1244 if (ordered_hashmap_get(j->files, path))
1245 return 0;
1246
1247 if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1248 log_debug("Too many open journal files, not adding %s.", path);
1249 r = -ETOOMANYREFS;
1250 goto fail;
1251 }
1252
1253 r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
1254 if (r < 0) {
1255 log_debug_errno(r, "Failed to open journal file %s: %m", path);
1256 goto fail;
1257 }
1258
1259 /* journal_file_dump(f); */
1260
1261 r = ordered_hashmap_put(j->files, f->path, f);
1262 if (r < 0) {
1263 journal_file_close(f);
1264 goto fail;
1265 }
1266
1267 log_debug("File %s added.", f->path);
1268
1269 check_network(j, f->fd);
1270
1271 j->current_invalidate_counter ++;
1272
1273 return 0;
1274
1275 fail:
1276 k = journal_put_error(j, r, path);
1277 if (k < 0)
1278 return k;
1279
1280 return r;
1281 }
1282
1283 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
1284 const char *path;
1285
1286 assert(j);
1287 assert(prefix);
1288 assert(filename);
1289
1290 if (j->no_new_files ||
1291 !file_type_wanted(j->flags, filename))
1292 return 0;
1293
1294 path = strjoina(prefix, "/", filename);
1295
1296 if (!j->has_runtime_files && path_startswith(path, "/run/log/journal"))
1297 j->has_runtime_files = true;
1298 else if (!j->has_persistent_files && path_startswith(path, "/var/log/journal"))
1299 j->has_persistent_files = true;
1300
1301 return add_any_file(j, path);
1302 }
1303
1304 static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
1305 const char *path;
1306 JournalFile *f;
1307
1308 assert(j);
1309 assert(prefix);
1310 assert(filename);
1311
1312 path = strjoina(prefix, "/", filename);
1313 f = ordered_hashmap_get(j->files, path);
1314 if (!f)
1315 return;
1316
1317 remove_file_real(j, f);
1318 }
1319
1320 static void remove_file_real(sd_journal *j, JournalFile *f) {
1321 assert(j);
1322 assert(f);
1323
1324 ordered_hashmap_remove(j->files, f->path);
1325
1326 log_debug("File %s removed.", f->path);
1327
1328 if (j->current_file == f) {
1329 j->current_file = NULL;
1330 j->current_field = 0;
1331 }
1332
1333 if (j->unique_file == f) {
1334 /* Jump to the next unique_file or NULL if that one was last */
1335 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
1336 j->unique_offset = 0;
1337 if (!j->unique_file)
1338 j->unique_file_lost = true;
1339 }
1340
1341 if (j->fields_file == f) {
1342 j->fields_file = ordered_hashmap_next(j->files, j->fields_file->path);
1343 j->fields_offset = 0;
1344 if (!j->fields_file)
1345 j->fields_file_lost = true;
1346 }
1347
1348 journal_file_close(f);
1349
1350 j->current_invalidate_counter ++;
1351 }
1352
1353 static int dirname_is_machine_id(const char *fn) {
1354 sd_id128_t id, machine;
1355 int r;
1356
1357 r = sd_id128_get_machine(&machine);
1358 if (r < 0)
1359 return r;
1360
1361 r = sd_id128_from_string(fn, &id);
1362 if (r < 0)
1363 return r;
1364
1365 return sd_id128_equal(id, machine);
1366 }
1367
1368 static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
1369 _cleanup_free_ char *path = NULL;
1370 _cleanup_closedir_ DIR *d = NULL;
1371 struct dirent *de = NULL;
1372 Directory *m;
1373 int r, k;
1374
1375 assert(j);
1376 assert(prefix);
1377 assert(dirname);
1378
1379 log_debug("Considering %s/%s.", prefix, dirname);
1380
1381 if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
1382 !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run")))
1383 return 0;
1384
1385 path = strjoin(prefix, "/", dirname, NULL);
1386 if (!path) {
1387 r = -ENOMEM;
1388 goto fail;
1389 }
1390
1391 d = opendir(path);
1392 if (!d) {
1393 r = log_debug_errno(errno, "Failed to open directory %s: %m", path);
1394 goto fail;
1395 }
1396
1397 m = hashmap_get(j->directories_by_path, path);
1398 if (!m) {
1399 m = new0(Directory, 1);
1400 if (!m) {
1401 r = -ENOMEM;
1402 goto fail;
1403 }
1404
1405 m->is_root = false;
1406 m->path = path;
1407
1408 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1409 free(m);
1410 r = -ENOMEM;
1411 goto fail;
1412 }
1413
1414 path = NULL; /* avoid freeing in cleanup */
1415 j->current_invalidate_counter ++;
1416
1417 log_debug("Directory %s added.", m->path);
1418
1419 } else if (m->is_root)
1420 return 0;
1421
1422 if (m->wd <= 0 && j->inotify_fd >= 0) {
1423
1424 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1425 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1426 IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
1427 IN_ONLYDIR);
1428
1429 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1430 inotify_rm_watch(j->inotify_fd, m->wd);
1431 }
1432
1433 FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
1434
1435 if (dirent_is_file_with_suffix(de, ".journal") ||
1436 dirent_is_file_with_suffix(de, ".journal~"))
1437 (void) add_file(j, m->path, de->d_name);
1438 }
1439
1440 check_network(j, dirfd(d));
1441
1442 return 0;
1443
1444 fail:
1445 k = journal_put_error(j, r, path ?: dirname);
1446 if (k < 0)
1447 return k;
1448
1449 return r;
1450 }
1451
1452 static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
1453 _cleanup_closedir_ DIR *d = NULL;
1454 struct dirent *de;
1455 Directory *m;
1456 int r, k;
1457
1458 assert(j);
1459 assert(p);
1460
1461 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1462 !path_startswith(p, "/run"))
1463 return -EINVAL;
1464
1465 if (j->prefix)
1466 p = strjoina(j->prefix, p);
1467
1468 d = opendir(p);
1469 if (!d) {
1470 if (errno == ENOENT && missing_ok)
1471 return 0;
1472
1473 r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
1474 goto fail;
1475 }
1476
1477 m = hashmap_get(j->directories_by_path, p);
1478 if (!m) {
1479 m = new0(Directory, 1);
1480 if (!m) {
1481 r = -ENOMEM;
1482 goto fail;
1483 }
1484
1485 m->is_root = true;
1486 m->path = strdup(p);
1487 if (!m->path) {
1488 free(m);
1489 r = -ENOMEM;
1490 goto fail;
1491 }
1492
1493 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1494 free(m->path);
1495 free(m);
1496 r = -ENOMEM;
1497 goto fail;
1498 }
1499
1500 j->current_invalidate_counter ++;
1501
1502 log_debug("Root directory %s added.", m->path);
1503
1504 } else if (!m->is_root)
1505 return 0;
1506
1507 if (m->wd <= 0 && j->inotify_fd >= 0) {
1508
1509 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1510 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1511 IN_ONLYDIR);
1512
1513 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1514 inotify_rm_watch(j->inotify_fd, m->wd);
1515 }
1516
1517 if (j->no_new_files)
1518 return 0;
1519
1520 FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
1521 sd_id128_t id;
1522
1523 if (dirent_is_file_with_suffix(de, ".journal") ||
1524 dirent_is_file_with_suffix(de, ".journal~"))
1525 (void) add_file(j, m->path, de->d_name);
1526 else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) &&
1527 sd_id128_from_string(de->d_name, &id) >= 0)
1528 (void) add_directory(j, m->path, de->d_name);
1529 }
1530
1531 check_network(j, dirfd(d));
1532
1533 return 0;
1534
1535 fail:
1536 k = journal_put_error(j, r, p);
1537 if (k < 0)
1538 return k;
1539
1540 return r;
1541 }
1542
1543 static void remove_directory(sd_journal *j, Directory *d) {
1544 assert(j);
1545
1546 if (d->wd > 0) {
1547 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1548
1549 if (j->inotify_fd >= 0)
1550 inotify_rm_watch(j->inotify_fd, d->wd);
1551 }
1552
1553 hashmap_remove(j->directories_by_path, d->path);
1554
1555 if (d->is_root)
1556 log_debug("Root directory %s removed.", d->path);
1557 else
1558 log_debug("Directory %s removed.", d->path);
1559
1560 free(d->path);
1561 free(d);
1562 }
1563
1564 static int add_search_paths(sd_journal *j) {
1565
1566 static const char search_paths[] =
1567 "/run/log/journal\0"
1568 "/var/log/journal\0";
1569 const char *p;
1570
1571 assert(j);
1572
1573 /* We ignore most errors here, since the idea is to only open
1574 * what's actually accessible, and ignore the rest. */
1575
1576 NULSTR_FOREACH(p, search_paths)
1577 (void) add_root_directory(j, p, true);
1578
1579 return 0;
1580 }
1581
1582 static int add_current_paths(sd_journal *j) {
1583 Iterator i;
1584 JournalFile *f;
1585
1586 assert(j);
1587 assert(j->no_new_files);
1588
1589 /* Simply adds all directories for files we have open as
1590 * "root" directories. We don't expect errors here, so we
1591 * treat them as fatal. */
1592
1593 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
1594 _cleanup_free_ char *dir;
1595 int r;
1596
1597 dir = dirname_malloc(f->path);
1598 if (!dir)
1599 return -ENOMEM;
1600
1601 r = add_root_directory(j, dir, true);
1602 if (r < 0)
1603 return r;
1604 }
1605
1606 return 0;
1607 }
1608
1609 static int allocate_inotify(sd_journal *j) {
1610 assert(j);
1611
1612 if (j->inotify_fd < 0) {
1613 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1614 if (j->inotify_fd < 0)
1615 return -errno;
1616 }
1617
1618 if (!j->directories_by_wd) {
1619 j->directories_by_wd = hashmap_new(NULL);
1620 if (!j->directories_by_wd)
1621 return -ENOMEM;
1622 }
1623
1624 return 0;
1625 }
1626
1627 static sd_journal *journal_new(int flags, const char *path) {
1628 sd_journal *j;
1629
1630 j = new0(sd_journal, 1);
1631 if (!j)
1632 return NULL;
1633
1634 j->original_pid = getpid();
1635 j->inotify_fd = -1;
1636 j->flags = flags;
1637 j->data_threshold = DEFAULT_DATA_THRESHOLD;
1638
1639 if (path) {
1640 j->path = strdup(path);
1641 if (!j->path)
1642 goto fail;
1643 }
1644
1645 j->files = ordered_hashmap_new(&string_hash_ops);
1646 j->directories_by_path = hashmap_new(&string_hash_ops);
1647 j->mmap = mmap_cache_new();
1648 if (!j->files || !j->directories_by_path || !j->mmap)
1649 goto fail;
1650
1651 return j;
1652
1653 fail:
1654 sd_journal_close(j);
1655 return NULL;
1656 }
1657
1658 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1659 sd_journal *j;
1660 int r;
1661
1662 assert_return(ret, -EINVAL);
1663 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL);
1664
1665 j = journal_new(flags, NULL);
1666 if (!j)
1667 return -ENOMEM;
1668
1669 r = add_search_paths(j);
1670 if (r < 0)
1671 goto fail;
1672
1673 *ret = j;
1674 return 0;
1675
1676 fail:
1677 sd_journal_close(j);
1678
1679 return r;
1680 }
1681
1682 _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
1683 _cleanup_free_ char *root = NULL, *class = NULL;
1684 sd_journal *j;
1685 char *p;
1686 int r;
1687
1688 assert_return(machine, -EINVAL);
1689 assert_return(ret, -EINVAL);
1690 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL);
1691 assert_return(machine_name_is_valid(machine), -EINVAL);
1692
1693 p = strjoina("/run/systemd/machines/", machine);
1694 r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL);
1695 if (r == -ENOENT)
1696 return -EHOSTDOWN;
1697 if (r < 0)
1698 return r;
1699 if (!root)
1700 return -ENODATA;
1701
1702 if (!streq_ptr(class, "container"))
1703 return -EIO;
1704
1705 j = journal_new(flags, NULL);
1706 if (!j)
1707 return -ENOMEM;
1708
1709 j->prefix = root;
1710 root = NULL;
1711
1712 r = add_search_paths(j);
1713 if (r < 0)
1714 goto fail;
1715
1716 *ret = j;
1717 return 0;
1718
1719 fail:
1720 sd_journal_close(j);
1721 return r;
1722 }
1723
1724 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1725 sd_journal *j;
1726 int r;
1727
1728 assert_return(ret, -EINVAL);
1729 assert_return(path, -EINVAL);
1730 assert_return(flags == 0, -EINVAL);
1731
1732 j = journal_new(flags, path);
1733 if (!j)
1734 return -ENOMEM;
1735
1736 r = add_root_directory(j, path, false);
1737 if (r < 0)
1738 goto fail;
1739
1740 *ret = j;
1741 return 0;
1742
1743 fail:
1744 sd_journal_close(j);
1745
1746 return r;
1747 }
1748
1749 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1750 sd_journal *j;
1751 const char **path;
1752 int r;
1753
1754 assert_return(ret, -EINVAL);
1755 assert_return(flags == 0, -EINVAL);
1756
1757 j = journal_new(flags, NULL);
1758 if (!j)
1759 return -ENOMEM;
1760
1761 STRV_FOREACH(path, paths) {
1762 r = add_any_file(j, *path);
1763 if (r < 0)
1764 goto fail;
1765 }
1766
1767 j->no_new_files = true;
1768
1769 *ret = j;
1770 return 0;
1771
1772 fail:
1773 sd_journal_close(j);
1774
1775 return r;
1776 }
1777
1778 _public_ void sd_journal_close(sd_journal *j) {
1779 Directory *d;
1780 JournalFile *f;
1781 char *p;
1782
1783 if (!j)
1784 return;
1785
1786 sd_journal_flush_matches(j);
1787
1788 while ((f = ordered_hashmap_steal_first(j->files)))
1789 journal_file_close(f);
1790
1791 ordered_hashmap_free(j->files);
1792
1793 while ((d = hashmap_first(j->directories_by_path)))
1794 remove_directory(j, d);
1795
1796 while ((d = hashmap_first(j->directories_by_wd)))
1797 remove_directory(j, d);
1798
1799 hashmap_free(j->directories_by_path);
1800 hashmap_free(j->directories_by_wd);
1801
1802 safe_close(j->inotify_fd);
1803
1804 if (j->mmap) {
1805 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
1806 mmap_cache_unref(j->mmap);
1807 }
1808
1809 while ((p = hashmap_steal_first(j->errors)))
1810 free(p);
1811 hashmap_free(j->errors);
1812
1813 free(j->path);
1814 free(j->prefix);
1815 free(j->unique_field);
1816 free(j->fields_buffer);
1817 free(j);
1818 }
1819
1820 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
1821 Object *o;
1822 JournalFile *f;
1823 int r;
1824
1825 assert_return(j, -EINVAL);
1826 assert_return(!journal_pid_changed(j), -ECHILD);
1827 assert_return(ret, -EINVAL);
1828
1829 f = j->current_file;
1830 if (!f)
1831 return -EADDRNOTAVAIL;
1832
1833 if (f->current_offset <= 0)
1834 return -EADDRNOTAVAIL;
1835
1836 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1837 if (r < 0)
1838 return r;
1839
1840 *ret = le64toh(o->entry.realtime);
1841 return 0;
1842 }
1843
1844 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
1845 Object *o;
1846 JournalFile *f;
1847 int r;
1848 sd_id128_t id;
1849
1850 assert_return(j, -EINVAL);
1851 assert_return(!journal_pid_changed(j), -ECHILD);
1852
1853 f = j->current_file;
1854 if (!f)
1855 return -EADDRNOTAVAIL;
1856
1857 if (f->current_offset <= 0)
1858 return -EADDRNOTAVAIL;
1859
1860 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1861 if (r < 0)
1862 return r;
1863
1864 if (ret_boot_id)
1865 *ret_boot_id = o->entry.boot_id;
1866 else {
1867 r = sd_id128_get_boot(&id);
1868 if (r < 0)
1869 return r;
1870
1871 if (!sd_id128_equal(id, o->entry.boot_id))
1872 return -ESTALE;
1873 }
1874
1875 if (ret)
1876 *ret = le64toh(o->entry.monotonic);
1877
1878 return 0;
1879 }
1880
1881 static bool field_is_valid(const char *field) {
1882 const char *p;
1883
1884 assert(field);
1885
1886 if (isempty(field))
1887 return false;
1888
1889 if (startswith(field, "__"))
1890 return false;
1891
1892 for (p = field; *p; p++) {
1893
1894 if (*p == '_')
1895 continue;
1896
1897 if (*p >= 'A' && *p <= 'Z')
1898 continue;
1899
1900 if (*p >= '0' && *p <= '9')
1901 continue;
1902
1903 return false;
1904 }
1905
1906 return true;
1907 }
1908
1909 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
1910 JournalFile *f;
1911 uint64_t i, n;
1912 size_t field_length;
1913 int r;
1914 Object *o;
1915
1916 assert_return(j, -EINVAL);
1917 assert_return(!journal_pid_changed(j), -ECHILD);
1918 assert_return(field, -EINVAL);
1919 assert_return(data, -EINVAL);
1920 assert_return(size, -EINVAL);
1921 assert_return(field_is_valid(field), -EINVAL);
1922
1923 f = j->current_file;
1924 if (!f)
1925 return -EADDRNOTAVAIL;
1926
1927 if (f->current_offset <= 0)
1928 return -EADDRNOTAVAIL;
1929
1930 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1931 if (r < 0)
1932 return r;
1933
1934 field_length = strlen(field);
1935
1936 n = journal_file_entry_n_items(o);
1937 for (i = 0; i < n; i++) {
1938 uint64_t p, l;
1939 le64_t le_hash;
1940 size_t t;
1941 int compression;
1942
1943 p = le64toh(o->entry.items[i].object_offset);
1944 le_hash = o->entry.items[i].hash;
1945 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1946 if (r < 0)
1947 return r;
1948
1949 if (le_hash != o->data.hash)
1950 return -EBADMSG;
1951
1952 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1953
1954 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
1955 if (compression) {
1956 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
1957 r = decompress_startswith(compression,
1958 o->data.payload, l,
1959 &f->compress_buffer, &f->compress_buffer_size,
1960 field, field_length, '=');
1961 if (r < 0)
1962 log_debug_errno(r, "Cannot decompress %s object of length %zu at offset "OFSfmt": %m",
1963 object_compressed_to_string(compression), l, p);
1964 else if (r > 0) {
1965
1966 size_t rsize;
1967
1968 r = decompress_blob(compression,
1969 o->data.payload, l,
1970 &f->compress_buffer, &f->compress_buffer_size, &rsize,
1971 j->data_threshold);
1972 if (r < 0)
1973 return r;
1974
1975 *data = f->compress_buffer;
1976 *size = (size_t) rsize;
1977
1978 return 0;
1979 }
1980 #else
1981 return -EPROTONOSUPPORT;
1982 #endif
1983 } else if (l >= field_length+1 &&
1984 memcmp(o->data.payload, field, field_length) == 0 &&
1985 o->data.payload[field_length] == '=') {
1986
1987 t = (size_t) l;
1988
1989 if ((uint64_t) t != l)
1990 return -E2BIG;
1991
1992 *data = o->data.payload;
1993 *size = t;
1994
1995 return 0;
1996 }
1997
1998 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1999 if (r < 0)
2000 return r;
2001 }
2002
2003 return -ENOENT;
2004 }
2005
2006 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
2007 size_t t;
2008 uint64_t l;
2009 int compression;
2010
2011 l = le64toh(o->object.size) - offsetof(Object, data.payload);
2012 t = (size_t) l;
2013
2014 /* We can't read objects larger than 4G on a 32bit machine */
2015 if ((uint64_t) t != l)
2016 return -E2BIG;
2017
2018 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
2019 if (compression) {
2020 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
2021 size_t rsize;
2022 int r;
2023
2024 r = decompress_blob(compression,
2025 o->data.payload, l, &f->compress_buffer,
2026 &f->compress_buffer_size, &rsize, j->data_threshold);
2027 if (r < 0)
2028 return r;
2029
2030 *data = f->compress_buffer;
2031 *size = (size_t) rsize;
2032 #else
2033 return -EPROTONOSUPPORT;
2034 #endif
2035 } else {
2036 *data = o->data.payload;
2037 *size = t;
2038 }
2039
2040 return 0;
2041 }
2042
2043 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
2044 JournalFile *f;
2045 uint64_t p, n;
2046 le64_t le_hash;
2047 int r;
2048 Object *o;
2049
2050 assert_return(j, -EINVAL);
2051 assert_return(!journal_pid_changed(j), -ECHILD);
2052 assert_return(data, -EINVAL);
2053 assert_return(size, -EINVAL);
2054
2055 f = j->current_file;
2056 if (!f)
2057 return -EADDRNOTAVAIL;
2058
2059 if (f->current_offset <= 0)
2060 return -EADDRNOTAVAIL;
2061
2062 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2063 if (r < 0)
2064 return r;
2065
2066 n = journal_file_entry_n_items(o);
2067 if (j->current_field >= n)
2068 return 0;
2069
2070 p = le64toh(o->entry.items[j->current_field].object_offset);
2071 le_hash = o->entry.items[j->current_field].hash;
2072 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2073 if (r < 0)
2074 return r;
2075
2076 if (le_hash != o->data.hash)
2077 return -EBADMSG;
2078
2079 r = return_data(j, f, o, data, size);
2080 if (r < 0)
2081 return r;
2082
2083 j->current_field ++;
2084
2085 return 1;
2086 }
2087
2088 _public_ void sd_journal_restart_data(sd_journal *j) {
2089 if (!j)
2090 return;
2091
2092 j->current_field = 0;
2093 }
2094
2095 _public_ int sd_journal_get_fd(sd_journal *j) {
2096 int r;
2097
2098 assert_return(j, -EINVAL);
2099 assert_return(!journal_pid_changed(j), -ECHILD);
2100
2101 if (j->inotify_fd >= 0)
2102 return j->inotify_fd;
2103
2104 r = allocate_inotify(j);
2105 if (r < 0)
2106 return r;
2107
2108 /* Iterate through all dirs again, to add them to the
2109 * inotify */
2110 if (j->no_new_files)
2111 r = add_current_paths(j);
2112 else if (j->path)
2113 r = add_root_directory(j, j->path, true);
2114 else
2115 r = add_search_paths(j);
2116 if (r < 0)
2117 return r;
2118
2119 return j->inotify_fd;
2120 }
2121
2122 _public_ int sd_journal_get_events(sd_journal *j) {
2123 int fd;
2124
2125 assert_return(j, -EINVAL);
2126 assert_return(!journal_pid_changed(j), -ECHILD);
2127
2128 fd = sd_journal_get_fd(j);
2129 if (fd < 0)
2130 return fd;
2131
2132 return POLLIN;
2133 }
2134
2135 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2136 int fd;
2137
2138 assert_return(j, -EINVAL);
2139 assert_return(!journal_pid_changed(j), -ECHILD);
2140 assert_return(timeout_usec, -EINVAL);
2141
2142 fd = sd_journal_get_fd(j);
2143 if (fd < 0)
2144 return fd;
2145
2146 if (!j->on_network) {
2147 *timeout_usec = (uint64_t) -1;
2148 return 0;
2149 }
2150
2151 /* If we are on the network we need to regularly check for
2152 * changes manually */
2153
2154 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2155 return 1;
2156 }
2157
2158 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
2159 Directory *d;
2160
2161 assert(j);
2162 assert(e);
2163
2164 /* Is this a subdirectory we watch? */
2165 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2166 if (d) {
2167 sd_id128_t id;
2168
2169 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2170 (endswith(e->name, ".journal") ||
2171 endswith(e->name, ".journal~"))) {
2172
2173 /* Event for a journal file */
2174
2175 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
2176 (void) add_file(j, d->path, e->name);
2177 else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT))
2178 remove_file(j, d->path, e->name);
2179
2180 } else if (!d->is_root && e->len == 0) {
2181
2182 /* Event for a subdirectory */
2183
2184 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT))
2185 remove_directory(j, d);
2186
2187 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2188
2189 /* Event for root directory */
2190
2191 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
2192 (void) add_directory(j, d->path, e->name);
2193 }
2194
2195 return;
2196 }
2197
2198 if (e->mask & IN_IGNORED)
2199 return;
2200
2201 log_debug("Unknown inotify event.");
2202 }
2203
2204 static int determine_change(sd_journal *j) {
2205 bool b;
2206
2207 assert(j);
2208
2209 b = j->current_invalidate_counter != j->last_invalidate_counter;
2210 j->last_invalidate_counter = j->current_invalidate_counter;
2211
2212 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2213 }
2214
2215 _public_ int sd_journal_process(sd_journal *j) {
2216 bool got_something = false;
2217
2218 assert_return(j, -EINVAL);
2219 assert_return(!journal_pid_changed(j), -ECHILD);
2220
2221 j->last_process_usec = now(CLOCK_MONOTONIC);
2222
2223 for (;;) {
2224 union inotify_event_buffer buffer;
2225 struct inotify_event *e;
2226 ssize_t l;
2227
2228 l = read(j->inotify_fd, &buffer, sizeof(buffer));
2229 if (l < 0) {
2230 if (errno == EAGAIN || errno == EINTR)
2231 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2232
2233 return -errno;
2234 }
2235
2236 got_something = true;
2237
2238 FOREACH_INOTIFY_EVENT(e, buffer, l)
2239 process_inotify_event(j, e);
2240 }
2241 }
2242
2243 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2244 int r;
2245 uint64_t t;
2246
2247 assert_return(j, -EINVAL);
2248 assert_return(!journal_pid_changed(j), -ECHILD);
2249
2250 if (j->inotify_fd < 0) {
2251
2252 /* This is the first invocation, hence create the
2253 * inotify watch */
2254 r = sd_journal_get_fd(j);
2255 if (r < 0)
2256 return r;
2257
2258 /* The journal might have changed since the context
2259 * object was created and we weren't watching before,
2260 * hence don't wait for anything, and return
2261 * immediately. */
2262 return determine_change(j);
2263 }
2264
2265 r = sd_journal_get_timeout(j, &t);
2266 if (r < 0)
2267 return r;
2268
2269 if (t != (uint64_t) -1) {
2270 usec_t n;
2271
2272 n = now(CLOCK_MONOTONIC);
2273 t = t > n ? t - n : 0;
2274
2275 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2276 timeout_usec = t;
2277 }
2278
2279 do {
2280 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2281 } while (r == -EINTR);
2282
2283 if (r < 0)
2284 return r;
2285
2286 return sd_journal_process(j);
2287 }
2288
2289 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2290 Iterator i;
2291 JournalFile *f;
2292 bool first = true;
2293 uint64_t fmin = 0, tmax = 0;
2294 int r;
2295
2296 assert_return(j, -EINVAL);
2297 assert_return(!journal_pid_changed(j), -ECHILD);
2298 assert_return(from || to, -EINVAL);
2299 assert_return(from != to, -EINVAL);
2300
2301 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2302 usec_t fr, t;
2303
2304 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2305 if (r == -ENOENT)
2306 continue;
2307 if (r < 0)
2308 return r;
2309 if (r == 0)
2310 continue;
2311
2312 if (first) {
2313 fmin = fr;
2314 tmax = t;
2315 first = false;
2316 } else {
2317 fmin = MIN(fr, fmin);
2318 tmax = MAX(t, tmax);
2319 }
2320 }
2321
2322 if (from)
2323 *from = fmin;
2324 if (to)
2325 *to = tmax;
2326
2327 return first ? 0 : 1;
2328 }
2329
2330 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2331 Iterator i;
2332 JournalFile *f;
2333 bool found = false;
2334 int r;
2335
2336 assert_return(j, -EINVAL);
2337 assert_return(!journal_pid_changed(j), -ECHILD);
2338 assert_return(from || to, -EINVAL);
2339 assert_return(from != to, -EINVAL);
2340
2341 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2342 usec_t fr, t;
2343
2344 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2345 if (r == -ENOENT)
2346 continue;
2347 if (r < 0)
2348 return r;
2349 if (r == 0)
2350 continue;
2351
2352 if (found) {
2353 if (from)
2354 *from = MIN(fr, *from);
2355 if (to)
2356 *to = MAX(t, *to);
2357 } else {
2358 if (from)
2359 *from = fr;
2360 if (to)
2361 *to = t;
2362 found = true;
2363 }
2364 }
2365
2366 return found;
2367 }
2368
2369 void journal_print_header(sd_journal *j) {
2370 Iterator i;
2371 JournalFile *f;
2372 bool newline = false;
2373
2374 assert(j);
2375
2376 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2377 if (newline)
2378 putchar('\n');
2379 else
2380 newline = true;
2381
2382 journal_file_print_header(f);
2383 }
2384 }
2385
2386 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2387 Iterator i;
2388 JournalFile *f;
2389 uint64_t sum = 0;
2390
2391 assert_return(j, -EINVAL);
2392 assert_return(!journal_pid_changed(j), -ECHILD);
2393 assert_return(bytes, -EINVAL);
2394
2395 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2396 struct stat st;
2397
2398 if (fstat(f->fd, &st) < 0)
2399 return -errno;
2400
2401 sum += (uint64_t) st.st_blocks * 512ULL;
2402 }
2403
2404 *bytes = sum;
2405 return 0;
2406 }
2407
2408 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2409 char *f;
2410
2411 assert_return(j, -EINVAL);
2412 assert_return(!journal_pid_changed(j), -ECHILD);
2413 assert_return(!isempty(field), -EINVAL);
2414 assert_return(field_is_valid(field), -EINVAL);
2415
2416 f = strdup(field);
2417 if (!f)
2418 return -ENOMEM;
2419
2420 free(j->unique_field);
2421 j->unique_field = f;
2422 j->unique_file = NULL;
2423 j->unique_offset = 0;
2424 j->unique_file_lost = false;
2425
2426 return 0;
2427 }
2428
2429 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2430 size_t k;
2431
2432 assert_return(j, -EINVAL);
2433 assert_return(!journal_pid_changed(j), -ECHILD);
2434 assert_return(data, -EINVAL);
2435 assert_return(l, -EINVAL);
2436 assert_return(j->unique_field, -EINVAL);
2437
2438 k = strlen(j->unique_field);
2439
2440 if (!j->unique_file) {
2441 if (j->unique_file_lost)
2442 return 0;
2443
2444 j->unique_file = ordered_hashmap_first(j->files);
2445 if (!j->unique_file)
2446 return 0;
2447
2448 j->unique_offset = 0;
2449 }
2450
2451 for (;;) {
2452 JournalFile *of;
2453 Iterator i;
2454 Object *o;
2455 const void *odata;
2456 size_t ol;
2457 bool found;
2458 int r;
2459
2460 /* Proceed to next data object in the field's linked list */
2461 if (j->unique_offset == 0) {
2462 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2463 if (r < 0)
2464 return r;
2465
2466 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2467 } else {
2468 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2469 if (r < 0)
2470 return r;
2471
2472 j->unique_offset = le64toh(o->data.next_field_offset);
2473 }
2474
2475 /* We reached the end of the list? Then start again, with the next file */
2476 if (j->unique_offset == 0) {
2477 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
2478 if (!j->unique_file)
2479 return 0;
2480
2481 continue;
2482 }
2483
2484 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2485 * instead, so that we can look at this data object at the same
2486 * time as one on another file */
2487 r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o);
2488 if (r < 0)
2489 return r;
2490
2491 /* Let's do the type check by hand, since we used 0 context above. */
2492 if (o->object.type != OBJECT_DATA) {
2493 log_debug("%s:offset " OFSfmt ": object has type %d, expected %d",
2494 j->unique_file->path, j->unique_offset,
2495 o->object.type, OBJECT_DATA);
2496 return -EBADMSG;
2497 }
2498
2499 r = return_data(j, j->unique_file, o, &odata, &ol);
2500 if (r < 0)
2501 return r;
2502
2503 /* Check if we have at least the field name and "=". */
2504 if (ol <= k) {
2505 log_debug("%s:offset " OFSfmt ": object has size %zu, expected at least %zu",
2506 j->unique_file->path, j->unique_offset,
2507 ol, k + 1);
2508 return -EBADMSG;
2509 }
2510
2511 if (memcmp(odata, j->unique_field, k) || ((const char*) odata)[k] != '=') {
2512 log_debug("%s:offset " OFSfmt ": object does not start with \"%s=\"",
2513 j->unique_file->path, j->unique_offset,
2514 j->unique_field);
2515 return -EBADMSG;
2516 }
2517
2518 /* OK, now let's see if we already returned this data
2519 * object by checking if it exists in the earlier
2520 * traversed files. */
2521 found = false;
2522 ORDERED_HASHMAP_FOREACH(of, j->files, i) {
2523 if (of == j->unique_file)
2524 break;
2525
2526 /* Skip this file it didn't have any fields indexed */
2527 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0)
2528 continue;
2529
2530 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), NULL, NULL);
2531 if (r < 0)
2532 return r;
2533 if (r > 0) {
2534 found = true;
2535 break;
2536 }
2537 }
2538
2539 if (found)
2540 continue;
2541
2542 r = return_data(j, j->unique_file, o, data, l);
2543 if (r < 0)
2544 return r;
2545
2546 return 1;
2547 }
2548 }
2549
2550 _public_ void sd_journal_restart_unique(sd_journal *j) {
2551 if (!j)
2552 return;
2553
2554 j->unique_file = NULL;
2555 j->unique_offset = 0;
2556 j->unique_file_lost = false;
2557 }
2558
2559 _public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) {
2560 int r;
2561
2562 assert_return(j, -EINVAL);
2563 assert_return(!journal_pid_changed(j), -ECHILD);
2564 assert_return(field, -EINVAL);
2565
2566 if (!j->fields_file) {
2567 if (j->fields_file_lost)
2568 return 0;
2569
2570 j->fields_file = ordered_hashmap_first(j->files);
2571 if (!j->fields_file)
2572 return 0;
2573
2574 j->fields_hash_table_index = 0;
2575 j->fields_offset = 0;
2576 }
2577
2578 for (;;) {
2579 JournalFile *f, *of;
2580 Iterator i;
2581 uint64_t m;
2582 Object *o;
2583 size_t sz;
2584 bool found;
2585
2586 f = j->fields_file;
2587
2588 if (j->fields_offset == 0) {
2589 bool eof = false;
2590
2591 /* We are not yet positioned at any field. Let's pick the first one */
2592 r = journal_file_map_field_hash_table(f);
2593 if (r < 0)
2594 return r;
2595
2596 m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
2597 for (;;) {
2598 if (j->fields_hash_table_index >= m) {
2599 /* Reached the end of the hash table, go to the next file. */
2600 eof = true;
2601 break;
2602 }
2603
2604 j->fields_offset = le64toh(f->field_hash_table[j->fields_hash_table_index].head_hash_offset);
2605
2606 if (j->fields_offset != 0)
2607 break;
2608
2609 /* Empty hash table bucket, go to next one */
2610 j->fields_hash_table_index++;
2611 }
2612
2613 if (eof) {
2614 /* Proceed with next file */
2615 j->fields_file = ordered_hashmap_next(j->files, f->path);
2616 if (!j->fields_file) {
2617 *field = NULL;
2618 return 0;
2619 }
2620
2621 j->fields_offset = 0;
2622 j->fields_hash_table_index = 0;
2623 continue;
2624 }
2625
2626 } else {
2627 /* We are already positioned at a field. If so, let's figure out the next field from it */
2628
2629 r = journal_file_move_to_object(f, OBJECT_FIELD, j->fields_offset, &o);
2630 if (r < 0)
2631 return r;
2632
2633 j->fields_offset = le64toh(o->field.next_hash_offset);
2634 if (j->fields_offset == 0) {
2635 /* Reached the end of the hash table chain */
2636 j->fields_hash_table_index++;
2637 continue;
2638 }
2639 }
2640
2641 /* We use OBJECT_UNUSED here, so that the iteator below doesn't remove our mmap window */
2642 r = journal_file_move_to_object(f, OBJECT_UNUSED, j->fields_offset, &o);
2643 if (r < 0)
2644 return r;
2645
2646 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
2647 if (o->object.type != OBJECT_FIELD) {
2648 log_debug("%s:offset " OFSfmt ": object has type %i, expected %i", f->path, j->fields_offset, o->object.type, OBJECT_FIELD);
2649 return -EBADMSG;
2650 }
2651
2652 sz = le64toh(o->object.size) - offsetof(Object, field.payload);
2653
2654 /* Let's see if we already returned this field name before. */
2655 found = false;
2656 ORDERED_HASHMAP_FOREACH(of, j->files, i) {
2657 if (of == f)
2658 break;
2659
2660 /* Skip this file it didn't have any fields indexed */
2661 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0)
2662 continue;
2663
2664 r = journal_file_find_field_object_with_hash(of, o->field.payload, sz, le64toh(o->field.hash), NULL, NULL);
2665 if (r < 0)
2666 return r;
2667 if (r > 0) {
2668 found = true;
2669 break;
2670 }
2671 }
2672
2673 if (found)
2674 continue;
2675
2676 /* Check if this is really a valid string containing no NUL byte */
2677 if (memchr(o->field.payload, 0, sz))
2678 return -EBADMSG;
2679
2680 if (sz > j->data_threshold)
2681 sz = j->data_threshold;
2682
2683 if (!GREEDY_REALLOC(j->fields_buffer, j->fields_buffer_allocated, sz + 1))
2684 return -ENOMEM;
2685
2686 memcpy(j->fields_buffer, o->field.payload, sz);
2687 j->fields_buffer[sz] = 0;
2688
2689 if (!field_is_valid(j->fields_buffer))
2690 return -EBADMSG;
2691
2692 *field = j->fields_buffer;
2693 return 1;
2694 }
2695 }
2696
2697 _public_ void sd_journal_restart_fields(sd_journal *j) {
2698 if (!j)
2699 return;
2700
2701 j->fields_file = NULL;
2702 j->fields_hash_table_index = 0;
2703 j->fields_offset = 0;
2704 j->fields_file_lost = false;
2705 }
2706
2707 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2708 assert_return(j, -EINVAL);
2709 assert_return(!journal_pid_changed(j), -ECHILD);
2710
2711 return !j->on_network;
2712 }
2713
2714 static char *lookup_field(const char *field, void *userdata) {
2715 sd_journal *j = userdata;
2716 const void *data;
2717 size_t size, d;
2718 int r;
2719
2720 assert(field);
2721 assert(j);
2722
2723 r = sd_journal_get_data(j, field, &data, &size);
2724 if (r < 0 ||
2725 size > REPLACE_VAR_MAX)
2726 return strdup(field);
2727
2728 d = strlen(field) + 1;
2729
2730 return strndup((const char*) data + d, size - d);
2731 }
2732
2733 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2734 const void *data;
2735 size_t size;
2736 sd_id128_t id;
2737 _cleanup_free_ char *text = NULL, *cid = NULL;
2738 char *t;
2739 int r;
2740
2741 assert_return(j, -EINVAL);
2742 assert_return(!journal_pid_changed(j), -ECHILD);
2743 assert_return(ret, -EINVAL);
2744
2745 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2746 if (r < 0)
2747 return r;
2748
2749 cid = strndup((const char*) data + 11, size - 11);
2750 if (!cid)
2751 return -ENOMEM;
2752
2753 r = sd_id128_from_string(cid, &id);
2754 if (r < 0)
2755 return r;
2756
2757 r = catalog_get(CATALOG_DATABASE, id, &text);
2758 if (r < 0)
2759 return r;
2760
2761 t = replace_var(text, lookup_field, j);
2762 if (!t)
2763 return -ENOMEM;
2764
2765 *ret = t;
2766 return 0;
2767 }
2768
2769 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2770 assert_return(ret, -EINVAL);
2771
2772 return catalog_get(CATALOG_DATABASE, id, ret);
2773 }
2774
2775 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2776 assert_return(j, -EINVAL);
2777 assert_return(!journal_pid_changed(j), -ECHILD);
2778
2779 j->data_threshold = sz;
2780 return 0;
2781 }
2782
2783 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2784 assert_return(j, -EINVAL);
2785 assert_return(!journal_pid_changed(j), -ECHILD);
2786 assert_return(sz, -EINVAL);
2787
2788 *sz = j->data_threshold;
2789 return 0;
2790 }
2791
2792 _public_ int sd_journal_has_runtime_files(sd_journal *j) {
2793 assert_return(j, -EINVAL);
2794
2795 return j->has_runtime_files;
2796 }
2797
2798 _public_ int sd_journal_has_persistent_files(sd_journal *j) {
2799 assert_return(j, -EINVAL);
2800
2801 return j->has_persistent_files;
2802 }