1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
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.
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.
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/>.
24 #include <linux/magic.h>
27 #include <sys/inotify.h>
31 #include "sd-journal.h"
33 #include "alloc-util.h"
36 #include "dirent-util.h"
39 #include "format-util.h"
42 #include "hostname-util.h"
44 #include "journal-def.h"
45 #include "journal-file.h"
46 #include "journal-internal.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"
58 #define JOURNAL_FILES_MAX 7168
60 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
62 #define REPLACE_VAR_MAX 256
64 #define DEFAULT_DATA_THRESHOLD (64*1024)
66 static void remove_file_real(sd_journal
*j
, JournalFile
*f
);
68 static bool journal_pid_changed(sd_journal
*j
) {
71 /* We don't support people creating a journal object and
72 * keeping it around over a fork(). Let's complain. */
74 return j
->original_pid
!= getpid_cached();
77 static int journal_put_error(sd_journal
*j
, int r
, const char *path
) {
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
89 * We return an error here only if we didn't manage to
90 * memorize the real error. */
95 k
= hashmap_ensure_allocated(&j
->errors
, NULL
);
106 k
= hashmap_put(j
->errors
, INT_TO_PTR(r
), copy
);
119 static void detach_location(sd_journal
*j
) {
125 j
->current_file
= NULL
;
126 j
->current_field
= 0;
128 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
)
129 journal_file_reset_location(f
);
132 static void reset_location(sd_journal
*j
) {
136 zero(j
->current_location
);
139 static void init_location(Location
*l
, LocationType type
, JournalFile
*f
, Object
*o
) {
141 assert(IN_SET(type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
143 assert(o
->object
.type
== OBJECT_ENTRY
);
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
);
153 l
->seqnum_set
= l
->realtime_set
= l
->monotonic_set
= l
->xor_hash_set
= true;
156 static void set_location(sd_journal
*j
, JournalFile
*f
, Object
*o
) {
161 init_location(&j
->current_location
, LOCATION_DISCRETE
, f
, o
);
164 j
->current_field
= 0;
166 /* Let f know its candidate entry was picked. */
167 assert(f
->location_type
== LOCATION_SEEK
);
168 f
->location_type
= LOCATION_DISCRETE
;
171 static int match_is_valid(const void *data
, size_t size
) {
179 if (startswith(data
, "__"))
183 for (p
= b
; p
< b
+ size
; p
++) {
191 if (*p
>= 'A' && *p
<= 'Z')
194 if (*p
>= '0' && *p
<= '9')
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
;
207 for (j
= 0; j
< s
&& j
< t
; j
++) {
216 assert_not_reached("\"=\" not found");
219 static Match
*match_new(Match
*p
, MatchType t
) {
230 LIST_PREPEND(matches
, p
->matches
, m
);
236 static void match_free(Match
*m
) {
240 match_free(m
->matches
);
243 LIST_REMOVE(matches
, m
->parent
->matches
, m
);
249 static void match_free_if_empty(Match
*m
) {
250 if (!m
|| m
->matches
)
256 _public_
int sd_journal_add_match(sd_journal
*j
, const void *data
, size_t size
) {
257 Match
*l3
, *l4
, *add_here
= NULL
, *m
;
260 assert_return(j
, -EINVAL
);
261 assert_return(!journal_pid_changed(j
), -ECHILD
);
262 assert_return(data
, -EINVAL
);
267 assert_return(match_is_valid(data
, size
), -EINVAL
);
273 * level 4: concrete matches */
276 j
->level0
= match_new(NULL
, MATCH_AND_TERM
);
282 j
->level1
= match_new(j
->level0
, MATCH_OR_TERM
);
288 j
->level2
= match_new(j
->level1
, MATCH_AND_TERM
);
293 assert(j
->level0
->type
== MATCH_AND_TERM
);
294 assert(j
->level1
->type
== MATCH_OR_TERM
);
295 assert(j
->level2
->type
== MATCH_AND_TERM
);
297 le_hash
= htole64(hash64(data
, size
));
299 LIST_FOREACH(matches
, l3
, j
->level2
->matches
) {
300 assert(l3
->type
== MATCH_OR_TERM
);
302 LIST_FOREACH(matches
, l4
, l3
->matches
) {
303 assert(l4
->type
== MATCH_DISCRETE
);
305 /* Exactly the same match already? Then ignore
307 if (l4
->le_hash
== le_hash
&&
309 memcmp(l4
->data
, data
, size
) == 0)
312 /* Same field? Then let's add this to this OR term */
313 if (same_field(data
, size
, l4
->data
, l4
->size
)) {
324 add_here
= match_new(j
->level2
, MATCH_OR_TERM
);
329 m
= match_new(add_here
, MATCH_DISCRETE
);
333 m
->le_hash
= le_hash
;
335 m
->data
= memdup(data
, size
);
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
);
352 _public_
int sd_journal_add_conjunction(sd_journal
*j
) {
353 assert_return(j
, -EINVAL
);
354 assert_return(!journal_pid_changed(j
), -ECHILD
);
362 if (!j
->level1
->matches
)
371 _public_
int sd_journal_add_disjunction(sd_journal
*j
) {
372 assert_return(j
, -EINVAL
);
373 assert_return(!journal_pid_changed(j
), -ECHILD
);
384 if (!j
->level2
->matches
)
391 static char *match_make_string(Match
*m
) {
394 bool enclose
= false;
397 return strdup("none");
399 if (m
->type
== MATCH_DISCRETE
)
400 return strndup(m
->data
, m
->size
);
402 LIST_FOREACH(matches
, i
, m
->matches
) {
405 t
= match_make_string(i
);
410 k
= strjoin(p
, m
->type
== MATCH_OR_TERM
? " OR " : " AND ", t
);
425 r
= strjoin("(", p
, ")");
433 char *journal_make_match_string(sd_journal
*j
) {
436 return match_make_string(j
->level0
);
439 _public_
void sd_journal_flush_matches(sd_journal
*j
) {
444 match_free(j
->level0
);
446 j
->level0
= j
->level1
= j
->level2
= NULL
;
451 _pure_
static int compare_with_location(JournalFile
*f
, Location
*l
) {
454 assert(f
->location_type
== LOCATION_SEEK
);
455 assert(IN_SET(l
->type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
457 if (l
->monotonic_set
&&
458 sd_id128_equal(f
->current_boot_id
, l
->boot_id
) &&
460 f
->current_realtime
== l
->realtime
&&
462 f
->current_xor_hash
== l
->xor_hash
)
466 sd_id128_equal(f
->header
->seqnum_id
, l
->seqnum_id
)) {
468 if (f
->current_seqnum
< l
->seqnum
)
470 if (f
->current_seqnum
> l
->seqnum
)
474 if (l
->monotonic_set
&&
475 sd_id128_equal(f
->current_boot_id
, l
->boot_id
)) {
477 if (f
->current_monotonic
< l
->monotonic
)
479 if (f
->current_monotonic
> l
->monotonic
)
483 if (l
->realtime_set
) {
485 if (f
->current_realtime
< l
->realtime
)
487 if (f
->current_realtime
> l
->realtime
)
491 if (l
->xor_hash_set
) {
493 if (f
->current_xor_hash
< l
->xor_hash
)
495 if (f
->current_xor_hash
> l
->xor_hash
)
502 static int next_for_match(
506 uint64_t after_offset
,
507 direction_t direction
,
519 if (m
->type
== MATCH_DISCRETE
) {
522 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
526 return journal_file_move_to_entry_by_offset_for_data(f
, dp
, after_offset
, direction
, ret
, offset
);
528 } else if (m
->type
== MATCH_OR_TERM
) {
531 /* Find the earliest match beyond after_offset */
533 LIST_FOREACH(matches
, i
, m
->matches
) {
536 r
= next_for_match(j
, i
, f
, after_offset
, direction
, NULL
, &cp
);
540 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
< np
: cp
> np
))
548 } else if (m
->type
== MATCH_AND_TERM
) {
549 Match
*i
, *last_moved
;
551 /* Always jump to the next matching entry and repeat
552 * this until we find an offset that matches for all
558 r
= next_for_match(j
, m
->matches
, f
, after_offset
, direction
, NULL
, &np
);
562 assert(direction
== DIRECTION_DOWN
? np
>= after_offset
: np
<= after_offset
);
563 last_moved
= m
->matches
;
565 LIST_LOOP_BUT_ONE(matches
, i
, m
->matches
, last_moved
) {
568 r
= next_for_match(j
, i
, f
, np
, direction
, NULL
, &cp
);
572 assert(direction
== DIRECTION_DOWN
? cp
>= np
: cp
<= np
);
573 if (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
) {
582 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
594 static int find_location_for_match(
598 direction_t direction
,
608 if (m
->type
== MATCH_DISCRETE
) {
611 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
615 /* FIXME: missing: find by monotonic */
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
);
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
);
631 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, direction
, ret
, offset
);
633 } else if (m
->type
== MATCH_OR_TERM
) {
638 /* Find the earliest match */
640 LIST_FOREACH(matches
, i
, m
->matches
) {
643 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
647 if (np
== 0 || (direction
== DIRECTION_DOWN
? np
> cp
: np
< cp
))
655 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
670 assert(m
->type
== MATCH_AND_TERM
);
672 /* First jump to the last match, and then find the
673 * next one where all matches match */
678 LIST_FOREACH(matches
, i
, m
->matches
) {
681 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
685 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
))
689 return next_for_match(j
, m
, f
, np
, direction
, ret
, offset
);
693 static int find_location_with_matches(
696 direction_t direction
,
708 /* No matches is simple */
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
);
721 if (j
->current_location
.realtime_set
)
722 return journal_file_move_to_entry_by_realtime(f
, j
->current_location
.realtime
, direction
, ret
, offset
);
724 return journal_file_next_entry(f
, 0, direction
, ret
, offset
);
726 return find_location_for_match(j
, j
->level0
, f
, direction
, ret
, offset
);
729 static int next_with_matches(
732 direction_t direction
,
741 /* No matches is easy. We simple advance the file
744 return journal_file_next_entry(f
, f
->current_offset
, direction
, ret
, offset
);
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
);
754 static int next_beyond_location(sd_journal
*j
, JournalFile
*f
, direction_t direction
) {
756 uint64_t cp
, n_entries
;
762 n_entries
= le64toh(f
->header
->n_entries
);
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
)
770 f
->last_n_entries
= n_entries
;
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
);
781 journal_file_save_location(f
, c
, cp
);
784 f
->last_direction
= direction
;
786 r
= find_location_with_matches(j
, f
, direction
, &c
, &cp
);
790 journal_file_save_location(f
, c
, cp
);
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. */
802 if (j
->current_location
.type
== LOCATION_DISCRETE
) {
805 k
= compare_with_location(f
, &j
->current_location
);
807 found
= direction
== DIRECTION_DOWN
? k
> 0 : k
< 0;
814 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
818 journal_file_save_location(f
, c
, cp
);
822 static int real_journal_next(sd_journal
*j
, direction_t direction
) {
823 JournalFile
*f
, *new_file
= NULL
;
828 assert_return(j
, -EINVAL
);
829 assert_return(!journal_pid_changed(j
), -ECHILD
);
831 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
834 r
= next_beyond_location(j
, f
, direction
);
836 log_debug_errno(r
, "Can't iterate through %s, ignoring: %m", f
->path
);
837 remove_file_real(j
, f
);
840 f
->location_type
= LOCATION_TAIL
;
849 k
= journal_file_compare_locations(f
, new_file
);
851 found
= direction
== DIRECTION_DOWN
? k
< 0 : k
> 0;
861 r
= journal_file_move_to_object(new_file
, OBJECT_ENTRY
, new_file
->current_offset
, &o
);
865 set_location(j
, new_file
, o
);
870 _public_
int sd_journal_next(sd_journal
*j
) {
871 return real_journal_next(j
, DIRECTION_DOWN
);
874 _public_
int sd_journal_previous(sd_journal
*j
) {
875 return real_journal_next(j
, DIRECTION_UP
);
878 static int real_journal_next_skip(sd_journal
*j
, direction_t direction
, uint64_t skip
) {
881 assert_return(j
, -EINVAL
);
882 assert_return(!journal_pid_changed(j
), -ECHILD
);
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
);
897 r
= real_journal_next(j
, direction
);
911 _public_
int sd_journal_next_skip(sd_journal
*j
, uint64_t skip
) {
912 return real_journal_next_skip(j
, DIRECTION_DOWN
, skip
);
915 _public_
int sd_journal_previous_skip(sd_journal
*j
, uint64_t skip
) {
916 return real_journal_next_skip(j
, DIRECTION_UP
, skip
);
919 _public_
int sd_journal_get_cursor(sd_journal
*j
, char **cursor
) {
922 char bid
[33], sid
[33];
924 assert_return(j
, -EINVAL
);
925 assert_return(!journal_pid_changed(j
), -ECHILD
);
926 assert_return(cursor
, -EINVAL
);
928 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
929 return -EADDRNOTAVAIL
;
931 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
935 sd_id128_to_string(j
->current_file
->header
->seqnum_id
, sid
);
936 sd_id128_to_string(o
->entry
.boot_id
, bid
);
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)
949 _public_
int sd_journal_seek_cursor(sd_journal
*j
, const char *cursor
) {
950 const char *word
, *state
;
952 unsigned long long seqnum
, monotonic
, realtime
, xor_hash
;
954 seqnum_id_set
= false,
957 monotonic_set
= false,
958 realtime_set
= false,
959 xor_hash_set
= false;
960 sd_id128_t seqnum_id
, boot_id
;
962 assert_return(j
, -EINVAL
);
963 assert_return(!journal_pid_changed(j
), -ECHILD
);
964 assert_return(!isempty(cursor
), -EINVAL
);
966 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
970 if (l
< 2 || word
[1] != '=')
973 item
= strndup(word
, l
);
980 seqnum_id_set
= true;
981 k
= sd_id128_from_string(item
+2, &seqnum_id
);
986 if (sscanf(item
+2, "%llx", &seqnum
) != 1)
992 k
= sd_id128_from_string(item
+2, &boot_id
);
996 monotonic_set
= true;
997 if (sscanf(item
+2, "%llx", &monotonic
) != 1)
1002 realtime_set
= true;
1003 if (sscanf(item
+2, "%llx", &realtime
) != 1)
1008 xor_hash_set
= true;
1009 if (sscanf(item
+2, "%llx", &xor_hash
) != 1)
1020 if ((!seqnum_set
|| !seqnum_id_set
) &&
1021 (!monotonic_set
|| !boot_id_set
) &&
1027 j
->current_location
.type
= LOCATION_SEEK
;
1030 j
->current_location
.realtime
= (uint64_t) realtime
;
1031 j
->current_location
.realtime_set
= true;
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;
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;
1047 j
->current_location
.xor_hash
= (uint64_t) xor_hash
;
1048 j
->current_location
.xor_hash_set
= true;
1054 _public_
int sd_journal_test_cursor(sd_journal
*j
, const char *cursor
) {
1058 assert_return(j
, -EINVAL
);
1059 assert_return(!journal_pid_changed(j
), -ECHILD
);
1060 assert_return(!isempty(cursor
), -EINVAL
);
1062 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
1063 return -EADDRNOTAVAIL
;
1065 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
1070 _cleanup_free_
char *item
= NULL
;
1071 unsigned long long ll
;
1075 r
= extract_first_word(&cursor
, &item
, ";", EXTRACT_DONT_COALESCE_SEPARATORS
);
1082 if (strlen(item
) < 2 || item
[1] != '=')
1088 k
= sd_id128_from_string(item
+2, &id
);
1091 if (!sd_id128_equal(id
, j
->current_file
->header
->seqnum_id
))
1096 if (sscanf(item
+2, "%llx", &ll
) != 1)
1098 if (ll
!= le64toh(o
->entry
.seqnum
))
1103 k
= sd_id128_from_string(item
+2, &id
);
1106 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1111 if (sscanf(item
+2, "%llx", &ll
) != 1)
1113 if (ll
!= le64toh(o
->entry
.monotonic
))
1118 if (sscanf(item
+2, "%llx", &ll
) != 1)
1120 if (ll
!= le64toh(o
->entry
.realtime
))
1125 if (sscanf(item
+2, "%llx", &ll
) != 1)
1127 if (ll
!= le64toh(o
->entry
.xor_hash
))
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
);
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;
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
);
1155 j
->current_location
.type
= LOCATION_SEEK
;
1156 j
->current_location
.realtime
= usec
;
1157 j
->current_location
.realtime_set
= true;
1162 _public_
int sd_journal_seek_head(sd_journal
*j
) {
1163 assert_return(j
, -EINVAL
);
1164 assert_return(!journal_pid_changed(j
), -ECHILD
);
1167 j
->current_location
.type
= LOCATION_HEAD
;
1172 _public_
int sd_journal_seek_tail(sd_journal
*j
) {
1173 assert_return(j
, -EINVAL
);
1174 assert_return(!journal_pid_changed(j
), -ECHILD
);
1177 j
->current_location
.type
= LOCATION_TAIL
;
1182 static void check_network(sd_journal
*j
, int fd
) {
1190 if (fstatfs(fd
, &sfs
) < 0)
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
);
1201 static bool file_has_type_prefix(const char *prefix
, const char *filename
) {
1202 const char *full
, *tilded
, *atted
;
1204 full
= strjoina(prefix
, ".journal");
1205 tilded
= strjoina(full
, "~");
1206 atted
= strjoina(prefix
, "@");
1208 return streq(filename
, full
) ||
1209 streq(filename
, tilded
) ||
1210 startswith(filename
, atted
);
1213 static bool file_type_wanted(int flags
, const char *filename
) {
1216 if (!endswith(filename
, ".journal") && !endswith(filename
, ".journal~"))
1219 /* no flags set → every type is OK */
1220 if (!(flags
& (SD_JOURNAL_SYSTEM
| SD_JOURNAL_CURRENT_USER
)))
1223 if (flags
& SD_JOURNAL_SYSTEM
&& file_has_type_prefix("system", filename
))
1226 if (flags
& SD_JOURNAL_CURRENT_USER
) {
1227 char prefix
[5 + DECIMAL_STR_MAX(uid_t
) + 1];
1229 xsprintf(prefix
, "user-"UID_FMT
, getuid());
1231 if (file_has_type_prefix(prefix
, filename
))
1238 static bool path_has_prefix(sd_journal
*j
, const char *path
, const char *prefix
) {
1243 if (j
->toplevel_fd
>= 0)
1246 return path_startswith(path
, prefix
);
1249 static const char *skip_slash(const char *p
) {
1260 static int add_any_file(sd_journal
*j
, int fd
, const char *path
) {
1261 JournalFile
*f
= NULL
;
1262 bool close_fd
= false;
1266 assert(fd
>= 0 || path
);
1268 if (path
&& ordered_hashmap_get(j
->files
, path
))
1271 if (ordered_hashmap_size(j
->files
) >= JOURNAL_FILES_MAX
) {
1272 log_debug("Too many open journal files, not adding %s.", path
);
1277 if (fd
< 0 && j
->toplevel_fd
>= 0) {
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.) */
1282 fd
= openat(j
->toplevel_fd
, skip_slash(path
), O_RDONLY
|O_CLOEXEC
);
1284 r
= log_debug_errno(errno
, "Failed to open journal file %s: %m", path
);
1291 r
= journal_file_open(fd
, path
, O_RDONLY
, 0, false, false, NULL
, j
->mmap
, NULL
, NULL
, &f
);
1295 log_debug_errno(r
, "Failed to open journal file %s: %m", path
);
1299 /* journal_file_dump(f); */
1301 r
= ordered_hashmap_put(j
->files
, f
->path
, f
);
1303 f
->close_fd
= close_fd
;
1304 (void) journal_file_close(f
);
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;
1313 log_debug("File %s added.", f
->path
);
1315 check_network(j
, f
->fd
);
1317 j
->current_invalidate_counter
++;
1322 k
= journal_put_error(j
, r
, path
);
1329 static int add_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1336 if (j
->no_new_files
)
1339 if (!file_type_wanted(j
->flags
, filename
))
1342 path
= strjoina(prefix
, "/", filename
);
1343 return add_any_file(j
, -1, path
);
1346 static void remove_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1354 path
= strjoina(prefix
, "/", filename
);
1355 f
= ordered_hashmap_get(j
->files
, path
);
1359 remove_file_real(j
, f
);
1362 static void remove_file_real(sd_journal
*j
, JournalFile
*f
) {
1366 ordered_hashmap_remove(j
->files
, f
->path
);
1368 log_debug("File %s removed.", f
->path
);
1370 if (j
->current_file
== f
) {
1371 j
->current_file
= NULL
;
1372 j
->current_field
= 0;
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;
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;
1390 (void) journal_file_close(f
);
1392 j
->current_invalidate_counter
++;
1395 static int dirname_is_machine_id(const char *fn
) {
1396 sd_id128_t id
, machine
;
1399 r
= sd_id128_get_machine(&machine
);
1403 r
= sd_id128_from_string(fn
, &id
);
1407 return sd_id128_equal(id
, machine
);
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
;
1420 /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
1421 * and reenumerates directory contents */
1424 path
= strjoin(prefix
, "/", dirname
);
1426 path
= strdup(prefix
);
1432 log_debug("Considering directory %s.", path
);
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")))
1440 if (j
->toplevel_fd
< 0)
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);
1447 r
= log_debug_errno(errno
, "Failed to open directory %s: %m", path
);
1451 m
= hashmap_get(j
->directories_by_path
, path
);
1453 m
= new0(Directory
, 1);
1462 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1468 path
= NULL
; /* avoid freeing in cleanup */
1469 j
->current_invalidate_counter
++;
1471 log_debug("Directory %s added.", m
->path
);
1473 } else if (m
->is_root
)
1476 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1477 /* Watch this directory, if it not being watched yet. */
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
|
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
);
1488 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
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
);
1495 check_network(j
, dirfd(d
));
1500 k
= journal_put_error(j
, r
, path
?: prefix
);
1507 static int add_root_directory(sd_journal
*j
, const char *p
, bool missing_ok
) {
1509 _cleanup_closedir_
DIR *d
= NULL
;
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. */
1521 /* If there's a path specified, use it. */
1523 if ((j
->flags
& SD_JOURNAL_RUNTIME_ONLY
) &&
1524 !path_has_prefix(j
, p
, "/run"))
1528 p
= strjoina(j
->prefix
, p
);
1530 if (j
->toplevel_fd
< 0)
1533 d
= xopendirat(j
->toplevel_fd
, skip_slash(p
), 0);
1536 if (errno
== ENOENT
&& missing_ok
)
1539 r
= log_debug_errno(errno
, "Failed to open root directory %s: %m", p
);
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. */
1548 p
= "."; /* store this as "." in the directories hashmap */
1550 dfd
= fcntl(j
->toplevel_fd
, F_DUPFD_CLOEXEC
, 3);
1566 m
= hashmap_get(j
->directories_by_path
, p
);
1568 m
= new0(Directory
, 1);
1576 m
->path
= strdup(p
);
1583 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1590 j
->current_invalidate_counter
++;
1592 log_debug("Root directory %s added.", m
->path
);
1594 } else if (!m
->is_root
)
1597 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1599 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1600 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
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
);
1607 if (j
->no_new_files
)
1610 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
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
);
1621 check_network(j
, dirfd(d
));
1626 k
= journal_put_error(j
, r
, p
);
1633 static void remove_directory(sd_journal
*j
, Directory
*d
) {
1637 hashmap_remove(j
->directories_by_wd
, INT_TO_PTR(d
->wd
));
1639 if (j
->inotify_fd
>= 0)
1640 inotify_rm_watch(j
->inotify_fd
, d
->wd
);
1643 hashmap_remove(j
->directories_by_path
, d
->path
);
1646 log_debug("Root directory %s removed.", d
->path
);
1648 log_debug("Directory %s removed.", d
->path
);
1654 static int add_search_paths(sd_journal
*j
) {
1656 static const char search_paths
[] =
1657 "/run/log/journal\0"
1658 "/var/log/journal\0";
1663 /* We ignore most errors here, since the idea is to only open
1664 * what's actually accessible, and ignore the rest. */
1666 NULSTR_FOREACH(p
, search_paths
)
1667 (void) add_root_directory(j
, p
, true);
1669 if (!(j
->flags
& SD_JOURNAL_LOCAL_ONLY
))
1670 (void) add_root_directory(j
, "/var/log/journal/remote", true);
1675 static int add_current_paths(sd_journal
*j
) {
1680 assert(j
->no_new_files
);
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. */
1685 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1686 _cleanup_free_
char *dir
;
1689 dir
= dirname_malloc(f
->path
);
1693 r
= add_directory(j
, dir
, NULL
);
1701 static int allocate_inotify(sd_journal
*j
) {
1704 if (j
->inotify_fd
< 0) {
1705 j
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1706 if (j
->inotify_fd
< 0)
1710 return hashmap_ensure_allocated(&j
->directories_by_wd
, NULL
);
1713 static sd_journal
*journal_new(int flags
, const char *path
) {
1716 j
= new0(sd_journal
, 1);
1720 j
->original_pid
= getpid_cached();
1721 j
->toplevel_fd
= -1;
1724 j
->data_threshold
= DEFAULT_DATA_THRESHOLD
;
1733 if (flags
& SD_JOURNAL_OS_ROOT
)
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
)
1748 sd_journal_close(j
);
1752 #define OPEN_ALLOWED_FLAGS \
1753 (SD_JOURNAL_LOCAL_ONLY | \
1754 SD_JOURNAL_RUNTIME_ONLY | \
1755 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)
1757 _public_
int sd_journal_open(sd_journal
**ret
, int flags
) {
1761 assert_return(ret
, -EINVAL
);
1762 assert_return((flags
& ~OPEN_ALLOWED_FLAGS
) == 0, -EINVAL
);
1764 j
= journal_new(flags
, NULL
);
1768 r
= add_search_paths(j
);
1776 sd_journal_close(j
);
1781 #define OPEN_CONTAINER_ALLOWED_FLAGS \
1782 (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
1784 _public_
int sd_journal_open_container(sd_journal
**ret
, const char *machine
, int flags
) {
1785 _cleanup_free_
char *root
= NULL
, *class = NULL
;
1790 /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
1791 * combination with sd_journal_open_directory_fd(). */
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
);
1798 p
= strjoina("/run/systemd/machines/", machine
);
1799 r
= parse_env_file(p
, NEWLINE
, "ROOT", &root
, "CLASS", &class, NULL
);
1807 if (!streq_ptr(class, "container"))
1810 j
= journal_new(flags
, root
);
1814 r
= add_search_paths(j
);
1822 sd_journal_close(j
);
1826 #define OPEN_DIRECTORY_ALLOWED_FLAGS \
1827 (SD_JOURNAL_OS_ROOT | \
1828 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1830 _public_
int sd_journal_open_directory(sd_journal
**ret
, const char *path
, int flags
) {
1834 assert_return(ret
, -EINVAL
);
1835 assert_return(path
, -EINVAL
);
1836 assert_return((flags
& ~OPEN_DIRECTORY_ALLOWED_FLAGS
) == 0, -EINVAL
);
1838 j
= journal_new(flags
, path
);
1842 if (flags
& SD_JOURNAL_OS_ROOT
)
1843 r
= add_search_paths(j
);
1845 r
= add_root_directory(j
, path
, false);
1853 sd_journal_close(j
);
1857 _public_
int sd_journal_open_files(sd_journal
**ret
, const char **paths
, int flags
) {
1862 assert_return(ret
, -EINVAL
);
1863 assert_return(flags
== 0, -EINVAL
);
1865 j
= journal_new(flags
, NULL
);
1869 STRV_FOREACH(path
, paths
) {
1870 r
= add_any_file(j
, -1, *path
);
1875 j
->no_new_files
= true;
1881 sd_journal_close(j
);
1885 #define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
1886 (SD_JOURNAL_OS_ROOT | \
1887 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1889 _public_
int sd_journal_open_directory_fd(sd_journal
**ret
, int fd
, int flags
) {
1894 assert_return(ret
, -EINVAL
);
1895 assert_return(fd
>= 0, -EBADF
);
1896 assert_return((flags
& ~OPEN_DIRECTORY_FD_ALLOWED_FLAGS
) == 0, -EINVAL
);
1898 if (fstat(fd
, &st
) < 0)
1901 if (!S_ISDIR(st
.st_mode
))
1904 j
= journal_new(flags
, NULL
);
1908 j
->toplevel_fd
= fd
;
1910 if (flags
& SD_JOURNAL_OS_ROOT
)
1911 r
= add_search_paths(j
);
1913 r
= add_root_directory(j
, NULL
, false);
1921 sd_journal_close(j
);
1925 _public_
int sd_journal_open_files_fd(sd_journal
**ret
, int fds
[], unsigned n_fds
, int flags
) {
1932 assert_return(ret
, -EINVAL
);
1933 assert_return(n_fds
> 0, -EBADF
);
1934 assert_return(flags
== 0, -EINVAL
);
1936 j
= journal_new(flags
, NULL
);
1940 for (i
= 0; i
< n_fds
; i
++) {
1948 if (fstat(fds
[i
], &st
) < 0) {
1953 if (!S_ISREG(st
.st_mode
)) {
1958 r
= add_any_file(j
, fds
[i
], NULL
);
1963 j
->no_new_files
= true;
1964 j
->no_inotify
= true;
1970 /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
1972 ORDERED_HASHMAP_FOREACH(f
, j
->files
, iterator
)
1973 f
->close_fd
= false;
1975 sd_journal_close(j
);
1979 _public_
void sd_journal_close(sd_journal
*j
) {
1985 sd_journal_flush_matches(j
);
1987 ordered_hashmap_free_with_destructor(j
->files
, journal_file_close
);
1989 while ((d
= hashmap_first(j
->directories_by_path
)))
1990 remove_directory(j
, d
);
1992 while ((d
= hashmap_first(j
->directories_by_wd
)))
1993 remove_directory(j
, d
);
1995 hashmap_free(j
->directories_by_path
);
1996 hashmap_free(j
->directories_by_wd
);
1998 safe_close(j
->inotify_fd
);
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
);
2005 hashmap_free_free(j
->errors
);
2009 free(j
->unique_field
);
2010 free(j
->fields_buffer
);
2014 _public_
int sd_journal_get_realtime_usec(sd_journal
*j
, uint64_t *ret
) {
2019 assert_return(j
, -EINVAL
);
2020 assert_return(!journal_pid_changed(j
), -ECHILD
);
2021 assert_return(ret
, -EINVAL
);
2023 f
= j
->current_file
;
2025 return -EADDRNOTAVAIL
;
2027 if (f
->current_offset
<= 0)
2028 return -EADDRNOTAVAIL
;
2030 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2034 *ret
= le64toh(o
->entry
.realtime
);
2038 _public_
int sd_journal_get_monotonic_usec(sd_journal
*j
, uint64_t *ret
, sd_id128_t
*ret_boot_id
) {
2044 assert_return(j
, -EINVAL
);
2045 assert_return(!journal_pid_changed(j
), -ECHILD
);
2047 f
= j
->current_file
;
2049 return -EADDRNOTAVAIL
;
2051 if (f
->current_offset
<= 0)
2052 return -EADDRNOTAVAIL
;
2054 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2059 *ret_boot_id
= o
->entry
.boot_id
;
2061 r
= sd_id128_get_boot(&id
);
2065 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
2070 *ret
= le64toh(o
->entry
.monotonic
);
2075 static bool field_is_valid(const char *field
) {
2083 if (startswith(field
, "__"))
2086 for (p
= field
; *p
; p
++) {
2091 if (*p
>= 'A' && *p
<= 'Z')
2094 if (*p
>= '0' && *p
<= '9')
2103 _public_
int sd_journal_get_data(sd_journal
*j
, const char *field
, const void **data
, size_t *size
) {
2106 size_t field_length
;
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
);
2117 f
= j
->current_file
;
2119 return -EADDRNOTAVAIL
;
2121 if (f
->current_offset
<= 0)
2122 return -EADDRNOTAVAIL
;
2124 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2128 field_length
= strlen(field
);
2130 n
= journal_file_entry_n_items(o
);
2131 for (i
= 0; i
< n
; i
++) {
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
);
2143 if (le_hash
!= o
->data
.hash
)
2146 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2148 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2150 #if HAVE_XZ || HAVE_LZ4
2151 r
= decompress_startswith(compression
,
2153 &f
->compress_buffer
, &f
->compress_buffer_size
,
2154 field
, field_length
, '=');
2156 log_debug_errno(r
, "Cannot decompress %s object of length %"PRIu64
" at offset "OFSfmt
": %m",
2157 object_compressed_to_string(compression
), l
, p
);
2162 r
= decompress_blob(compression
,
2164 &f
->compress_buffer
, &f
->compress_buffer_size
, &rsize
,
2169 *data
= f
->compress_buffer
;
2170 *size
= (size_t) rsize
;
2175 return -EPROTONOSUPPORT
;
2177 } else if (l
>= field_length
+1 &&
2178 memcmp(o
->data
.payload
, field
, field_length
) == 0 &&
2179 o
->data
.payload
[field_length
] == '=') {
2183 if ((uint64_t) t
!= l
)
2186 *data
= o
->data
.payload
;
2192 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2200 static int return_data(sd_journal
*j
, JournalFile
*f
, Object
*o
, const void **data
, size_t *size
) {
2205 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2208 /* We can't read objects larger than 4G on a 32bit machine */
2209 if ((uint64_t) t
!= l
)
2212 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2214 #if HAVE_XZ || HAVE_LZ4
2218 r
= decompress_blob(compression
,
2219 o
->data
.payload
, l
, &f
->compress_buffer
,
2220 &f
->compress_buffer_size
, &rsize
, j
->data_threshold
);
2224 *data
= f
->compress_buffer
;
2225 *size
= (size_t) rsize
;
2227 return -EPROTONOSUPPORT
;
2230 *data
= o
->data
.payload
;
2237 _public_
int sd_journal_enumerate_data(sd_journal
*j
, const void **data
, size_t *size
) {
2244 assert_return(j
, -EINVAL
);
2245 assert_return(!journal_pid_changed(j
), -ECHILD
);
2246 assert_return(data
, -EINVAL
);
2247 assert_return(size
, -EINVAL
);
2249 f
= j
->current_file
;
2251 return -EADDRNOTAVAIL
;
2253 if (f
->current_offset
<= 0)
2254 return -EADDRNOTAVAIL
;
2256 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2260 n
= journal_file_entry_n_items(o
);
2261 if (j
->current_field
>= n
)
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
);
2270 if (le_hash
!= o
->data
.hash
)
2273 r
= return_data(j
, f
, o
, data
, size
);
2282 _public_
void sd_journal_restart_data(sd_journal
*j
) {
2286 j
->current_field
= 0;
2289 _public_
int sd_journal_get_fd(sd_journal
*j
) {
2292 assert_return(j
, -EINVAL
);
2293 assert_return(!journal_pid_changed(j
), -ECHILD
);
2296 return -EMEDIUMTYPE
;
2298 if (j
->inotify_fd
>= 0)
2299 return j
->inotify_fd
;
2301 r
= allocate_inotify(j
);
2305 log_debug("Reiterating files to get inotify watches established");
2307 /* Iterate through all dirs again, to add them to the
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);
2316 r
= add_root_directory(j
, j
->path
, true);
2318 r
= add_search_paths(j
);
2322 return j
->inotify_fd
;
2325 _public_
int sd_journal_get_events(sd_journal
*j
) {
2328 assert_return(j
, -EINVAL
);
2329 assert_return(!journal_pid_changed(j
), -ECHILD
);
2331 fd
= sd_journal_get_fd(j
);
2338 _public_
int sd_journal_get_timeout(sd_journal
*j
, uint64_t *timeout_usec
) {
2341 assert_return(j
, -EINVAL
);
2342 assert_return(!journal_pid_changed(j
), -ECHILD
);
2343 assert_return(timeout_usec
, -EINVAL
);
2345 fd
= sd_journal_get_fd(j
);
2349 if (!j
->on_network
) {
2350 *timeout_usec
= (uint64_t) -1;
2354 /* If we are on the network we need to regularly check for
2355 * changes manually */
2357 *timeout_usec
= j
->last_process_usec
+ JOURNAL_FILES_RECHECK_USEC
;
2361 static void process_inotify_event(sd_journal
*j
, struct inotify_event
*e
) {
2367 /* Is this a subdirectory we watch? */
2368 d
= hashmap_get(j
->directories_by_wd
, INT_TO_PTR(e
->wd
));
2372 if (!(e
->mask
& IN_ISDIR
) && e
->len
> 0 &&
2373 (endswith(e
->name
, ".journal") ||
2374 endswith(e
->name
, ".journal~"))) {
2376 /* Event for a journal file */
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
);
2383 } else if (!d
->is_root
&& e
->len
== 0) {
2385 /* Event for a subdirectory */
2387 if (e
->mask
& (IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
))
2388 remove_directory(j
, d
);
2390 } else if (d
->is_root
&& (e
->mask
& IN_ISDIR
) && e
->len
> 0 && sd_id128_from_string(e
->name
, &id
) >= 0) {
2392 /* Event for root directory */
2394 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2395 (void) add_directory(j
, d
->path
, e
->name
);
2401 if (e
->mask
& IN_IGNORED
)
2404 log_debug("Unknown inotify event.");
2407 static int determine_change(sd_journal
*j
) {
2412 b
= j
->current_invalidate_counter
!= j
->last_invalidate_counter
;
2413 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2415 return b
? SD_JOURNAL_INVALIDATE
: SD_JOURNAL_APPEND
;
2418 _public_
int sd_journal_process(sd_journal
*j
) {
2419 bool got_something
= false;
2421 assert_return(j
, -EINVAL
);
2422 assert_return(!journal_pid_changed(j
), -ECHILD
);
2424 j
->last_process_usec
= now(CLOCK_MONOTONIC
);
2425 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2428 union inotify_event_buffer buffer
;
2429 struct inotify_event
*e
;
2432 l
= read(j
->inotify_fd
, &buffer
, sizeof(buffer
));
2434 if (IN_SET(errno
, EAGAIN
, EINTR
))
2435 return got_something
? determine_change(j
) : SD_JOURNAL_NOP
;
2440 got_something
= true;
2442 FOREACH_INOTIFY_EVENT(e
, buffer
, l
)
2443 process_inotify_event(j
, e
);
2447 _public_
int sd_journal_wait(sd_journal
*j
, uint64_t timeout_usec
) {
2451 assert_return(j
, -EINVAL
);
2452 assert_return(!journal_pid_changed(j
), -ECHILD
);
2454 if (j
->inotify_fd
< 0) {
2456 /* This is the first invocation, hence create the
2458 r
= sd_journal_get_fd(j
);
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
2466 return determine_change(j
);
2469 r
= sd_journal_get_timeout(j
, &t
);
2473 if (t
!= (uint64_t) -1) {
2476 n
= now(CLOCK_MONOTONIC
);
2477 t
= t
> n
? t
- n
: 0;
2479 if (timeout_usec
== (uint64_t) -1 || timeout_usec
> t
)
2484 r
= fd_wait_for_event(j
->inotify_fd
, POLLIN
, timeout_usec
);
2485 } while (r
== -EINTR
);
2490 return sd_journal_process(j
);
2493 _public_
int sd_journal_get_cutoff_realtime_usec(sd_journal
*j
, uint64_t *from
, uint64_t *to
) {
2497 uint64_t fmin
= 0, tmax
= 0;
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
);
2505 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2508 r
= journal_file_get_cutoff_realtime_usec(f
, &fr
, &t
);
2521 fmin
= MIN(fr
, fmin
);
2522 tmax
= MAX(t
, tmax
);
2531 return first
? 0 : 1;
2534 _public_
int sd_journal_get_cutoff_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t *from
, uint64_t *to
) {
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
);
2545 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2548 r
= journal_file_get_cutoff_monotonic_usec(f
, boot_id
, &fr
, &t
);
2558 *from
= MIN(fr
, *from
);
2573 void journal_print_header(sd_journal
*j
) {
2576 bool newline
= false;
2580 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2586 journal_file_print_header(f
);
2590 _public_
int sd_journal_get_usage(sd_journal
*j
, uint64_t *bytes
) {
2595 assert_return(j
, -EINVAL
);
2596 assert_return(!journal_pid_changed(j
), -ECHILD
);
2597 assert_return(bytes
, -EINVAL
);
2599 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2602 if (fstat(f
->fd
, &st
) < 0)
2605 sum
+= (uint64_t) st
.st_blocks
* 512ULL;
2612 _public_
int sd_journal_query_unique(sd_journal
*j
, const char *field
) {
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
);
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;
2633 _public_
int sd_journal_enumerate_unique(sd_journal
*j
, const void **data
, size_t *l
) {
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
);
2642 k
= strlen(j
->unique_field
);
2644 if (!j
->unique_file
) {
2645 if (j
->unique_file_lost
)
2648 j
->unique_file
= ordered_hashmap_first(j
->files
);
2649 if (!j
->unique_file
)
2652 j
->unique_offset
= 0;
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
);
2670 j
->unique_offset
= r
> 0 ? le64toh(o
->field
.head_data_offset
) : 0;
2672 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_DATA
, j
->unique_offset
, &o
);
2676 j
->unique_offset
= le64toh(o
->data
.next_field_offset
);
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
)
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
);
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
);
2703 r
= return_data(j
, j
->unique_file
, o
, &odata
, &ol
);
2707 /* Check if we have at least the field name and "=". */
2709 log_debug("%s:offset " OFSfmt
": object has size %zu, expected at least %zu",
2710 j
->unique_file
->path
, j
->unique_offset
,
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
,
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. */
2726 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2727 if (of
== j
->unique_file
)
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)
2734 r
= journal_file_find_data_object_with_hash(of
, odata
, ol
, le64toh(o
->data
.hash
), NULL
, NULL
);
2746 r
= return_data(j
, j
->unique_file
, o
, data
, l
);
2754 _public_
void sd_journal_restart_unique(sd_journal
*j
) {
2758 j
->unique_file
= NULL
;
2759 j
->unique_offset
= 0;
2760 j
->unique_file_lost
= false;
2763 _public_
int sd_journal_enumerate_fields(sd_journal
*j
, const char **field
) {
2766 assert_return(j
, -EINVAL
);
2767 assert_return(!journal_pid_changed(j
), -ECHILD
);
2768 assert_return(field
, -EINVAL
);
2770 if (!j
->fields_file
) {
2771 if (j
->fields_file_lost
)
2774 j
->fields_file
= ordered_hashmap_first(j
->files
);
2775 if (!j
->fields_file
)
2778 j
->fields_hash_table_index
= 0;
2779 j
->fields_offset
= 0;
2783 JournalFile
*f
, *of
;
2792 if (j
->fields_offset
== 0) {
2795 /* We are not yet positioned at any field. Let's pick the first one */
2796 r
= journal_file_map_field_hash_table(f
);
2800 m
= le64toh(f
->header
->field_hash_table_size
) / sizeof(HashItem
);
2802 if (j
->fields_hash_table_index
>= m
) {
2803 /* Reached the end of the hash table, go to the next file. */
2808 j
->fields_offset
= le64toh(f
->field_hash_table
[j
->fields_hash_table_index
].head_hash_offset
);
2810 if (j
->fields_offset
!= 0)
2813 /* Empty hash table bucket, go to next one */
2814 j
->fields_hash_table_index
++;
2818 /* Proceed with next file */
2819 j
->fields_file
= ordered_hashmap_next(j
->files
, f
->path
);
2820 if (!j
->fields_file
) {
2825 j
->fields_offset
= 0;
2826 j
->fields_hash_table_index
= 0;
2831 /* We are already positioned at a field. If so, let's figure out the next field from it */
2833 r
= journal_file_move_to_object(f
, OBJECT_FIELD
, j
->fields_offset
, &o
);
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
++;
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
);
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
);
2856 sz
= le64toh(o
->object
.size
) - offsetof(Object
, field
.payload
);
2858 /* Let's see if we already returned this field name before. */
2860 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
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)
2868 r
= journal_file_find_field_object_with_hash(of
, o
->field
.payload
, sz
, le64toh(o
->field
.hash
), NULL
, NULL
);
2880 /* Check if this is really a valid string containing no NUL byte */
2881 if (memchr(o
->field
.payload
, 0, sz
))
2884 if (sz
> j
->data_threshold
)
2885 sz
= j
->data_threshold
;
2887 if (!GREEDY_REALLOC(j
->fields_buffer
, j
->fields_buffer_allocated
, sz
+ 1))
2890 memcpy(j
->fields_buffer
, o
->field
.payload
, sz
);
2891 j
->fields_buffer
[sz
] = 0;
2893 if (!field_is_valid(j
->fields_buffer
))
2896 *field
= j
->fields_buffer
;
2901 _public_
void sd_journal_restart_fields(sd_journal
*j
) {
2905 j
->fields_file
= NULL
;
2906 j
->fields_hash_table_index
= 0;
2907 j
->fields_offset
= 0;
2908 j
->fields_file_lost
= false;
2911 _public_
int sd_journal_reliable_fd(sd_journal
*j
) {
2912 assert_return(j
, -EINVAL
);
2913 assert_return(!journal_pid_changed(j
), -ECHILD
);
2915 return !j
->on_network
;
2918 static char *lookup_field(const char *field
, void *userdata
) {
2919 sd_journal
*j
= userdata
;
2927 r
= sd_journal_get_data(j
, field
, &data
, &size
);
2929 size
> REPLACE_VAR_MAX
)
2930 return strdup(field
);
2932 d
= strlen(field
) + 1;
2934 return strndup((const char*) data
+ d
, size
- d
);
2937 _public_
int sd_journal_get_catalog(sd_journal
*j
, char **ret
) {
2941 _cleanup_free_
char *text
= NULL
, *cid
= NULL
;
2945 assert_return(j
, -EINVAL
);
2946 assert_return(!journal_pid_changed(j
), -ECHILD
);
2947 assert_return(ret
, -EINVAL
);
2949 r
= sd_journal_get_data(j
, "MESSAGE_ID", &data
, &size
);
2953 cid
= strndup((const char*) data
+ 11, size
- 11);
2957 r
= sd_id128_from_string(cid
, &id
);
2961 r
= catalog_get(CATALOG_DATABASE
, id
, &text
);
2965 t
= replace_var(text
, lookup_field
, j
);
2973 _public_
int sd_journal_get_catalog_for_message_id(sd_id128_t id
, char **ret
) {
2974 assert_return(ret
, -EINVAL
);
2976 return catalog_get(CATALOG_DATABASE
, id
, ret
);
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
);
2983 j
->data_threshold
= sz
;
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
);
2992 *sz
= j
->data_threshold
;
2996 _public_
int sd_journal_has_runtime_files(sd_journal
*j
) {
2997 assert_return(j
, -EINVAL
);
2999 return j
->has_runtime_files
;
3002 _public_
int sd_journal_has_persistent_files(sd_journal
*j
) {
3003 assert_return(j
, -EINVAL
);
3005 return j
->has_persistent_files
;