]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/sd-journal.c
Merge pull request #7042 from vcaputo/iteratedcache
[thirdparty/systemd.git] / src / journal / sd-journal.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <linux/magic.h>
25 #include <poll.h>
26 #include <stddef.h>
27 #include <sys/inotify.h>
28 #include <sys/vfs.h>
29 #include <unistd.h>
30
31 #include "sd-journal.h"
32
33 #include "alloc-util.h"
34 #include "catalog.h"
35 #include "compress.h"
36 #include "dirent-util.h"
37 #include "fd-util.h"
38 #include "fileio.h"
39 #include "format-util.h"
40 #include "fs-util.h"
41 #include "hashmap.h"
42 #include "hostname-util.h"
43 #include "io-util.h"
44 #include "journal-def.h"
45 #include "journal-file.h"
46 #include "journal-internal.h"
47 #include "list.h"
48 #include "lookup3.h"
49 #include "missing.h"
50 #include "path-util.h"
51 #include "process-util.h"
52 #include "replace-var.h"
53 #include "stat-util.h"
54 #include "stdio-util.h"
55 #include "string-util.h"
56 #include "strv.h"
57
58 #define JOURNAL_FILES_MAX 7168
59
60 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
61
62 #define REPLACE_VAR_MAX 256
63
64 #define DEFAULT_DATA_THRESHOLD (64*1024)
65
66 static void remove_file_real(sd_journal *j, JournalFile *f);
67
68 static bool journal_pid_changed(sd_journal *j) {
69 assert(j);
70
71 /* We don't support people creating a journal object and
72 * keeping it around over a fork(). Let's complain. */
73
74 return j->original_pid != getpid_cached();
75 }
76
77 static int journal_put_error(sd_journal *j, int r, const char *path) {
78 char *copy;
79 int k;
80
81 /* Memorize an error we encountered, and store which
82 * file/directory it was generated from. Note that we store
83 * only *one* path per error code, as the error code is the
84 * key into the hashmap, and the path is the value. This means
85 * we keep track only of all error kinds, but not of all error
86 * locations. This has the benefit that the hashmap cannot
87 * grow beyond bounds.
88 *
89 * We return an error here only if we didn't manage to
90 * memorize the real error. */
91
92 if (r >= 0)
93 return r;
94
95 k = hashmap_ensure_allocated(&j->errors, NULL);
96 if (k < 0)
97 return k;
98
99 if (path) {
100 copy = strdup(path);
101 if (!copy)
102 return -ENOMEM;
103 } else
104 copy = NULL;
105
106 k = hashmap_put(j->errors, INT_TO_PTR(r), copy);
107 if (k < 0) {
108 free(copy);
109
110 if (k == -EEXIST)
111 return 0;
112
113 return k;
114 }
115
116 return 0;
117 }
118
119 static void detach_location(sd_journal *j) {
120 Iterator i;
121 JournalFile *f;
122
123 assert(j);
124
125 j->current_file = NULL;
126 j->current_field = 0;
127
128 ORDERED_HASHMAP_FOREACH(f, j->files, i)
129 journal_file_reset_location(f);
130 }
131
132 static void reset_location(sd_journal *j) {
133 assert(j);
134
135 detach_location(j);
136 zero(j->current_location);
137 }
138
139 static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
140 assert(l);
141 assert(IN_SET(type, LOCATION_DISCRETE, LOCATION_SEEK));
142 assert(f);
143 assert(o->object.type == OBJECT_ENTRY);
144
145 l->type = type;
146 l->seqnum = le64toh(o->entry.seqnum);
147 l->seqnum_id = f->header->seqnum_id;
148 l->realtime = le64toh(o->entry.realtime);
149 l->monotonic = le64toh(o->entry.monotonic);
150 l->boot_id = o->entry.boot_id;
151 l->xor_hash = le64toh(o->entry.xor_hash);
152
153 l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
154 }
155
156 static void set_location(sd_journal *j, JournalFile *f, Object *o) {
157 assert(j);
158 assert(f);
159 assert(o);
160
161 init_location(&j->current_location, LOCATION_DISCRETE, f, o);
162
163 j->current_file = f;
164 j->current_field = 0;
165
166 /* Let f know its candidate entry was picked. */
167 assert(f->location_type == LOCATION_SEEK);
168 f->location_type = LOCATION_DISCRETE;
169 }
170
171 static int match_is_valid(const void *data, size_t size) {
172 const char *b, *p;
173
174 assert(data);
175
176 if (size < 2)
177 return false;
178
179 if (startswith(data, "__"))
180 return false;
181
182 b = data;
183 for (p = b; p < b + size; p++) {
184
185 if (*p == '=')
186 return p > b;
187
188 if (*p == '_')
189 continue;
190
191 if (*p >= 'A' && *p <= 'Z')
192 continue;
193
194 if (*p >= '0' && *p <= '9')
195 continue;
196
197 return false;
198 }
199
200 return false;
201 }
202
203 static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
204 const uint8_t *a = _a, *b = _b;
205 size_t j;
206
207 for (j = 0; j < s && j < t; j++) {
208
209 if (a[j] != b[j])
210 return false;
211
212 if (a[j] == '=')
213 return true;
214 }
215
216 assert_not_reached("\"=\" not found");
217 }
218
219 static Match *match_new(Match *p, MatchType t) {
220 Match *m;
221
222 m = new0(Match, 1);
223 if (!m)
224 return NULL;
225
226 m->type = t;
227
228 if (p) {
229 m->parent = p;
230 LIST_PREPEND(matches, p->matches, m);
231 }
232
233 return m;
234 }
235
236 static void match_free(Match *m) {
237 assert(m);
238
239 while (m->matches)
240 match_free(m->matches);
241
242 if (m->parent)
243 LIST_REMOVE(matches, m->parent->matches, m);
244
245 free(m->data);
246 free(m);
247 }
248
249 static void match_free_if_empty(Match *m) {
250 if (!m || m->matches)
251 return;
252
253 match_free(m);
254 }
255
256 _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
257 Match *l3, *l4, *add_here = NULL, *m;
258 le64_t le_hash;
259
260 assert_return(j, -EINVAL);
261 assert_return(!journal_pid_changed(j), -ECHILD);
262 assert_return(data, -EINVAL);
263
264 if (size == 0)
265 size = strlen(data);
266
267 assert_return(match_is_valid(data, size), -EINVAL);
268
269 /* level 0: AND term
270 * level 1: OR terms
271 * level 2: AND terms
272 * level 3: OR terms
273 * level 4: concrete matches */
274
275 if (!j->level0) {
276 j->level0 = match_new(NULL, MATCH_AND_TERM);
277 if (!j->level0)
278 return -ENOMEM;
279 }
280
281 if (!j->level1) {
282 j->level1 = match_new(j->level0, MATCH_OR_TERM);
283 if (!j->level1)
284 return -ENOMEM;
285 }
286
287 if (!j->level2) {
288 j->level2 = match_new(j->level1, MATCH_AND_TERM);
289 if (!j->level2)
290 return -ENOMEM;
291 }
292
293 assert(j->level0->type == MATCH_AND_TERM);
294 assert(j->level1->type == MATCH_OR_TERM);
295 assert(j->level2->type == MATCH_AND_TERM);
296
297 le_hash = htole64(hash64(data, size));
298
299 LIST_FOREACH(matches, l3, j->level2->matches) {
300 assert(l3->type == MATCH_OR_TERM);
301
302 LIST_FOREACH(matches, l4, l3->matches) {
303 assert(l4->type == MATCH_DISCRETE);
304
305 /* Exactly the same match already? Then ignore
306 * this addition */
307 if (l4->le_hash == le_hash &&
308 l4->size == size &&
309 memcmp(l4->data, data, size) == 0)
310 return 0;
311
312 /* Same field? Then let's add this to this OR term */
313 if (same_field(data, size, l4->data, l4->size)) {
314 add_here = l3;
315 break;
316 }
317 }
318
319 if (add_here)
320 break;
321 }
322
323 if (!add_here) {
324 add_here = match_new(j->level2, MATCH_OR_TERM);
325 if (!add_here)
326 goto fail;
327 }
328
329 m = match_new(add_here, MATCH_DISCRETE);
330 if (!m)
331 goto fail;
332
333 m->le_hash = le_hash;
334 m->size = size;
335 m->data = memdup(data, size);
336 if (!m->data)
337 goto fail;
338
339 detach_location(j);
340
341 return 0;
342
343 fail:
344 match_free_if_empty(add_here);
345 match_free_if_empty(j->level2);
346 match_free_if_empty(j->level1);
347 match_free_if_empty(j->level0);
348
349 return -ENOMEM;
350 }
351
352 _public_ int sd_journal_add_conjunction(sd_journal *j) {
353 assert_return(j, -EINVAL);
354 assert_return(!journal_pid_changed(j), -ECHILD);
355
356 if (!j->level0)
357 return 0;
358
359 if (!j->level1)
360 return 0;
361
362 if (!j->level1->matches)
363 return 0;
364
365 j->level1 = NULL;
366 j->level2 = NULL;
367
368 return 0;
369 }
370
371 _public_ int sd_journal_add_disjunction(sd_journal *j) {
372 assert_return(j, -EINVAL);
373 assert_return(!journal_pid_changed(j), -ECHILD);
374
375 if (!j->level0)
376 return 0;
377
378 if (!j->level1)
379 return 0;
380
381 if (!j->level2)
382 return 0;
383
384 if (!j->level2->matches)
385 return 0;
386
387 j->level2 = NULL;
388 return 0;
389 }
390
391 static char *match_make_string(Match *m) {
392 char *p = NULL, *r;
393 Match *i;
394 bool enclose = false;
395
396 if (!m)
397 return strdup("none");
398
399 if (m->type == MATCH_DISCRETE)
400 return strndup(m->data, m->size);
401
402 LIST_FOREACH(matches, i, m->matches) {
403 char *t, *k;
404
405 t = match_make_string(i);
406 if (!t)
407 return mfree(p);
408
409 if (p) {
410 k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t);
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, ")");
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(IN_SET(l->type, LOCATION_DISCRETE, 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 *new_file = NULL;
824 unsigned i, n_files;
825 const void **files;
826 Object *o;
827 int r;
828
829 assert_return(j, -EINVAL);
830 assert_return(!journal_pid_changed(j), -ECHILD);
831
832 r = iterated_cache_get(j->files_cache, NULL, &files, &n_files);
833 if (r < 0)
834 return r;
835
836 for (i = 0; i < n_files; i++) {
837 JournalFile *f = (JournalFile *)files[i];
838 bool found;
839
840 r = next_beyond_location(j, f, direction);
841 if (r < 0) {
842 log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path);
843 remove_file_real(j, f);
844 continue;
845 } else if (r == 0) {
846 f->location_type = LOCATION_TAIL;
847 continue;
848 }
849
850 if (!new_file)
851 found = true;
852 else {
853 int k;
854
855 k = journal_file_compare_locations(f, new_file);
856
857 found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
858 }
859
860 if (found)
861 new_file = f;
862 }
863
864 if (!new_file)
865 return 0;
866
867 r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o);
868 if (r < 0)
869 return r;
870
871 set_location(j, new_file, o);
872
873 return 1;
874 }
875
876 _public_ int sd_journal_next(sd_journal *j) {
877 return real_journal_next(j, DIRECTION_DOWN);
878 }
879
880 _public_ int sd_journal_previous(sd_journal *j) {
881 return real_journal_next(j, DIRECTION_UP);
882 }
883
884 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
885 int c = 0, r;
886
887 assert_return(j, -EINVAL);
888 assert_return(!journal_pid_changed(j), -ECHILD);
889
890 if (skip == 0) {
891 /* If this is not a discrete skip, then at least
892 * resolve the current location */
893 if (j->current_location.type != LOCATION_DISCRETE) {
894 r = real_journal_next(j, direction);
895 if (r < 0)
896 return r;
897 }
898
899 return 0;
900 }
901
902 do {
903 r = real_journal_next(j, direction);
904 if (r < 0)
905 return r;
906
907 if (r == 0)
908 return c;
909
910 skip--;
911 c++;
912 } while (skip > 0);
913
914 return c;
915 }
916
917 _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
918 return real_journal_next_skip(j, DIRECTION_DOWN, skip);
919 }
920
921 _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
922 return real_journal_next_skip(j, DIRECTION_UP, skip);
923 }
924
925 _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
926 Object *o;
927 int r;
928 char bid[33], sid[33];
929
930 assert_return(j, -EINVAL);
931 assert_return(!journal_pid_changed(j), -ECHILD);
932 assert_return(cursor, -EINVAL);
933
934 if (!j->current_file || j->current_file->current_offset <= 0)
935 return -EADDRNOTAVAIL;
936
937 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
938 if (r < 0)
939 return r;
940
941 sd_id128_to_string(j->current_file->header->seqnum_id, sid);
942 sd_id128_to_string(o->entry.boot_id, bid);
943
944 if (asprintf(cursor,
945 "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
946 sid, le64toh(o->entry.seqnum),
947 bid, le64toh(o->entry.monotonic),
948 le64toh(o->entry.realtime),
949 le64toh(o->entry.xor_hash)) < 0)
950 return -ENOMEM;
951
952 return 0;
953 }
954
955 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
956 const char *word, *state;
957 size_t l;
958 unsigned long long seqnum, monotonic, realtime, xor_hash;
959 bool
960 seqnum_id_set = false,
961 seqnum_set = false,
962 boot_id_set = false,
963 monotonic_set = false,
964 realtime_set = false,
965 xor_hash_set = false;
966 sd_id128_t seqnum_id, boot_id;
967
968 assert_return(j, -EINVAL);
969 assert_return(!journal_pid_changed(j), -ECHILD);
970 assert_return(!isempty(cursor), -EINVAL);
971
972 FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
973 char *item;
974 int k = 0;
975
976 if (l < 2 || word[1] != '=')
977 return -EINVAL;
978
979 item = strndup(word, l);
980 if (!item)
981 return -ENOMEM;
982
983 switch (word[0]) {
984
985 case 's':
986 seqnum_id_set = true;
987 k = sd_id128_from_string(item+2, &seqnum_id);
988 break;
989
990 case 'i':
991 seqnum_set = true;
992 if (sscanf(item+2, "%llx", &seqnum) != 1)
993 k = -EINVAL;
994 break;
995
996 case 'b':
997 boot_id_set = true;
998 k = sd_id128_from_string(item+2, &boot_id);
999 break;
1000
1001 case 'm':
1002 monotonic_set = true;
1003 if (sscanf(item+2, "%llx", &monotonic) != 1)
1004 k = -EINVAL;
1005 break;
1006
1007 case 't':
1008 realtime_set = true;
1009 if (sscanf(item+2, "%llx", &realtime) != 1)
1010 k = -EINVAL;
1011 break;
1012
1013 case 'x':
1014 xor_hash_set = true;
1015 if (sscanf(item+2, "%llx", &xor_hash) != 1)
1016 k = -EINVAL;
1017 break;
1018 }
1019
1020 free(item);
1021
1022 if (k < 0)
1023 return k;
1024 }
1025
1026 if ((!seqnum_set || !seqnum_id_set) &&
1027 (!monotonic_set || !boot_id_set) &&
1028 !realtime_set)
1029 return -EINVAL;
1030
1031 reset_location(j);
1032
1033 j->current_location.type = LOCATION_SEEK;
1034
1035 if (realtime_set) {
1036 j->current_location.realtime = (uint64_t) realtime;
1037 j->current_location.realtime_set = true;
1038 }
1039
1040 if (seqnum_set && seqnum_id_set) {
1041 j->current_location.seqnum = (uint64_t) seqnum;
1042 j->current_location.seqnum_id = seqnum_id;
1043 j->current_location.seqnum_set = true;
1044 }
1045
1046 if (monotonic_set && boot_id_set) {
1047 j->current_location.monotonic = (uint64_t) monotonic;
1048 j->current_location.boot_id = boot_id;
1049 j->current_location.monotonic_set = true;
1050 }
1051
1052 if (xor_hash_set) {
1053 j->current_location.xor_hash = (uint64_t) xor_hash;
1054 j->current_location.xor_hash_set = true;
1055 }
1056
1057 return 0;
1058 }
1059
1060 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1061 int r;
1062 Object *o;
1063
1064 assert_return(j, -EINVAL);
1065 assert_return(!journal_pid_changed(j), -ECHILD);
1066 assert_return(!isempty(cursor), -EINVAL);
1067
1068 if (!j->current_file || j->current_file->current_offset <= 0)
1069 return -EADDRNOTAVAIL;
1070
1071 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1072 if (r < 0)
1073 return r;
1074
1075 for (;;) {
1076 _cleanup_free_ char *item = NULL;
1077 unsigned long long ll;
1078 sd_id128_t id;
1079 int k = 0;
1080
1081 r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
1082 if (r < 0)
1083 return r;
1084
1085 if (r == 0)
1086 break;
1087
1088 if (strlen(item) < 2 || item[1] != '=')
1089 return -EINVAL;
1090
1091 switch (item[0]) {
1092
1093 case 's':
1094 k = sd_id128_from_string(item+2, &id);
1095 if (k < 0)
1096 return k;
1097 if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1098 return 0;
1099 break;
1100
1101 case 'i':
1102 if (sscanf(item+2, "%llx", &ll) != 1)
1103 return -EINVAL;
1104 if (ll != le64toh(o->entry.seqnum))
1105 return 0;
1106 break;
1107
1108 case 'b':
1109 k = sd_id128_from_string(item+2, &id);
1110 if (k < 0)
1111 return k;
1112 if (!sd_id128_equal(id, o->entry.boot_id))
1113 return 0;
1114 break;
1115
1116 case 'm':
1117 if (sscanf(item+2, "%llx", &ll) != 1)
1118 return -EINVAL;
1119 if (ll != le64toh(o->entry.monotonic))
1120 return 0;
1121 break;
1122
1123 case 't':
1124 if (sscanf(item+2, "%llx", &ll) != 1)
1125 return -EINVAL;
1126 if (ll != le64toh(o->entry.realtime))
1127 return 0;
1128 break;
1129
1130 case 'x':
1131 if (sscanf(item+2, "%llx", &ll) != 1)
1132 return -EINVAL;
1133 if (ll != le64toh(o->entry.xor_hash))
1134 return 0;
1135 break;
1136 }
1137 }
1138
1139 return 1;
1140 }
1141
1142
1143 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1144 assert_return(j, -EINVAL);
1145 assert_return(!journal_pid_changed(j), -ECHILD);
1146
1147 reset_location(j);
1148 j->current_location.type = LOCATION_SEEK;
1149 j->current_location.boot_id = boot_id;
1150 j->current_location.monotonic = usec;
1151 j->current_location.monotonic_set = true;
1152
1153 return 0;
1154 }
1155
1156 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
1157 assert_return(j, -EINVAL);
1158 assert_return(!journal_pid_changed(j), -ECHILD);
1159
1160 reset_location(j);
1161 j->current_location.type = LOCATION_SEEK;
1162 j->current_location.realtime = usec;
1163 j->current_location.realtime_set = true;
1164
1165 return 0;
1166 }
1167
1168 _public_ int sd_journal_seek_head(sd_journal *j) {
1169 assert_return(j, -EINVAL);
1170 assert_return(!journal_pid_changed(j), -ECHILD);
1171
1172 reset_location(j);
1173 j->current_location.type = LOCATION_HEAD;
1174
1175 return 0;
1176 }
1177
1178 _public_ int sd_journal_seek_tail(sd_journal *j) {
1179 assert_return(j, -EINVAL);
1180 assert_return(!journal_pid_changed(j), -ECHILD);
1181
1182 reset_location(j);
1183 j->current_location.type = LOCATION_TAIL;
1184
1185 return 0;
1186 }
1187
1188 static void check_network(sd_journal *j, int fd) {
1189 struct statfs sfs;
1190
1191 assert(j);
1192
1193 if (j->on_network)
1194 return;
1195
1196 if (fstatfs(fd, &sfs) < 0)
1197 return;
1198
1199 j->on_network =
1200 F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) ||
1201 F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) ||
1202 F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) ||
1203 F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) ||
1204 F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC);
1205 }
1206
1207 static bool file_has_type_prefix(const char *prefix, const char *filename) {
1208 const char *full, *tilded, *atted;
1209
1210 full = strjoina(prefix, ".journal");
1211 tilded = strjoina(full, "~");
1212 atted = strjoina(prefix, "@");
1213
1214 return streq(filename, full) ||
1215 streq(filename, tilded) ||
1216 startswith(filename, atted);
1217 }
1218
1219 static bool file_type_wanted(int flags, const char *filename) {
1220 assert(filename);
1221
1222 if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1223 return false;
1224
1225 /* no flags set → every type is OK */
1226 if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1227 return true;
1228
1229 if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1230 return true;
1231
1232 if (flags & SD_JOURNAL_CURRENT_USER) {
1233 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1234
1235 xsprintf(prefix, "user-"UID_FMT, getuid());
1236
1237 if (file_has_type_prefix(prefix, filename))
1238 return true;
1239 }
1240
1241 return false;
1242 }
1243
1244 static bool path_has_prefix(sd_journal *j, const char *path, const char *prefix) {
1245 assert(j);
1246 assert(path);
1247 assert(prefix);
1248
1249 if (j->toplevel_fd >= 0)
1250 return false;
1251
1252 return path_startswith(path, prefix);
1253 }
1254
1255 static const char *skip_slash(const char *p) {
1256
1257 if (!p)
1258 return NULL;
1259
1260 while (*p == '/')
1261 p++;
1262
1263 return p;
1264 }
1265
1266 static int add_any_file(sd_journal *j, int fd, const char *path) {
1267 JournalFile *f = NULL;
1268 bool close_fd = false;
1269 int r, k;
1270
1271 assert(j);
1272 assert(fd >= 0 || path);
1273
1274 if (path && ordered_hashmap_get(j->files, path))
1275 return 0;
1276
1277 if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1278 log_debug("Too many open journal files, not adding %s.", path);
1279 r = -ETOOMANYREFS;
1280 goto fail;
1281 }
1282
1283 if (fd < 0 && j->toplevel_fd >= 0) {
1284
1285 /* If there's a top-level fd defined, open the file relative to this now. (Make the path relative,
1286 * explicitly, since otherwise openat() ignores the first argument.) */
1287
1288 fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC);
1289 if (fd < 0) {
1290 r = log_debug_errno(errno, "Failed to open journal file %s: %m", path);
1291 goto fail;
1292 }
1293
1294 close_fd = true;
1295 }
1296
1297 r = journal_file_open(fd, path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f);
1298 if (r < 0) {
1299 if (close_fd)
1300 safe_close(fd);
1301 log_debug_errno(r, "Failed to open journal file %s: %m", path);
1302 goto fail;
1303 }
1304
1305 /* journal_file_dump(f); */
1306
1307 r = ordered_hashmap_put(j->files, f->path, f);
1308 if (r < 0) {
1309 f->close_fd = close_fd;
1310 (void) journal_file_close(f);
1311 goto fail;
1312 }
1313
1314 if (!j->has_runtime_files && path_has_prefix(j, f->path, "/run"))
1315 j->has_runtime_files = true;
1316 else if (!j->has_persistent_files && path_has_prefix(j, f->path, "/var"))
1317 j->has_persistent_files = true;
1318
1319 log_debug("File %s added.", f->path);
1320
1321 check_network(j, f->fd);
1322
1323 j->current_invalidate_counter++;
1324
1325 return 0;
1326
1327 fail:
1328 k = journal_put_error(j, r, path);
1329 if (k < 0)
1330 return k;
1331
1332 return r;
1333 }
1334
1335 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
1336 const char *path;
1337
1338 assert(j);
1339 assert(prefix);
1340 assert(filename);
1341
1342 if (j->no_new_files)
1343 return 0;
1344
1345 if (!file_type_wanted(j->flags, filename))
1346 return 0;
1347
1348 path = strjoina(prefix, "/", filename);
1349 return add_any_file(j, -1, path);
1350 }
1351
1352 static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
1353 const char *path;
1354 JournalFile *f;
1355
1356 assert(j);
1357 assert(prefix);
1358 assert(filename);
1359
1360 path = strjoina(prefix, "/", filename);
1361 f = ordered_hashmap_get(j->files, path);
1362 if (!f)
1363 return;
1364
1365 remove_file_real(j, f);
1366 }
1367
1368 static void remove_file_real(sd_journal *j, JournalFile *f) {
1369 assert(j);
1370 assert(f);
1371
1372 ordered_hashmap_remove(j->files, f->path);
1373
1374 log_debug("File %s removed.", f->path);
1375
1376 if (j->current_file == f) {
1377 j->current_file = NULL;
1378 j->current_field = 0;
1379 }
1380
1381 if (j->unique_file == f) {
1382 /* Jump to the next unique_file or NULL if that one was last */
1383 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
1384 j->unique_offset = 0;
1385 if (!j->unique_file)
1386 j->unique_file_lost = true;
1387 }
1388
1389 if (j->fields_file == f) {
1390 j->fields_file = ordered_hashmap_next(j->files, j->fields_file->path);
1391 j->fields_offset = 0;
1392 if (!j->fields_file)
1393 j->fields_file_lost = true;
1394 }
1395
1396 (void) journal_file_close(f);
1397
1398 j->current_invalidate_counter++;
1399 }
1400
1401 static int dirname_is_machine_id(const char *fn) {
1402 sd_id128_t id, machine;
1403 int r;
1404
1405 r = sd_id128_get_machine(&machine);
1406 if (r < 0)
1407 return r;
1408
1409 r = sd_id128_from_string(fn, &id);
1410 if (r < 0)
1411 return r;
1412
1413 return sd_id128_equal(id, machine);
1414 }
1415
1416 static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
1417 _cleanup_free_ char *path = NULL;
1418 _cleanup_closedir_ DIR *d = NULL;
1419 struct dirent *de = NULL;
1420 Directory *m;
1421 int r, k;
1422
1423 assert(j);
1424 assert(prefix);
1425
1426 /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
1427 * and reenumerates directory contents */
1428
1429 if (dirname)
1430 path = strjoin(prefix, "/", dirname);
1431 else
1432 path = strdup(prefix);
1433 if (!path) {
1434 r = -ENOMEM;
1435 goto fail;
1436 }
1437
1438 log_debug("Considering directory %s.", path);
1439
1440 /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
1441 if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
1442 !((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
1443 return 0;
1444
1445
1446 if (j->toplevel_fd < 0)
1447 d = opendir(path);
1448 else
1449 /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
1450 * relative, by dropping the initial slash */
1451 d = xopendirat(j->toplevel_fd, skip_slash(path), 0);
1452 if (!d) {
1453 r = log_debug_errno(errno, "Failed to open directory %s: %m", path);
1454 goto fail;
1455 }
1456
1457 m = hashmap_get(j->directories_by_path, path);
1458 if (!m) {
1459 m = new0(Directory, 1);
1460 if (!m) {
1461 r = -ENOMEM;
1462 goto fail;
1463 }
1464
1465 m->is_root = false;
1466 m->path = path;
1467
1468 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1469 free(m);
1470 r = -ENOMEM;
1471 goto fail;
1472 }
1473
1474 path = NULL; /* avoid freeing in cleanup */
1475 j->current_invalidate_counter++;
1476
1477 log_debug("Directory %s added.", m->path);
1478
1479 } else if (m->is_root)
1480 return 0;
1481
1482 if (m->wd <= 0 && j->inotify_fd >= 0) {
1483 /* Watch this directory, if it not being watched yet. */
1484
1485 m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d),
1486 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1487 IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
1488 IN_ONLYDIR);
1489
1490 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1491 inotify_rm_watch(j->inotify_fd, m->wd);
1492 }
1493
1494 FOREACH_DIRENT_ALL(de, d, r = log_debug_errno(errno, "Failed to read directory %s: %m", m->path); goto fail) {
1495
1496 if (dirent_is_file_with_suffix(de, ".journal") ||
1497 dirent_is_file_with_suffix(de, ".journal~"))
1498 (void) add_file(j, m->path, de->d_name);
1499 }
1500
1501 check_network(j, dirfd(d));
1502
1503 return 0;
1504
1505 fail:
1506 k = journal_put_error(j, r, path ?: prefix);
1507 if (k < 0)
1508 return k;
1509
1510 return r;
1511 }
1512
1513 static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
1514
1515 _cleanup_closedir_ DIR *d = NULL;
1516 struct dirent *de;
1517 Directory *m;
1518 int r, k;
1519
1520 assert(j);
1521
1522 /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
1523 * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
1524 * populate the set, as well as to update it later. */
1525
1526 if (p) {
1527 /* If there's a path specified, use it. */
1528
1529 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1530 !path_has_prefix(j, p, "/run"))
1531 return -EINVAL;
1532
1533 if (j->prefix)
1534 p = strjoina(j->prefix, p);
1535
1536 if (j->toplevel_fd < 0)
1537 d = opendir(p);
1538 else
1539 d = xopendirat(j->toplevel_fd, skip_slash(p), 0);
1540
1541 if (!d) {
1542 if (errno == ENOENT && missing_ok)
1543 return 0;
1544
1545 r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
1546 goto fail;
1547 }
1548 } else {
1549 int dfd;
1550
1551 /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
1552 * opendir() will take possession of the fd, and close it, which we don't want. */
1553
1554 p = "."; /* store this as "." in the directories hashmap */
1555
1556 dfd = fcntl(j->toplevel_fd, F_DUPFD_CLOEXEC, 3);
1557 if (dfd < 0) {
1558 r = -errno;
1559 goto fail;
1560 }
1561
1562 d = fdopendir(dfd);
1563 if (!d) {
1564 r = -errno;
1565 safe_close(dfd);
1566 goto fail;
1567 }
1568
1569 rewinddir(d);
1570 }
1571
1572 m = hashmap_get(j->directories_by_path, p);
1573 if (!m) {
1574 m = new0(Directory, 1);
1575 if (!m) {
1576 r = -ENOMEM;
1577 goto fail;
1578 }
1579
1580 m->is_root = true;
1581
1582 m->path = strdup(p);
1583 if (!m->path) {
1584 free(m);
1585 r = -ENOMEM;
1586 goto fail;
1587 }
1588
1589 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1590 free(m->path);
1591 free(m);
1592 r = -ENOMEM;
1593 goto fail;
1594 }
1595
1596 j->current_invalidate_counter++;
1597
1598 log_debug("Root directory %s added.", m->path);
1599
1600 } else if (!m->is_root)
1601 return 0;
1602
1603 if (m->wd <= 0 && j->inotify_fd >= 0) {
1604
1605 m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d),
1606 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1607 IN_ONLYDIR);
1608
1609 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1610 inotify_rm_watch(j->inotify_fd, m->wd);
1611 }
1612
1613 if (j->no_new_files)
1614 return 0;
1615
1616 FOREACH_DIRENT_ALL(de, d, r = log_debug_errno(errno, "Failed to read directory %s: %m", m->path); goto fail) {
1617 sd_id128_t id;
1618
1619 if (dirent_is_file_with_suffix(de, ".journal") ||
1620 dirent_is_file_with_suffix(de, ".journal~"))
1621 (void) add_file(j, m->path, de->d_name);
1622 else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) &&
1623 sd_id128_from_string(de->d_name, &id) >= 0)
1624 (void) add_directory(j, m->path, de->d_name);
1625 }
1626
1627 check_network(j, dirfd(d));
1628
1629 return 0;
1630
1631 fail:
1632 k = journal_put_error(j, r, p);
1633 if (k < 0)
1634 return k;
1635
1636 return r;
1637 }
1638
1639 static void remove_directory(sd_journal *j, Directory *d) {
1640 assert(j);
1641
1642 if (d->wd > 0) {
1643 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1644
1645 if (j->inotify_fd >= 0)
1646 inotify_rm_watch(j->inotify_fd, d->wd);
1647 }
1648
1649 hashmap_remove(j->directories_by_path, d->path);
1650
1651 if (d->is_root)
1652 log_debug("Root directory %s removed.", d->path);
1653 else
1654 log_debug("Directory %s removed.", d->path);
1655
1656 free(d->path);
1657 free(d);
1658 }
1659
1660 static int add_search_paths(sd_journal *j) {
1661
1662 static const char search_paths[] =
1663 "/run/log/journal\0"
1664 "/var/log/journal\0";
1665 const char *p;
1666
1667 assert(j);
1668
1669 /* We ignore most errors here, since the idea is to only open
1670 * what's actually accessible, and ignore the rest. */
1671
1672 NULSTR_FOREACH(p, search_paths)
1673 (void) add_root_directory(j, p, true);
1674
1675 if (!(j->flags & SD_JOURNAL_LOCAL_ONLY))
1676 (void) add_root_directory(j, "/var/log/journal/remote", true);
1677
1678 return 0;
1679 }
1680
1681 static int add_current_paths(sd_journal *j) {
1682 Iterator i;
1683 JournalFile *f;
1684
1685 assert(j);
1686 assert(j->no_new_files);
1687
1688 /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
1689 * treat them as fatal. */
1690
1691 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
1692 _cleanup_free_ char *dir;
1693 int r;
1694
1695 dir = dirname_malloc(f->path);
1696 if (!dir)
1697 return -ENOMEM;
1698
1699 r = add_directory(j, dir, NULL);
1700 if (r < 0)
1701 return r;
1702 }
1703
1704 return 0;
1705 }
1706
1707 static int allocate_inotify(sd_journal *j) {
1708 assert(j);
1709
1710 if (j->inotify_fd < 0) {
1711 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1712 if (j->inotify_fd < 0)
1713 return -errno;
1714 }
1715
1716 return hashmap_ensure_allocated(&j->directories_by_wd, NULL);
1717 }
1718
1719 static sd_journal *journal_new(int flags, const char *path) {
1720 sd_journal *j;
1721
1722 j = new0(sd_journal, 1);
1723 if (!j)
1724 return NULL;
1725
1726 j->original_pid = getpid_cached();
1727 j->toplevel_fd = -1;
1728 j->inotify_fd = -1;
1729 j->flags = flags;
1730 j->data_threshold = DEFAULT_DATA_THRESHOLD;
1731
1732 if (path) {
1733 char *t;
1734
1735 t = strdup(path);
1736 if (!t)
1737 goto fail;
1738
1739 if (flags & SD_JOURNAL_OS_ROOT)
1740 j->prefix = t;
1741 else
1742 j->path = t;
1743 }
1744
1745 j->files = ordered_hashmap_new(&string_hash_ops);
1746 if (!j->files)
1747 goto fail;
1748
1749 j->files_cache = ordered_hashmap_iterated_cache_new(j->files);
1750 j->directories_by_path = hashmap_new(&string_hash_ops);
1751 j->mmap = mmap_cache_new();
1752 if (!j->files_cache || !j->directories_by_path || !j->mmap)
1753 goto fail;
1754
1755 return j;
1756
1757 fail:
1758 sd_journal_close(j);
1759 return NULL;
1760 }
1761
1762 #define OPEN_ALLOWED_FLAGS \
1763 (SD_JOURNAL_LOCAL_ONLY | \
1764 SD_JOURNAL_RUNTIME_ONLY | \
1765 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)
1766
1767 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1768 sd_journal *j;
1769 int r;
1770
1771 assert_return(ret, -EINVAL);
1772 assert_return((flags & ~OPEN_ALLOWED_FLAGS) == 0, -EINVAL);
1773
1774 j = journal_new(flags, NULL);
1775 if (!j)
1776 return -ENOMEM;
1777
1778 r = add_search_paths(j);
1779 if (r < 0)
1780 goto fail;
1781
1782 *ret = j;
1783 return 0;
1784
1785 fail:
1786 sd_journal_close(j);
1787
1788 return r;
1789 }
1790
1791 #define OPEN_CONTAINER_ALLOWED_FLAGS \
1792 (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
1793
1794 _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
1795 _cleanup_free_ char *root = NULL, *class = NULL;
1796 sd_journal *j;
1797 char *p;
1798 int r;
1799
1800 /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
1801 * combination with sd_journal_open_directory_fd(). */
1802
1803 assert_return(machine, -EINVAL);
1804 assert_return(ret, -EINVAL);
1805 assert_return((flags & ~OPEN_CONTAINER_ALLOWED_FLAGS) == 0, -EINVAL);
1806 assert_return(machine_name_is_valid(machine), -EINVAL);
1807
1808 p = strjoina("/run/systemd/machines/", machine);
1809 r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL);
1810 if (r == -ENOENT)
1811 return -EHOSTDOWN;
1812 if (r < 0)
1813 return r;
1814 if (!root)
1815 return -ENODATA;
1816
1817 if (!streq_ptr(class, "container"))
1818 return -EIO;
1819
1820 j = journal_new(flags, root);
1821 if (!j)
1822 return -ENOMEM;
1823
1824 r = add_search_paths(j);
1825 if (r < 0)
1826 goto fail;
1827
1828 *ret = j;
1829 return 0;
1830
1831 fail:
1832 sd_journal_close(j);
1833 return r;
1834 }
1835
1836 #define OPEN_DIRECTORY_ALLOWED_FLAGS \
1837 (SD_JOURNAL_OS_ROOT | \
1838 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1839
1840 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1841 sd_journal *j;
1842 int r;
1843
1844 assert_return(ret, -EINVAL);
1845 assert_return(path, -EINVAL);
1846 assert_return((flags & ~OPEN_DIRECTORY_ALLOWED_FLAGS) == 0, -EINVAL);
1847
1848 j = journal_new(flags, path);
1849 if (!j)
1850 return -ENOMEM;
1851
1852 if (flags & SD_JOURNAL_OS_ROOT)
1853 r = add_search_paths(j);
1854 else
1855 r = add_root_directory(j, path, false);
1856 if (r < 0)
1857 goto fail;
1858
1859 *ret = j;
1860 return 0;
1861
1862 fail:
1863 sd_journal_close(j);
1864 return r;
1865 }
1866
1867 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1868 sd_journal *j;
1869 const char **path;
1870 int r;
1871
1872 assert_return(ret, -EINVAL);
1873 assert_return(flags == 0, -EINVAL);
1874
1875 j = journal_new(flags, NULL);
1876 if (!j)
1877 return -ENOMEM;
1878
1879 STRV_FOREACH(path, paths) {
1880 r = add_any_file(j, -1, *path);
1881 if (r < 0)
1882 goto fail;
1883 }
1884
1885 j->no_new_files = true;
1886
1887 *ret = j;
1888 return 0;
1889
1890 fail:
1891 sd_journal_close(j);
1892 return r;
1893 }
1894
1895 #define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
1896 (SD_JOURNAL_OS_ROOT | \
1897 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1898
1899 _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
1900 sd_journal *j;
1901 struct stat st;
1902 int r;
1903
1904 assert_return(ret, -EINVAL);
1905 assert_return(fd >= 0, -EBADF);
1906 assert_return((flags & ~OPEN_DIRECTORY_FD_ALLOWED_FLAGS) == 0, -EINVAL);
1907
1908 if (fstat(fd, &st) < 0)
1909 return -errno;
1910
1911 if (!S_ISDIR(st.st_mode))
1912 return -EBADFD;
1913
1914 j = journal_new(flags, NULL);
1915 if (!j)
1916 return -ENOMEM;
1917
1918 j->toplevel_fd = fd;
1919
1920 if (flags & SD_JOURNAL_OS_ROOT)
1921 r = add_search_paths(j);
1922 else
1923 r = add_root_directory(j, NULL, false);
1924 if (r < 0)
1925 goto fail;
1926
1927 *ret = j;
1928 return 0;
1929
1930 fail:
1931 sd_journal_close(j);
1932 return r;
1933 }
1934
1935 _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags) {
1936 Iterator iterator;
1937 JournalFile *f;
1938 sd_journal *j;
1939 unsigned i;
1940 int r;
1941
1942 assert_return(ret, -EINVAL);
1943 assert_return(n_fds > 0, -EBADF);
1944 assert_return(flags == 0, -EINVAL);
1945
1946 j = journal_new(flags, NULL);
1947 if (!j)
1948 return -ENOMEM;
1949
1950 for (i = 0; i < n_fds; i++) {
1951 struct stat st;
1952
1953 if (fds[i] < 0) {
1954 r = -EBADF;
1955 goto fail;
1956 }
1957
1958 if (fstat(fds[i], &st) < 0) {
1959 r = -errno;
1960 goto fail;
1961 }
1962
1963 if (!S_ISREG(st.st_mode)) {
1964 r = -EBADFD;
1965 goto fail;
1966 }
1967
1968 r = add_any_file(j, fds[i], NULL);
1969 if (r < 0)
1970 goto fail;
1971 }
1972
1973 j->no_new_files = true;
1974 j->no_inotify = true;
1975
1976 *ret = j;
1977 return 0;
1978
1979 fail:
1980 /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
1981 * remain open */
1982 ORDERED_HASHMAP_FOREACH(f, j->files, iterator)
1983 f->close_fd = false;
1984
1985 sd_journal_close(j);
1986 return r;
1987 }
1988
1989 _public_ void sd_journal_close(sd_journal *j) {
1990 Directory *d;
1991
1992 if (!j)
1993 return;
1994
1995 sd_journal_flush_matches(j);
1996
1997 ordered_hashmap_free_with_destructor(j->files, journal_file_close);
1998 iterated_cache_free(j->files_cache);
1999
2000 while ((d = hashmap_first(j->directories_by_path)))
2001 remove_directory(j, d);
2002
2003 while ((d = hashmap_first(j->directories_by_wd)))
2004 remove_directory(j, d);
2005
2006 hashmap_free(j->directories_by_path);
2007 hashmap_free(j->directories_by_wd);
2008
2009 safe_close(j->inotify_fd);
2010
2011 if (j->mmap) {
2012 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
2013 mmap_cache_unref(j->mmap);
2014 }
2015
2016 hashmap_free_free(j->errors);
2017
2018 free(j->path);
2019 free(j->prefix);
2020 free(j->unique_field);
2021 free(j->fields_buffer);
2022 free(j);
2023 }
2024
2025 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
2026 Object *o;
2027 JournalFile *f;
2028 int r;
2029
2030 assert_return(j, -EINVAL);
2031 assert_return(!journal_pid_changed(j), -ECHILD);
2032 assert_return(ret, -EINVAL);
2033
2034 f = j->current_file;
2035 if (!f)
2036 return -EADDRNOTAVAIL;
2037
2038 if (f->current_offset <= 0)
2039 return -EADDRNOTAVAIL;
2040
2041 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2042 if (r < 0)
2043 return r;
2044
2045 *ret = le64toh(o->entry.realtime);
2046 return 0;
2047 }
2048
2049 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
2050 Object *o;
2051 JournalFile *f;
2052 int r;
2053 sd_id128_t id;
2054
2055 assert_return(j, -EINVAL);
2056 assert_return(!journal_pid_changed(j), -ECHILD);
2057
2058 f = j->current_file;
2059 if (!f)
2060 return -EADDRNOTAVAIL;
2061
2062 if (f->current_offset <= 0)
2063 return -EADDRNOTAVAIL;
2064
2065 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2066 if (r < 0)
2067 return r;
2068
2069 if (ret_boot_id)
2070 *ret_boot_id = o->entry.boot_id;
2071 else {
2072 r = sd_id128_get_boot(&id);
2073 if (r < 0)
2074 return r;
2075
2076 if (!sd_id128_equal(id, o->entry.boot_id))
2077 return -ESTALE;
2078 }
2079
2080 if (ret)
2081 *ret = le64toh(o->entry.monotonic);
2082
2083 return 0;
2084 }
2085
2086 static bool field_is_valid(const char *field) {
2087 const char *p;
2088
2089 assert(field);
2090
2091 if (isempty(field))
2092 return false;
2093
2094 if (startswith(field, "__"))
2095 return false;
2096
2097 for (p = field; *p; p++) {
2098
2099 if (*p == '_')
2100 continue;
2101
2102 if (*p >= 'A' && *p <= 'Z')
2103 continue;
2104
2105 if (*p >= '0' && *p <= '9')
2106 continue;
2107
2108 return false;
2109 }
2110
2111 return true;
2112 }
2113
2114 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
2115 JournalFile *f;
2116 uint64_t i, n;
2117 size_t field_length;
2118 int r;
2119 Object *o;
2120
2121 assert_return(j, -EINVAL);
2122 assert_return(!journal_pid_changed(j), -ECHILD);
2123 assert_return(field, -EINVAL);
2124 assert_return(data, -EINVAL);
2125 assert_return(size, -EINVAL);
2126 assert_return(field_is_valid(field), -EINVAL);
2127
2128 f = j->current_file;
2129 if (!f)
2130 return -EADDRNOTAVAIL;
2131
2132 if (f->current_offset <= 0)
2133 return -EADDRNOTAVAIL;
2134
2135 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2136 if (r < 0)
2137 return r;
2138
2139 field_length = strlen(field);
2140
2141 n = journal_file_entry_n_items(o);
2142 for (i = 0; i < n; i++) {
2143 uint64_t p, l;
2144 le64_t le_hash;
2145 size_t t;
2146 int compression;
2147
2148 p = le64toh(o->entry.items[i].object_offset);
2149 le_hash = o->entry.items[i].hash;
2150 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2151 if (r < 0)
2152 return r;
2153
2154 if (le_hash != o->data.hash)
2155 return -EBADMSG;
2156
2157 l = le64toh(o->object.size) - offsetof(Object, data.payload);
2158
2159 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
2160 if (compression) {
2161 #if HAVE_XZ || HAVE_LZ4
2162 r = decompress_startswith(compression,
2163 o->data.payload, l,
2164 &f->compress_buffer, &f->compress_buffer_size,
2165 field, field_length, '=');
2166 if (r < 0)
2167 log_debug_errno(r, "Cannot decompress %s object of length %"PRIu64" at offset "OFSfmt": %m",
2168 object_compressed_to_string(compression), l, p);
2169 else if (r > 0) {
2170
2171 size_t rsize;
2172
2173 r = decompress_blob(compression,
2174 o->data.payload, l,
2175 &f->compress_buffer, &f->compress_buffer_size, &rsize,
2176 j->data_threshold);
2177 if (r < 0)
2178 return r;
2179
2180 *data = f->compress_buffer;
2181 *size = (size_t) rsize;
2182
2183 return 0;
2184 }
2185 #else
2186 return -EPROTONOSUPPORT;
2187 #endif
2188 } else if (l >= field_length+1 &&
2189 memcmp(o->data.payload, field, field_length) == 0 &&
2190 o->data.payload[field_length] == '=') {
2191
2192 t = (size_t) l;
2193
2194 if ((uint64_t) t != l)
2195 return -E2BIG;
2196
2197 *data = o->data.payload;
2198 *size = t;
2199
2200 return 0;
2201 }
2202
2203 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2204 if (r < 0)
2205 return r;
2206 }
2207
2208 return -ENOENT;
2209 }
2210
2211 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
2212 size_t t;
2213 uint64_t l;
2214 int compression;
2215
2216 l = le64toh(o->object.size) - offsetof(Object, data.payload);
2217 t = (size_t) l;
2218
2219 /* We can't read objects larger than 4G on a 32bit machine */
2220 if ((uint64_t) t != l)
2221 return -E2BIG;
2222
2223 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
2224 if (compression) {
2225 #if HAVE_XZ || HAVE_LZ4
2226 size_t rsize;
2227 int r;
2228
2229 r = decompress_blob(compression,
2230 o->data.payload, l, &f->compress_buffer,
2231 &f->compress_buffer_size, &rsize, j->data_threshold);
2232 if (r < 0)
2233 return r;
2234
2235 *data = f->compress_buffer;
2236 *size = (size_t) rsize;
2237 #else
2238 return -EPROTONOSUPPORT;
2239 #endif
2240 } else {
2241 *data = o->data.payload;
2242 *size = t;
2243 }
2244
2245 return 0;
2246 }
2247
2248 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
2249 JournalFile *f;
2250 uint64_t p, n;
2251 le64_t le_hash;
2252 int r;
2253 Object *o;
2254
2255 assert_return(j, -EINVAL);
2256 assert_return(!journal_pid_changed(j), -ECHILD);
2257 assert_return(data, -EINVAL);
2258 assert_return(size, -EINVAL);
2259
2260 f = j->current_file;
2261 if (!f)
2262 return -EADDRNOTAVAIL;
2263
2264 if (f->current_offset <= 0)
2265 return -EADDRNOTAVAIL;
2266
2267 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2268 if (r < 0)
2269 return r;
2270
2271 n = journal_file_entry_n_items(o);
2272 if (j->current_field >= n)
2273 return 0;
2274
2275 p = le64toh(o->entry.items[j->current_field].object_offset);
2276 le_hash = o->entry.items[j->current_field].hash;
2277 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2278 if (r < 0)
2279 return r;
2280
2281 if (le_hash != o->data.hash)
2282 return -EBADMSG;
2283
2284 r = return_data(j, f, o, data, size);
2285 if (r < 0)
2286 return r;
2287
2288 j->current_field++;
2289
2290 return 1;
2291 }
2292
2293 _public_ void sd_journal_restart_data(sd_journal *j) {
2294 if (!j)
2295 return;
2296
2297 j->current_field = 0;
2298 }
2299
2300 _public_ int sd_journal_get_fd(sd_journal *j) {
2301 int r;
2302
2303 assert_return(j, -EINVAL);
2304 assert_return(!journal_pid_changed(j), -ECHILD);
2305
2306 if (j->no_inotify)
2307 return -EMEDIUMTYPE;
2308
2309 if (j->inotify_fd >= 0)
2310 return j->inotify_fd;
2311
2312 r = allocate_inotify(j);
2313 if (r < 0)
2314 return r;
2315
2316 log_debug("Reiterating files to get inotify watches established");
2317
2318 /* Iterate through all dirs again, to add them to the
2319 * inotify */
2320 if (j->no_new_files)
2321 r = add_current_paths(j);
2322 else if (j->flags & SD_JOURNAL_OS_ROOT)
2323 r = add_search_paths(j);
2324 else if (j->toplevel_fd >= 0)
2325 r = add_root_directory(j, NULL, false);
2326 else if (j->path)
2327 r = add_root_directory(j, j->path, true);
2328 else
2329 r = add_search_paths(j);
2330 if (r < 0)
2331 return r;
2332
2333 return j->inotify_fd;
2334 }
2335
2336 _public_ int sd_journal_get_events(sd_journal *j) {
2337 int fd;
2338
2339 assert_return(j, -EINVAL);
2340 assert_return(!journal_pid_changed(j), -ECHILD);
2341
2342 fd = sd_journal_get_fd(j);
2343 if (fd < 0)
2344 return fd;
2345
2346 return POLLIN;
2347 }
2348
2349 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2350 int fd;
2351
2352 assert_return(j, -EINVAL);
2353 assert_return(!journal_pid_changed(j), -ECHILD);
2354 assert_return(timeout_usec, -EINVAL);
2355
2356 fd = sd_journal_get_fd(j);
2357 if (fd < 0)
2358 return fd;
2359
2360 if (!j->on_network) {
2361 *timeout_usec = (uint64_t) -1;
2362 return 0;
2363 }
2364
2365 /* If we are on the network we need to regularly check for
2366 * changes manually */
2367
2368 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2369 return 1;
2370 }
2371
2372 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
2373 Directory *d;
2374
2375 assert(j);
2376 assert(e);
2377
2378 /* Is this a subdirectory we watch? */
2379 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2380 if (d) {
2381 sd_id128_t id;
2382
2383 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2384 (endswith(e->name, ".journal") ||
2385 endswith(e->name, ".journal~"))) {
2386
2387 /* Event for a journal file */
2388
2389 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
2390 (void) add_file(j, d->path, e->name);
2391 else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT))
2392 remove_file(j, d->path, e->name);
2393
2394 } else if (!d->is_root && e->len == 0) {
2395
2396 /* Event for a subdirectory */
2397
2398 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT))
2399 remove_directory(j, d);
2400
2401 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2402
2403 /* Event for root directory */
2404
2405 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
2406 (void) add_directory(j, d->path, e->name);
2407 }
2408
2409 return;
2410 }
2411
2412 if (e->mask & IN_IGNORED)
2413 return;
2414
2415 log_debug("Unknown inotify event.");
2416 }
2417
2418 static int determine_change(sd_journal *j) {
2419 bool b;
2420
2421 assert(j);
2422
2423 b = j->current_invalidate_counter != j->last_invalidate_counter;
2424 j->last_invalidate_counter = j->current_invalidate_counter;
2425
2426 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2427 }
2428
2429 _public_ int sd_journal_process(sd_journal *j) {
2430 bool got_something = false;
2431
2432 assert_return(j, -EINVAL);
2433 assert_return(!journal_pid_changed(j), -ECHILD);
2434
2435 j->last_process_usec = now(CLOCK_MONOTONIC);
2436 j->last_invalidate_counter = j->current_invalidate_counter;
2437
2438 for (;;) {
2439 union inotify_event_buffer buffer;
2440 struct inotify_event *e;
2441 ssize_t l;
2442
2443 l = read(j->inotify_fd, &buffer, sizeof(buffer));
2444 if (l < 0) {
2445 if (IN_SET(errno, EAGAIN, EINTR))
2446 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2447
2448 return -errno;
2449 }
2450
2451 got_something = true;
2452
2453 FOREACH_INOTIFY_EVENT(e, buffer, l)
2454 process_inotify_event(j, e);
2455 }
2456 }
2457
2458 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2459 int r;
2460 uint64_t t;
2461
2462 assert_return(j, -EINVAL);
2463 assert_return(!journal_pid_changed(j), -ECHILD);
2464
2465 if (j->inotify_fd < 0) {
2466
2467 /* This is the first invocation, hence create the
2468 * inotify watch */
2469 r = sd_journal_get_fd(j);
2470 if (r < 0)
2471 return r;
2472
2473 /* The journal might have changed since the context
2474 * object was created and we weren't watching before,
2475 * hence don't wait for anything, and return
2476 * immediately. */
2477 return determine_change(j);
2478 }
2479
2480 r = sd_journal_get_timeout(j, &t);
2481 if (r < 0)
2482 return r;
2483
2484 if (t != (uint64_t) -1) {
2485 usec_t n;
2486
2487 n = now(CLOCK_MONOTONIC);
2488 t = t > n ? t - n : 0;
2489
2490 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2491 timeout_usec = t;
2492 }
2493
2494 do {
2495 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2496 } while (r == -EINTR);
2497
2498 if (r < 0)
2499 return r;
2500
2501 return sd_journal_process(j);
2502 }
2503
2504 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2505 Iterator i;
2506 JournalFile *f;
2507 bool first = true;
2508 uint64_t fmin = 0, tmax = 0;
2509 int r;
2510
2511 assert_return(j, -EINVAL);
2512 assert_return(!journal_pid_changed(j), -ECHILD);
2513 assert_return(from || to, -EINVAL);
2514 assert_return(from != to, -EINVAL);
2515
2516 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2517 usec_t fr, t;
2518
2519 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2520 if (r == -ENOENT)
2521 continue;
2522 if (r < 0)
2523 return r;
2524 if (r == 0)
2525 continue;
2526
2527 if (first) {
2528 fmin = fr;
2529 tmax = t;
2530 first = false;
2531 } else {
2532 fmin = MIN(fr, fmin);
2533 tmax = MAX(t, tmax);
2534 }
2535 }
2536
2537 if (from)
2538 *from = fmin;
2539 if (to)
2540 *to = tmax;
2541
2542 return first ? 0 : 1;
2543 }
2544
2545 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2546 Iterator i;
2547 JournalFile *f;
2548 bool found = false;
2549 int r;
2550
2551 assert_return(j, -EINVAL);
2552 assert_return(!journal_pid_changed(j), -ECHILD);
2553 assert_return(from || to, -EINVAL);
2554 assert_return(from != to, -EINVAL);
2555
2556 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2557 usec_t fr, t;
2558
2559 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2560 if (r == -ENOENT)
2561 continue;
2562 if (r < 0)
2563 return r;
2564 if (r == 0)
2565 continue;
2566
2567 if (found) {
2568 if (from)
2569 *from = MIN(fr, *from);
2570 if (to)
2571 *to = MAX(t, *to);
2572 } else {
2573 if (from)
2574 *from = fr;
2575 if (to)
2576 *to = t;
2577 found = true;
2578 }
2579 }
2580
2581 return found;
2582 }
2583
2584 void journal_print_header(sd_journal *j) {
2585 Iterator i;
2586 JournalFile *f;
2587 bool newline = false;
2588
2589 assert(j);
2590
2591 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2592 if (newline)
2593 putchar('\n');
2594 else
2595 newline = true;
2596
2597 journal_file_print_header(f);
2598 }
2599 }
2600
2601 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2602 Iterator i;
2603 JournalFile *f;
2604 uint64_t sum = 0;
2605
2606 assert_return(j, -EINVAL);
2607 assert_return(!journal_pid_changed(j), -ECHILD);
2608 assert_return(bytes, -EINVAL);
2609
2610 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
2611 struct stat st;
2612
2613 if (fstat(f->fd, &st) < 0)
2614 return -errno;
2615
2616 sum += (uint64_t) st.st_blocks * 512ULL;
2617 }
2618
2619 *bytes = sum;
2620 return 0;
2621 }
2622
2623 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2624 char *f;
2625
2626 assert_return(j, -EINVAL);
2627 assert_return(!journal_pid_changed(j), -ECHILD);
2628 assert_return(!isempty(field), -EINVAL);
2629 assert_return(field_is_valid(field), -EINVAL);
2630
2631 f = strdup(field);
2632 if (!f)
2633 return -ENOMEM;
2634
2635 free(j->unique_field);
2636 j->unique_field = f;
2637 j->unique_file = NULL;
2638 j->unique_offset = 0;
2639 j->unique_file_lost = false;
2640
2641 return 0;
2642 }
2643
2644 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2645 size_t k;
2646
2647 assert_return(j, -EINVAL);
2648 assert_return(!journal_pid_changed(j), -ECHILD);
2649 assert_return(data, -EINVAL);
2650 assert_return(l, -EINVAL);
2651 assert_return(j->unique_field, -EINVAL);
2652
2653 k = strlen(j->unique_field);
2654
2655 if (!j->unique_file) {
2656 if (j->unique_file_lost)
2657 return 0;
2658
2659 j->unique_file = ordered_hashmap_first(j->files);
2660 if (!j->unique_file)
2661 return 0;
2662
2663 j->unique_offset = 0;
2664 }
2665
2666 for (;;) {
2667 JournalFile *of;
2668 Iterator i;
2669 Object *o;
2670 const void *odata;
2671 size_t ol;
2672 bool found;
2673 int r;
2674
2675 /* Proceed to next data object in the field's linked list */
2676 if (j->unique_offset == 0) {
2677 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2678 if (r < 0)
2679 return r;
2680
2681 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2682 } else {
2683 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2684 if (r < 0)
2685 return r;
2686
2687 j->unique_offset = le64toh(o->data.next_field_offset);
2688 }
2689
2690 /* We reached the end of the list? Then start again, with the next file */
2691 if (j->unique_offset == 0) {
2692 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
2693 if (!j->unique_file)
2694 return 0;
2695
2696 continue;
2697 }
2698
2699 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2700 * instead, so that we can look at this data object at the same
2701 * time as one on another file */
2702 r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o);
2703 if (r < 0)
2704 return r;
2705
2706 /* Let's do the type check by hand, since we used 0 context above. */
2707 if (o->object.type != OBJECT_DATA) {
2708 log_debug("%s:offset " OFSfmt ": object has type %d, expected %d",
2709 j->unique_file->path, j->unique_offset,
2710 o->object.type, OBJECT_DATA);
2711 return -EBADMSG;
2712 }
2713
2714 r = return_data(j, j->unique_file, o, &odata, &ol);
2715 if (r < 0)
2716 return r;
2717
2718 /* Check if we have at least the field name and "=". */
2719 if (ol <= k) {
2720 log_debug("%s:offset " OFSfmt ": object has size %zu, expected at least %zu",
2721 j->unique_file->path, j->unique_offset,
2722 ol, k + 1);
2723 return -EBADMSG;
2724 }
2725
2726 if (memcmp(odata, j->unique_field, k) || ((const char*) odata)[k] != '=') {
2727 log_debug("%s:offset " OFSfmt ": object does not start with \"%s=\"",
2728 j->unique_file->path, j->unique_offset,
2729 j->unique_field);
2730 return -EBADMSG;
2731 }
2732
2733 /* OK, now let's see if we already returned this data
2734 * object by checking if it exists in the earlier
2735 * traversed files. */
2736 found = false;
2737 ORDERED_HASHMAP_FOREACH(of, j->files, i) {
2738 if (of == j->unique_file)
2739 break;
2740
2741 /* Skip this file it didn't have any fields indexed */
2742 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0)
2743 continue;
2744
2745 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), NULL, NULL);
2746 if (r < 0)
2747 return r;
2748 if (r > 0) {
2749 found = true;
2750 break;
2751 }
2752 }
2753
2754 if (found)
2755 continue;
2756
2757 r = return_data(j, j->unique_file, o, data, l);
2758 if (r < 0)
2759 return r;
2760
2761 return 1;
2762 }
2763 }
2764
2765 _public_ void sd_journal_restart_unique(sd_journal *j) {
2766 if (!j)
2767 return;
2768
2769 j->unique_file = NULL;
2770 j->unique_offset = 0;
2771 j->unique_file_lost = false;
2772 }
2773
2774 _public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) {
2775 int r;
2776
2777 assert_return(j, -EINVAL);
2778 assert_return(!journal_pid_changed(j), -ECHILD);
2779 assert_return(field, -EINVAL);
2780
2781 if (!j->fields_file) {
2782 if (j->fields_file_lost)
2783 return 0;
2784
2785 j->fields_file = ordered_hashmap_first(j->files);
2786 if (!j->fields_file)
2787 return 0;
2788
2789 j->fields_hash_table_index = 0;
2790 j->fields_offset = 0;
2791 }
2792
2793 for (;;) {
2794 JournalFile *f, *of;
2795 Iterator i;
2796 uint64_t m;
2797 Object *o;
2798 size_t sz;
2799 bool found;
2800
2801 f = j->fields_file;
2802
2803 if (j->fields_offset == 0) {
2804 bool eof = false;
2805
2806 /* We are not yet positioned at any field. Let's pick the first one */
2807 r = journal_file_map_field_hash_table(f);
2808 if (r < 0)
2809 return r;
2810
2811 m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
2812 for (;;) {
2813 if (j->fields_hash_table_index >= m) {
2814 /* Reached the end of the hash table, go to the next file. */
2815 eof = true;
2816 break;
2817 }
2818
2819 j->fields_offset = le64toh(f->field_hash_table[j->fields_hash_table_index].head_hash_offset);
2820
2821 if (j->fields_offset != 0)
2822 break;
2823
2824 /* Empty hash table bucket, go to next one */
2825 j->fields_hash_table_index++;
2826 }
2827
2828 if (eof) {
2829 /* Proceed with next file */
2830 j->fields_file = ordered_hashmap_next(j->files, f->path);
2831 if (!j->fields_file) {
2832 *field = NULL;
2833 return 0;
2834 }
2835
2836 j->fields_offset = 0;
2837 j->fields_hash_table_index = 0;
2838 continue;
2839 }
2840
2841 } else {
2842 /* We are already positioned at a field. If so, let's figure out the next field from it */
2843
2844 r = journal_file_move_to_object(f, OBJECT_FIELD, j->fields_offset, &o);
2845 if (r < 0)
2846 return r;
2847
2848 j->fields_offset = le64toh(o->field.next_hash_offset);
2849 if (j->fields_offset == 0) {
2850 /* Reached the end of the hash table chain */
2851 j->fields_hash_table_index++;
2852 continue;
2853 }
2854 }
2855
2856 /* We use OBJECT_UNUSED here, so that the iterator below doesn't remove our mmap window */
2857 r = journal_file_move_to_object(f, OBJECT_UNUSED, j->fields_offset, &o);
2858 if (r < 0)
2859 return r;
2860
2861 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
2862 if (o->object.type != OBJECT_FIELD) {
2863 log_debug("%s:offset " OFSfmt ": object has type %i, expected %i", f->path, j->fields_offset, o->object.type, OBJECT_FIELD);
2864 return -EBADMSG;
2865 }
2866
2867 sz = le64toh(o->object.size) - offsetof(Object, field.payload);
2868
2869 /* Let's see if we already returned this field name before. */
2870 found = false;
2871 ORDERED_HASHMAP_FOREACH(of, j->files, i) {
2872 if (of == f)
2873 break;
2874
2875 /* Skip this file it didn't have any fields indexed */
2876 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0)
2877 continue;
2878
2879 r = journal_file_find_field_object_with_hash(of, o->field.payload, sz, le64toh(o->field.hash), NULL, NULL);
2880 if (r < 0)
2881 return r;
2882 if (r > 0) {
2883 found = true;
2884 break;
2885 }
2886 }
2887
2888 if (found)
2889 continue;
2890
2891 /* Check if this is really a valid string containing no NUL byte */
2892 if (memchr(o->field.payload, 0, sz))
2893 return -EBADMSG;
2894
2895 if (sz > j->data_threshold)
2896 sz = j->data_threshold;
2897
2898 if (!GREEDY_REALLOC(j->fields_buffer, j->fields_buffer_allocated, sz + 1))
2899 return -ENOMEM;
2900
2901 memcpy(j->fields_buffer, o->field.payload, sz);
2902 j->fields_buffer[sz] = 0;
2903
2904 if (!field_is_valid(j->fields_buffer))
2905 return -EBADMSG;
2906
2907 *field = j->fields_buffer;
2908 return 1;
2909 }
2910 }
2911
2912 _public_ void sd_journal_restart_fields(sd_journal *j) {
2913 if (!j)
2914 return;
2915
2916 j->fields_file = NULL;
2917 j->fields_hash_table_index = 0;
2918 j->fields_offset = 0;
2919 j->fields_file_lost = false;
2920 }
2921
2922 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2923 assert_return(j, -EINVAL);
2924 assert_return(!journal_pid_changed(j), -ECHILD);
2925
2926 return !j->on_network;
2927 }
2928
2929 static char *lookup_field(const char *field, void *userdata) {
2930 sd_journal *j = userdata;
2931 const void *data;
2932 size_t size, d;
2933 int r;
2934
2935 assert(field);
2936 assert(j);
2937
2938 r = sd_journal_get_data(j, field, &data, &size);
2939 if (r < 0 ||
2940 size > REPLACE_VAR_MAX)
2941 return strdup(field);
2942
2943 d = strlen(field) + 1;
2944
2945 return strndup((const char*) data + d, size - d);
2946 }
2947
2948 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2949 const void *data;
2950 size_t size;
2951 sd_id128_t id;
2952 _cleanup_free_ char *text = NULL, *cid = NULL;
2953 char *t;
2954 int r;
2955
2956 assert_return(j, -EINVAL);
2957 assert_return(!journal_pid_changed(j), -ECHILD);
2958 assert_return(ret, -EINVAL);
2959
2960 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2961 if (r < 0)
2962 return r;
2963
2964 cid = strndup((const char*) data + 11, size - 11);
2965 if (!cid)
2966 return -ENOMEM;
2967
2968 r = sd_id128_from_string(cid, &id);
2969 if (r < 0)
2970 return r;
2971
2972 r = catalog_get(CATALOG_DATABASE, id, &text);
2973 if (r < 0)
2974 return r;
2975
2976 t = replace_var(text, lookup_field, j);
2977 if (!t)
2978 return -ENOMEM;
2979
2980 *ret = t;
2981 return 0;
2982 }
2983
2984 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2985 assert_return(ret, -EINVAL);
2986
2987 return catalog_get(CATALOG_DATABASE, id, ret);
2988 }
2989
2990 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2991 assert_return(j, -EINVAL);
2992 assert_return(!journal_pid_changed(j), -ECHILD);
2993
2994 j->data_threshold = sz;
2995 return 0;
2996 }
2997
2998 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2999 assert_return(j, -EINVAL);
3000 assert_return(!journal_pid_changed(j), -ECHILD);
3001 assert_return(sz, -EINVAL);
3002
3003 *sz = j->data_threshold;
3004 return 0;
3005 }
3006
3007 _public_ int sd_journal_has_runtime_files(sd_journal *j) {
3008 assert_return(j, -EINVAL);
3009
3010 return j->has_runtime_files;
3011 }
3012
3013 _public_ int sd_journal_has_persistent_files(sd_journal *j) {
3014 assert_return(j, -EINVAL);
3015
3016 return j->has_persistent_files;
3017 }