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