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