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