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