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