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