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