1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2011 Lennart Poettering
9 #include <linux/magic.h>
12 #include <sys/inotify.h>
16 #include "sd-journal.h"
18 #include "alloc-util.h"
21 #include "dirent-util.h"
24 #include "format-util.h"
27 #include "hostname-util.h"
28 #include "id128-util.h"
30 #include "journal-def.h"
31 #include "journal-file.h"
32 #include "journal-internal.h"
36 #include "path-util.h"
37 #include "process-util.h"
38 #include "replace-var.h"
39 #include "stat-util.h"
40 #include "stat-util.h"
41 #include "stdio-util.h"
42 #include "string-util.h"
45 #define JOURNAL_FILES_MAX 7168
47 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
49 #define REPLACE_VAR_MAX 256
51 #define DEFAULT_DATA_THRESHOLD (64*1024)
53 static void remove_file_real(sd_journal
*j
, JournalFile
*f
);
55 static bool journal_pid_changed(sd_journal
*j
) {
58 /* We don't support people creating a journal object and
59 * keeping it around over a fork(). Let's complain. */
61 return j
->original_pid
!= getpid_cached();
64 static int journal_put_error(sd_journal
*j
, int r
, const char *path
) {
68 /* Memorize an error we encountered, and store which
69 * file/directory it was generated from. Note that we store
70 * only *one* path per error code, as the error code is the
71 * key into the hashmap, and the path is the value. This means
72 * we keep track only of all error kinds, but not of all error
73 * locations. This has the benefit that the hashmap cannot
76 * We return an error here only if we didn't manage to
77 * memorize the real error. */
82 k
= hashmap_ensure_allocated(&j
->errors
, NULL
);
93 k
= hashmap_put(j
->errors
, INT_TO_PTR(r
), copy
);
106 static void detach_location(sd_journal
*j
) {
112 j
->current_file
= NULL
;
113 j
->current_field
= 0;
115 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
)
116 journal_file_reset_location(f
);
119 static void reset_location(sd_journal
*j
) {
123 zero(j
->current_location
);
126 static void init_location(Location
*l
, LocationType type
, JournalFile
*f
, Object
*o
) {
128 assert(IN_SET(type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
130 assert(o
->object
.type
== OBJECT_ENTRY
);
133 l
->seqnum
= le64toh(o
->entry
.seqnum
);
134 l
->seqnum_id
= f
->header
->seqnum_id
;
135 l
->realtime
= le64toh(o
->entry
.realtime
);
136 l
->monotonic
= le64toh(o
->entry
.monotonic
);
137 l
->boot_id
= o
->entry
.boot_id
;
138 l
->xor_hash
= le64toh(o
->entry
.xor_hash
);
140 l
->seqnum_set
= l
->realtime_set
= l
->monotonic_set
= l
->xor_hash_set
= true;
143 static void set_location(sd_journal
*j
, JournalFile
*f
, Object
*o
) {
148 init_location(&j
->current_location
, LOCATION_DISCRETE
, f
, o
);
151 j
->current_field
= 0;
153 /* Let f know its candidate entry was picked. */
154 assert(f
->location_type
== LOCATION_SEEK
);
155 f
->location_type
= LOCATION_DISCRETE
;
158 static int match_is_valid(const void *data
, size_t size
) {
166 if (startswith(data
, "__"))
170 for (p
= b
; p
< b
+ size
; p
++) {
178 if (*p
>= 'A' && *p
<= 'Z')
181 if (*p
>= '0' && *p
<= '9')
190 static bool same_field(const void *_a
, size_t s
, const void *_b
, size_t t
) {
191 const uint8_t *a
= _a
, *b
= _b
;
194 for (j
= 0; j
< s
&& j
< t
; j
++) {
203 assert_not_reached("\"=\" not found");
206 static Match
*match_new(Match
*p
, MatchType t
) {
217 LIST_PREPEND(matches
, p
->matches
, m
);
223 static void match_free(Match
*m
) {
227 match_free(m
->matches
);
230 LIST_REMOVE(matches
, m
->parent
->matches
, m
);
236 static void match_free_if_empty(Match
*m
) {
237 if (!m
|| m
->matches
)
243 _public_
int sd_journal_add_match(sd_journal
*j
, const void *data
, size_t size
) {
244 Match
*l3
, *l4
, *add_here
= NULL
, *m
;
247 assert_return(j
, -EINVAL
);
248 assert_return(!journal_pid_changed(j
), -ECHILD
);
249 assert_return(data
, -EINVAL
);
254 assert_return(match_is_valid(data
, size
), -EINVAL
);
260 * level 4: concrete matches */
263 j
->level0
= match_new(NULL
, MATCH_AND_TERM
);
269 j
->level1
= match_new(j
->level0
, MATCH_OR_TERM
);
275 j
->level2
= match_new(j
->level1
, MATCH_AND_TERM
);
280 assert(j
->level0
->type
== MATCH_AND_TERM
);
281 assert(j
->level1
->type
== MATCH_OR_TERM
);
282 assert(j
->level2
->type
== MATCH_AND_TERM
);
284 le_hash
= htole64(hash64(data
, size
));
286 LIST_FOREACH(matches
, l3
, j
->level2
->matches
) {
287 assert(l3
->type
== MATCH_OR_TERM
);
289 LIST_FOREACH(matches
, l4
, l3
->matches
) {
290 assert(l4
->type
== MATCH_DISCRETE
);
292 /* Exactly the same match already? Then ignore
294 if (l4
->le_hash
== le_hash
&&
296 memcmp(l4
->data
, data
, size
) == 0)
299 /* Same field? Then let's add this to this OR term */
300 if (same_field(data
, size
, l4
->data
, l4
->size
)) {
311 add_here
= match_new(j
->level2
, MATCH_OR_TERM
);
316 m
= match_new(add_here
, MATCH_DISCRETE
);
320 m
->le_hash
= le_hash
;
322 m
->data
= memdup(data
, size
);
331 match_free_if_empty(add_here
);
332 match_free_if_empty(j
->level2
);
333 match_free_if_empty(j
->level1
);
334 match_free_if_empty(j
->level0
);
339 _public_
int sd_journal_add_conjunction(sd_journal
*j
) {
340 assert_return(j
, -EINVAL
);
341 assert_return(!journal_pid_changed(j
), -ECHILD
);
349 if (!j
->level1
->matches
)
358 _public_
int sd_journal_add_disjunction(sd_journal
*j
) {
359 assert_return(j
, -EINVAL
);
360 assert_return(!journal_pid_changed(j
), -ECHILD
);
371 if (!j
->level2
->matches
)
378 static char *match_make_string(Match
*m
) {
381 bool enclose
= false;
384 return strdup("none");
386 if (m
->type
== MATCH_DISCRETE
)
387 return strndup(m
->data
, m
->size
);
389 LIST_FOREACH(matches
, i
, m
->matches
) {
392 t
= match_make_string(i
);
397 k
= strjoin(p
, m
->type
== MATCH_OR_TERM
? " OR " : " AND ", t
);
412 r
= strjoin("(", p
, ")");
420 char *journal_make_match_string(sd_journal
*j
) {
423 return match_make_string(j
->level0
);
426 _public_
void sd_journal_flush_matches(sd_journal
*j
) {
431 match_free(j
->level0
);
433 j
->level0
= j
->level1
= j
->level2
= NULL
;
438 _pure_
static int compare_with_location(JournalFile
*f
, Location
*l
) {
441 assert(f
->location_type
== LOCATION_SEEK
);
442 assert(IN_SET(l
->type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
444 if (l
->monotonic_set
&&
445 sd_id128_equal(f
->current_boot_id
, l
->boot_id
) &&
447 f
->current_realtime
== l
->realtime
&&
449 f
->current_xor_hash
== l
->xor_hash
)
453 sd_id128_equal(f
->header
->seqnum_id
, l
->seqnum_id
)) {
455 if (f
->current_seqnum
< l
->seqnum
)
457 if (f
->current_seqnum
> l
->seqnum
)
461 if (l
->monotonic_set
&&
462 sd_id128_equal(f
->current_boot_id
, l
->boot_id
)) {
464 if (f
->current_monotonic
< l
->monotonic
)
466 if (f
->current_monotonic
> l
->monotonic
)
470 if (l
->realtime_set
) {
472 if (f
->current_realtime
< l
->realtime
)
474 if (f
->current_realtime
> l
->realtime
)
478 if (l
->xor_hash_set
) {
480 if (f
->current_xor_hash
< l
->xor_hash
)
482 if (f
->current_xor_hash
> l
->xor_hash
)
489 static int next_for_match(
493 uint64_t after_offset
,
494 direction_t direction
,
506 if (m
->type
== MATCH_DISCRETE
) {
509 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
513 return journal_file_move_to_entry_by_offset_for_data(f
, dp
, after_offset
, direction
, ret
, offset
);
515 } else if (m
->type
== MATCH_OR_TERM
) {
518 /* Find the earliest match beyond after_offset */
520 LIST_FOREACH(matches
, i
, m
->matches
) {
523 r
= next_for_match(j
, i
, f
, after_offset
, direction
, NULL
, &cp
);
527 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
< np
: cp
> np
))
535 } else if (m
->type
== MATCH_AND_TERM
) {
536 Match
*i
, *last_moved
;
538 /* Always jump to the next matching entry and repeat
539 * this until we find an offset that matches for all
545 r
= next_for_match(j
, m
->matches
, f
, after_offset
, direction
, NULL
, &np
);
549 assert(direction
== DIRECTION_DOWN
? np
>= after_offset
: np
<= after_offset
);
550 last_moved
= m
->matches
;
552 LIST_LOOP_BUT_ONE(matches
, i
, m
->matches
, last_moved
) {
555 r
= next_for_match(j
, i
, f
, np
, direction
, NULL
, &cp
);
559 assert(direction
== DIRECTION_DOWN
? cp
>= np
: cp
<= np
);
560 if (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
) {
569 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
581 static int find_location_for_match(
585 direction_t direction
,
595 if (m
->type
== MATCH_DISCRETE
) {
598 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
602 /* FIXME: missing: find by monotonic */
604 if (j
->current_location
.type
== LOCATION_HEAD
)
605 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_DOWN
, ret
, offset
);
606 if (j
->current_location
.type
== LOCATION_TAIL
)
607 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_UP
, ret
, offset
);
608 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
609 return journal_file_move_to_entry_by_seqnum_for_data(f
, dp
, j
->current_location
.seqnum
, direction
, ret
, offset
);
610 if (j
->current_location
.monotonic_set
) {
611 r
= journal_file_move_to_entry_by_monotonic_for_data(f
, dp
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
615 if (j
->current_location
.realtime_set
)
616 return journal_file_move_to_entry_by_realtime_for_data(f
, dp
, j
->current_location
.realtime
, direction
, ret
, offset
);
618 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, direction
, ret
, offset
);
620 } else if (m
->type
== MATCH_OR_TERM
) {
625 /* Find the earliest match */
627 LIST_FOREACH(matches
, i
, m
->matches
) {
630 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
634 if (np
== 0 || (direction
== DIRECTION_DOWN
? np
> cp
: np
< cp
))
642 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
657 assert(m
->type
== MATCH_AND_TERM
);
659 /* First jump to the last match, and then find the
660 * next one where all matches match */
665 LIST_FOREACH(matches
, i
, m
->matches
) {
668 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
672 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
))
676 return next_for_match(j
, m
, f
, np
, direction
, ret
, offset
);
680 static int find_location_with_matches(
683 direction_t direction
,
695 /* No matches is simple */
697 if (j
->current_location
.type
== LOCATION_HEAD
)
698 return journal_file_next_entry(f
, 0, DIRECTION_DOWN
, ret
, offset
);
699 if (j
->current_location
.type
== LOCATION_TAIL
)
700 return journal_file_next_entry(f
, 0, DIRECTION_UP
, ret
, offset
);
701 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
702 return journal_file_move_to_entry_by_seqnum(f
, j
->current_location
.seqnum
, direction
, ret
, offset
);
703 if (j
->current_location
.monotonic_set
) {
704 r
= journal_file_move_to_entry_by_monotonic(f
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
708 if (j
->current_location
.realtime_set
)
709 return journal_file_move_to_entry_by_realtime(f
, j
->current_location
.realtime
, direction
, ret
, offset
);
711 return journal_file_next_entry(f
, 0, direction
, ret
, offset
);
713 return find_location_for_match(j
, j
->level0
, f
, direction
, ret
, offset
);
716 static int next_with_matches(
719 direction_t direction
,
728 /* No matches is easy. We simple advance the file
731 return journal_file_next_entry(f
, f
->current_offset
, direction
, ret
, offset
);
733 /* If we have a match then we look for the next matching entry
734 * with an offset at least one step larger */
735 return next_for_match(j
, j
->level0
, f
,
736 direction
== DIRECTION_DOWN
? f
->current_offset
+ 1
737 : f
->current_offset
- 1,
738 direction
, ret
, offset
);
741 static int next_beyond_location(sd_journal
*j
, JournalFile
*f
, direction_t direction
) {
743 uint64_t cp
, n_entries
;
749 n_entries
= le64toh(f
->header
->n_entries
);
751 /* If we hit EOF before, we don't need to look into this file again
752 * unless direction changed or new entries appeared. */
753 if (f
->last_direction
== direction
&& f
->location_type
== LOCATION_TAIL
&&
754 n_entries
== f
->last_n_entries
)
757 f
->last_n_entries
= n_entries
;
759 if (f
->last_direction
== direction
&& f
->current_offset
> 0) {
760 /* LOCATION_SEEK here means we did the work in a previous
761 * iteration and the current location already points to a
762 * candidate entry. */
763 if (f
->location_type
!= LOCATION_SEEK
) {
764 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
768 journal_file_save_location(f
, c
, cp
);
771 f
->last_direction
= direction
;
773 r
= find_location_with_matches(j
, f
, direction
, &c
, &cp
);
777 journal_file_save_location(f
, c
, cp
);
780 /* OK, we found the spot, now let's advance until an entry
781 * that is actually different from what we were previously
782 * looking at. This is necessary to handle entries which exist
783 * in two (or more) journal files, and which shall all be
784 * suppressed but one. */
789 if (j
->current_location
.type
== LOCATION_DISCRETE
) {
792 k
= compare_with_location(f
, &j
->current_location
);
794 found
= direction
== DIRECTION_DOWN
? k
> 0 : k
< 0;
801 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
805 journal_file_save_location(f
, c
, cp
);
809 static int real_journal_next(sd_journal
*j
, direction_t direction
) {
810 JournalFile
*new_file
= NULL
;
816 assert_return(j
, -EINVAL
);
817 assert_return(!journal_pid_changed(j
), -ECHILD
);
819 r
= iterated_cache_get(j
->files_cache
, NULL
, &files
, &n_files
);
823 for (i
= 0; i
< n_files
; i
++) {
824 JournalFile
*f
= (JournalFile
*)files
[i
];
827 r
= next_beyond_location(j
, f
, direction
);
829 log_debug_errno(r
, "Can't iterate through %s, ignoring: %m", f
->path
);
830 remove_file_real(j
, f
);
833 f
->location_type
= LOCATION_TAIL
;
842 k
= journal_file_compare_locations(f
, new_file
);
844 found
= direction
== DIRECTION_DOWN
? k
< 0 : k
> 0;
854 r
= journal_file_move_to_object(new_file
, OBJECT_ENTRY
, new_file
->current_offset
, &o
);
858 set_location(j
, new_file
, o
);
863 _public_
int sd_journal_next(sd_journal
*j
) {
864 return real_journal_next(j
, DIRECTION_DOWN
);
867 _public_
int sd_journal_previous(sd_journal
*j
) {
868 return real_journal_next(j
, DIRECTION_UP
);
871 static int real_journal_next_skip(sd_journal
*j
, direction_t direction
, uint64_t skip
) {
874 assert_return(j
, -EINVAL
);
875 assert_return(!journal_pid_changed(j
), -ECHILD
);
878 /* If this is not a discrete skip, then at least
879 * resolve the current location */
880 if (j
->current_location
.type
!= LOCATION_DISCRETE
) {
881 r
= real_journal_next(j
, direction
);
890 r
= real_journal_next(j
, direction
);
904 _public_
int sd_journal_next_skip(sd_journal
*j
, uint64_t skip
) {
905 return real_journal_next_skip(j
, DIRECTION_DOWN
, skip
);
908 _public_
int sd_journal_previous_skip(sd_journal
*j
, uint64_t skip
) {
909 return real_journal_next_skip(j
, DIRECTION_UP
, skip
);
912 _public_
int sd_journal_get_cursor(sd_journal
*j
, char **cursor
) {
915 char bid
[33], sid
[33];
917 assert_return(j
, -EINVAL
);
918 assert_return(!journal_pid_changed(j
), -ECHILD
);
919 assert_return(cursor
, -EINVAL
);
921 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
922 return -EADDRNOTAVAIL
;
924 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
928 sd_id128_to_string(j
->current_file
->header
->seqnum_id
, sid
);
929 sd_id128_to_string(o
->entry
.boot_id
, bid
);
932 "s=%s;i=%"PRIx64
";b=%s;m=%"PRIx64
";t=%"PRIx64
";x=%"PRIx64
,
933 sid
, le64toh(o
->entry
.seqnum
),
934 bid
, le64toh(o
->entry
.monotonic
),
935 le64toh(o
->entry
.realtime
),
936 le64toh(o
->entry
.xor_hash
)) < 0)
942 _public_
int sd_journal_seek_cursor(sd_journal
*j
, const char *cursor
) {
943 const char *word
, *state
;
945 unsigned long long seqnum
, monotonic
, realtime
, xor_hash
;
947 seqnum_id_set
= false,
950 monotonic_set
= false,
951 realtime_set
= false,
952 xor_hash_set
= false;
953 sd_id128_t seqnum_id
, boot_id
;
955 assert_return(j
, -EINVAL
);
956 assert_return(!journal_pid_changed(j
), -ECHILD
);
957 assert_return(!isempty(cursor
), -EINVAL
);
959 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
963 if (l
< 2 || word
[1] != '=')
966 item
= strndup(word
, l
);
973 seqnum_id_set
= true;
974 k
= sd_id128_from_string(item
+2, &seqnum_id
);
979 if (sscanf(item
+2, "%llx", &seqnum
) != 1)
985 k
= sd_id128_from_string(item
+2, &boot_id
);
989 monotonic_set
= true;
990 if (sscanf(item
+2, "%llx", &monotonic
) != 1)
996 if (sscanf(item
+2, "%llx", &realtime
) != 1)
1001 xor_hash_set
= true;
1002 if (sscanf(item
+2, "%llx", &xor_hash
) != 1)
1013 if ((!seqnum_set
|| !seqnum_id_set
) &&
1014 (!monotonic_set
|| !boot_id_set
) &&
1020 j
->current_location
.type
= LOCATION_SEEK
;
1023 j
->current_location
.realtime
= (uint64_t) realtime
;
1024 j
->current_location
.realtime_set
= true;
1027 if (seqnum_set
&& seqnum_id_set
) {
1028 j
->current_location
.seqnum
= (uint64_t) seqnum
;
1029 j
->current_location
.seqnum_id
= seqnum_id
;
1030 j
->current_location
.seqnum_set
= true;
1033 if (monotonic_set
&& boot_id_set
) {
1034 j
->current_location
.monotonic
= (uint64_t) monotonic
;
1035 j
->current_location
.boot_id
= boot_id
;
1036 j
->current_location
.monotonic_set
= true;
1040 j
->current_location
.xor_hash
= (uint64_t) xor_hash
;
1041 j
->current_location
.xor_hash_set
= true;
1047 _public_
int sd_journal_test_cursor(sd_journal
*j
, const char *cursor
) {
1051 assert_return(j
, -EINVAL
);
1052 assert_return(!journal_pid_changed(j
), -ECHILD
);
1053 assert_return(!isempty(cursor
), -EINVAL
);
1055 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
1056 return -EADDRNOTAVAIL
;
1058 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
1063 _cleanup_free_
char *item
= NULL
;
1064 unsigned long long ll
;
1068 r
= extract_first_word(&cursor
, &item
, ";", EXTRACT_DONT_COALESCE_SEPARATORS
);
1075 if (strlen(item
) < 2 || item
[1] != '=')
1081 k
= sd_id128_from_string(item
+2, &id
);
1084 if (!sd_id128_equal(id
, j
->current_file
->header
->seqnum_id
))
1089 if (sscanf(item
+2, "%llx", &ll
) != 1)
1091 if (ll
!= le64toh(o
->entry
.seqnum
))
1096 k
= sd_id128_from_string(item
+2, &id
);
1099 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1104 if (sscanf(item
+2, "%llx", &ll
) != 1)
1106 if (ll
!= le64toh(o
->entry
.monotonic
))
1111 if (sscanf(item
+2, "%llx", &ll
) != 1)
1113 if (ll
!= le64toh(o
->entry
.realtime
))
1118 if (sscanf(item
+2, "%llx", &ll
) != 1)
1120 if (ll
!= le64toh(o
->entry
.xor_hash
))
1129 _public_
int sd_journal_seek_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t usec
) {
1130 assert_return(j
, -EINVAL
);
1131 assert_return(!journal_pid_changed(j
), -ECHILD
);
1134 j
->current_location
.type
= LOCATION_SEEK
;
1135 j
->current_location
.boot_id
= boot_id
;
1136 j
->current_location
.monotonic
= usec
;
1137 j
->current_location
.monotonic_set
= true;
1142 _public_
int sd_journal_seek_realtime_usec(sd_journal
*j
, uint64_t usec
) {
1143 assert_return(j
, -EINVAL
);
1144 assert_return(!journal_pid_changed(j
), -ECHILD
);
1147 j
->current_location
.type
= LOCATION_SEEK
;
1148 j
->current_location
.realtime
= usec
;
1149 j
->current_location
.realtime_set
= true;
1154 _public_
int sd_journal_seek_head(sd_journal
*j
) {
1155 assert_return(j
, -EINVAL
);
1156 assert_return(!journal_pid_changed(j
), -ECHILD
);
1159 j
->current_location
.type
= LOCATION_HEAD
;
1164 _public_
int sd_journal_seek_tail(sd_journal
*j
) {
1165 assert_return(j
, -EINVAL
);
1166 assert_return(!journal_pid_changed(j
), -ECHILD
);
1169 j
->current_location
.type
= LOCATION_TAIL
;
1174 static void check_network(sd_journal
*j
, int fd
) {
1180 j
->on_network
= fd_is_network_fs(fd
);
1183 static bool file_has_type_prefix(const char *prefix
, const char *filename
) {
1184 const char *full
, *tilded
, *atted
;
1186 full
= strjoina(prefix
, ".journal");
1187 tilded
= strjoina(full
, "~");
1188 atted
= strjoina(prefix
, "@");
1190 return streq(filename
, full
) ||
1191 streq(filename
, tilded
) ||
1192 startswith(filename
, atted
);
1195 static bool file_type_wanted(int flags
, const char *filename
) {
1198 if (!endswith(filename
, ".journal") && !endswith(filename
, ".journal~"))
1201 /* no flags set → every type is OK */
1202 if (!(flags
& (SD_JOURNAL_SYSTEM
| SD_JOURNAL_CURRENT_USER
)))
1205 if (flags
& SD_JOURNAL_SYSTEM
&& file_has_type_prefix("system", filename
))
1208 if (flags
& SD_JOURNAL_CURRENT_USER
) {
1209 char prefix
[5 + DECIMAL_STR_MAX(uid_t
) + 1];
1211 xsprintf(prefix
, "user-"UID_FMT
, getuid());
1213 if (file_has_type_prefix(prefix
, filename
))
1220 static bool path_has_prefix(sd_journal
*j
, const char *path
, const char *prefix
) {
1225 if (j
->toplevel_fd
>= 0)
1228 return path_startswith(path
, prefix
);
1231 static void track_file_disposition(sd_journal
*j
, JournalFile
*f
) {
1235 if (!j
->has_runtime_files
&& path_has_prefix(j
, f
->path
, "/run"))
1236 j
->has_runtime_files
= true;
1237 else if (!j
->has_persistent_files
&& path_has_prefix(j
, f
->path
, "/var"))
1238 j
->has_persistent_files
= true;
1241 static const char *skip_slash(const char *p
) {
1252 static int add_any_file(
1257 bool close_fd
= false;
1263 assert(fd
>= 0 || path
);
1266 if (j
->toplevel_fd
>= 0)
1267 /* If there's a top-level fd defined make the path relative, explicitly, since otherwise
1268 * openat() ignores the first argument. */
1270 fd
= openat(j
->toplevel_fd
, skip_slash(path
), O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
);
1272 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
);
1274 r
= log_debug_errno(errno
, "Failed to open journal file %s: %m", path
);
1280 r
= fd_nonblock(fd
, false);
1282 r
= log_debug_errno(errno
, "Failed to turn off O_NONBLOCK for %s: %m", path
);
1287 if (fstat(fd
, &st
) < 0) {
1288 r
= log_debug_errno(errno
, "Failed to fstat file '%s': %m", path
);
1292 r
= stat_verify_regular(&st
);
1294 log_debug_errno(r
, "Refusing to open '%s', as it is not a regular file.", path
);
1298 f
= ordered_hashmap_get(j
->files
, path
);
1300 if (f
->last_stat
.st_dev
== st
.st_dev
&&
1301 f
->last_stat
.st_ino
== st
.st_ino
) {
1303 /* We already track this file, under the same path and with the same device/inode numbers, it's
1304 * hence really the same. Mark this file as seen in this generation. This is used to GC old
1305 * files in process_q_overflow() to detect journal files that are still there and discern them
1306 * from those which are gone. */
1308 f
->last_seen_generation
= j
->generation
;
1313 /* So we tracked a file under this name, but it has a different inode/device. In that case, it got
1314 * replaced (probably due to rotation?), let's drop it hence from our list. */
1315 remove_file_real(j
, f
);
1319 if (ordered_hashmap_size(j
->files
) >= JOURNAL_FILES_MAX
) {
1320 log_debug("Too many open journal files, not adding %s.", path
);
1325 r
= journal_file_open(fd
, path
, O_RDONLY
, 0, false, 0, false, NULL
, j
->mmap
, NULL
, NULL
, &f
);
1327 log_debug_errno(r
, "Failed to open journal file %s: %m", path
);
1331 /* journal_file_dump(f); */
1333 r
= ordered_hashmap_put(j
->files
, f
->path
, f
);
1335 f
->close_fd
= false; /* make sure journal_file_close() doesn't close the caller's fd (or our own). We'll let the caller do that, or ourselves */
1336 (void) journal_file_close(f
);
1340 close_fd
= false; /* the fd is now owned by the JournalFile object */
1342 f
->last_seen_generation
= j
->generation
;
1344 track_file_disposition(j
, f
);
1345 check_network(j
, f
->fd
);
1347 j
->current_invalidate_counter
++;
1349 log_debug("File %s added.", f
->path
);
1358 k
= journal_put_error(j
, r
, path
);
1366 static int add_file_by_name(
1369 const char *filename
) {
1377 if (j
->no_new_files
)
1380 if (!file_type_wanted(j
->flags
, filename
))
1383 path
= strjoina(prefix
, "/", filename
);
1384 return add_any_file(j
, -1, path
);
1387 static void remove_file_by_name(
1390 const char *filename
) {
1399 path
= strjoina(prefix
, "/", filename
);
1400 f
= ordered_hashmap_get(j
->files
, path
);
1404 remove_file_real(j
, f
);
1407 static void remove_file_real(sd_journal
*j
, JournalFile
*f
) {
1411 (void) ordered_hashmap_remove(j
->files
, f
->path
);
1413 log_debug("File %s removed.", f
->path
);
1415 if (j
->current_file
== f
) {
1416 j
->current_file
= NULL
;
1417 j
->current_field
= 0;
1420 if (j
->unique_file
== f
) {
1421 /* Jump to the next unique_file or NULL if that one was last */
1422 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
1423 j
->unique_offset
= 0;
1424 if (!j
->unique_file
)
1425 j
->unique_file_lost
= true;
1428 if (j
->fields_file
== f
) {
1429 j
->fields_file
= ordered_hashmap_next(j
->files
, j
->fields_file
->path
);
1430 j
->fields_offset
= 0;
1431 if (!j
->fields_file
)
1432 j
->fields_file_lost
= true;
1435 (void) journal_file_close(f
);
1437 j
->current_invalidate_counter
++;
1440 static int dirname_is_machine_id(const char *fn
) {
1441 sd_id128_t id
, machine
;
1444 r
= sd_id128_get_machine(&machine
);
1448 r
= sd_id128_from_string(fn
, &id
);
1452 return sd_id128_equal(id
, machine
);
1455 static bool dirent_is_journal_file(const struct dirent
*de
) {
1458 if (!IN_SET(de
->d_type
, DT_REG
, DT_LNK
, DT_UNKNOWN
))
1461 return endswith(de
->d_name
, ".journal") ||
1462 endswith(de
->d_name
, ".journal~");
1465 static bool dirent_is_id128_subdir(const struct dirent
*de
) {
1468 if (!IN_SET(de
->d_type
, DT_DIR
, DT_LNK
, DT_UNKNOWN
))
1471 return id128_is_valid(de
->d_name
);
1474 static int directory_open(sd_journal
*j
, const char *path
, DIR **ret
) {
1481 if (j
->toplevel_fd
< 0)
1484 /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
1485 * relative, by dropping the initial slash */
1486 d
= xopendirat(j
->toplevel_fd
, skip_slash(path
), 0);
1494 static int add_directory(sd_journal
*j
, const char *prefix
, const char *dirname
);
1496 static void directory_enumerate(sd_journal
*j
, Directory
*m
, DIR *d
) {
1503 FOREACH_DIRENT_ALL(de
, d
, goto fail
) {
1505 if (dirent_is_journal_file(de
))
1506 (void) add_file_by_name(j
, m
->path
, de
->d_name
);
1508 if (m
->is_root
&& dirent_is_id128_subdir(de
))
1509 (void) add_directory(j
, m
->path
, de
->d_name
);
1515 log_debug_errno(errno
, "Failed to enumerate directory %s, ignoring: %m", m
->path
);
1518 static void directory_watch(sd_journal
*j
, Directory
*m
, int fd
, uint32_t mask
) {
1525 /* Watch this directory if that's enabled and if it not being watched yet. */
1527 if (m
->wd
> 0) /* Already have a watch? */
1529 if (j
->inotify_fd
< 0) /* Not watching at all? */
1532 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, fd
, mask
);
1534 log_debug_errno(errno
, "Failed to watch journal directory '%s', ignoring: %m", m
->path
);
1538 r
= hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
);
1540 log_debug_errno(r
, "Directory '%s' already being watched under a different path, ignoring: %m", m
->path
);
1542 log_debug_errno(r
, "Failed to add watch for journal directory '%s' to hashmap, ignoring: %m", m
->path
);
1543 (void) inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1548 static int add_directory(sd_journal
*j
, const char *prefix
, const char *dirname
) {
1549 _cleanup_free_
char *path
= NULL
;
1550 _cleanup_closedir_
DIR *d
= NULL
;
1557 /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
1558 * and reenumerates directory contents */
1561 path
= strjoin(prefix
, "/", dirname
);
1563 path
= strdup(prefix
);
1569 log_debug("Considering directory '%s'.", path
);
1571 /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
1572 if ((j
->flags
& SD_JOURNAL_LOCAL_ONLY
) &&
1573 !((dirname
&& dirname_is_machine_id(dirname
) > 0) || path_has_prefix(j
, path
, "/run")))
1576 r
= directory_open(j
, path
, &d
);
1578 log_debug_errno(r
, "Failed to open directory '%s': %m", path
);
1582 m
= hashmap_get(j
->directories_by_path
, path
);
1584 m
= new0(Directory
, 1);
1593 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1599 path
= NULL
; /* avoid freeing in cleanup */
1600 j
->current_invalidate_counter
++;
1602 log_debug("Directory %s added.", m
->path
);
1604 } else if (m
->is_root
)
1605 return 0; /* Don't 'downgrade' from root directory */
1607 m
->last_seen_generation
= j
->generation
;
1609 directory_watch(j
, m
, dirfd(d
),
1610 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1611 IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
|IN_MOVED_FROM
|
1614 if (!j
->no_new_files
)
1615 directory_enumerate(j
, m
, d
);
1617 check_network(j
, dirfd(d
));
1622 k
= journal_put_error(j
, r
, path
?: prefix
);
1629 static int add_root_directory(sd_journal
*j
, const char *p
, bool missing_ok
) {
1631 _cleanup_closedir_
DIR *d
= NULL
;
1637 /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
1638 * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
1639 * populate the set, as well as to update it later. */
1642 /* If there's a path specified, use it. */
1644 log_debug("Considering root directory '%s'.", p
);
1646 if ((j
->flags
& SD_JOURNAL_RUNTIME_ONLY
) &&
1647 !path_has_prefix(j
, p
, "/run"))
1651 p
= strjoina(j
->prefix
, p
);
1653 r
= directory_open(j
, p
, &d
);
1654 if (r
== -ENOENT
&& missing_ok
)
1657 log_debug_errno(r
, "Failed to open root directory %s: %m", p
);
1663 /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
1664 * opendir() will take possession of the fd, and close it, which we don't want. */
1666 p
= "."; /* store this as "." in the directories hashmap */
1668 dfd
= fcntl(j
->toplevel_fd
, F_DUPFD_CLOEXEC
, 3);
1684 m
= hashmap_get(j
->directories_by_path
, p
);
1686 m
= new0(Directory
, 1);
1694 m
->path
= strdup(p
);
1701 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1708 j
->current_invalidate_counter
++;
1710 log_debug("Root directory %s added.", m
->path
);
1712 } else if (!m
->is_root
)
1715 directory_watch(j
, m
, dirfd(d
),
1716 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1719 if (!j
->no_new_files
)
1720 directory_enumerate(j
, m
, d
);
1722 check_network(j
, dirfd(d
));
1727 k
= journal_put_error(j
, r
, p
);
1734 static void remove_directory(sd_journal
*j
, Directory
*d
) {
1738 hashmap_remove(j
->directories_by_wd
, INT_TO_PTR(d
->wd
));
1740 if (j
->inotify_fd
>= 0)
1741 inotify_rm_watch(j
->inotify_fd
, d
->wd
);
1744 hashmap_remove(j
->directories_by_path
, d
->path
);
1747 log_debug("Root directory %s removed.", d
->path
);
1749 log_debug("Directory %s removed.", d
->path
);
1755 static int add_search_paths(sd_journal
*j
) {
1757 static const char search_paths
[] =
1758 "/run/log/journal\0"
1759 "/var/log/journal\0";
1764 /* We ignore most errors here, since the idea is to only open
1765 * what's actually accessible, and ignore the rest. */
1767 NULSTR_FOREACH(p
, search_paths
)
1768 (void) add_root_directory(j
, p
, true);
1770 if (!(j
->flags
& SD_JOURNAL_LOCAL_ONLY
))
1771 (void) add_root_directory(j
, "/var/log/journal/remote", true);
1776 static int add_current_paths(sd_journal
*j
) {
1781 assert(j
->no_new_files
);
1783 /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
1784 * treat them as fatal. */
1786 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1787 _cleanup_free_
char *dir
;
1790 dir
= dirname_malloc(f
->path
);
1794 r
= add_directory(j
, dir
, NULL
);
1802 static int allocate_inotify(sd_journal
*j
) {
1805 if (j
->inotify_fd
< 0) {
1806 j
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1807 if (j
->inotify_fd
< 0)
1811 return hashmap_ensure_allocated(&j
->directories_by_wd
, NULL
);
1814 static sd_journal
*journal_new(int flags
, const char *path
) {
1815 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1817 j
= new0(sd_journal
, 1);
1821 j
->original_pid
= getpid_cached();
1822 j
->toplevel_fd
= -1;
1825 j
->data_threshold
= DEFAULT_DATA_THRESHOLD
;
1834 if (flags
& SD_JOURNAL_OS_ROOT
)
1840 j
->files
= ordered_hashmap_new(&path_hash_ops
);
1844 j
->files_cache
= ordered_hashmap_iterated_cache_new(j
->files
);
1845 j
->directories_by_path
= hashmap_new(&path_hash_ops
);
1846 j
->mmap
= mmap_cache_new();
1847 if (!j
->files_cache
|| !j
->directories_by_path
|| !j
->mmap
)
1853 #define OPEN_ALLOWED_FLAGS \
1854 (SD_JOURNAL_LOCAL_ONLY | \
1855 SD_JOURNAL_RUNTIME_ONLY | \
1856 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)
1858 _public_
int sd_journal_open(sd_journal
**ret
, int flags
) {
1859 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1862 assert_return(ret
, -EINVAL
);
1863 assert_return((flags
& ~OPEN_ALLOWED_FLAGS
) == 0, -EINVAL
);
1865 j
= journal_new(flags
, NULL
);
1869 r
= add_search_paths(j
);
1877 #define OPEN_CONTAINER_ALLOWED_FLAGS \
1878 (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
1880 _public_
int sd_journal_open_container(sd_journal
**ret
, const char *machine
, int flags
) {
1881 _cleanup_free_
char *root
= NULL
, *class = NULL
;
1882 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1886 /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
1887 * combination with sd_journal_open_directory_fd(). */
1889 assert_return(machine
, -EINVAL
);
1890 assert_return(ret
, -EINVAL
);
1891 assert_return((flags
& ~OPEN_CONTAINER_ALLOWED_FLAGS
) == 0, -EINVAL
);
1892 assert_return(machine_name_is_valid(machine
), -EINVAL
);
1894 p
= strjoina("/run/systemd/machines/", machine
);
1895 r
= parse_env_file(NULL
, p
, NEWLINE
, "ROOT", &root
, "CLASS", &class, NULL
);
1903 if (!streq_ptr(class, "container"))
1906 j
= journal_new(flags
, root
);
1910 r
= add_search_paths(j
);
1918 #define OPEN_DIRECTORY_ALLOWED_FLAGS \
1919 (SD_JOURNAL_OS_ROOT | \
1920 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1922 _public_
int sd_journal_open_directory(sd_journal
**ret
, const char *path
, int flags
) {
1923 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1926 assert_return(ret
, -EINVAL
);
1927 assert_return(path
, -EINVAL
);
1928 assert_return((flags
& ~OPEN_DIRECTORY_ALLOWED_FLAGS
) == 0, -EINVAL
);
1930 j
= journal_new(flags
, path
);
1934 if (flags
& SD_JOURNAL_OS_ROOT
)
1935 r
= add_search_paths(j
);
1937 r
= add_root_directory(j
, path
, false);
1945 _public_
int sd_journal_open_files(sd_journal
**ret
, const char **paths
, int flags
) {
1946 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1950 assert_return(ret
, -EINVAL
);
1951 assert_return(flags
== 0, -EINVAL
);
1953 j
= journal_new(flags
, NULL
);
1957 STRV_FOREACH(path
, paths
) {
1958 r
= add_any_file(j
, -1, *path
);
1963 j
->no_new_files
= true;
1969 #define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
1970 (SD_JOURNAL_OS_ROOT | \
1971 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1973 _public_
int sd_journal_open_directory_fd(sd_journal
**ret
, int fd
, int flags
) {
1974 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1978 assert_return(ret
, -EINVAL
);
1979 assert_return(fd
>= 0, -EBADF
);
1980 assert_return((flags
& ~OPEN_DIRECTORY_FD_ALLOWED_FLAGS
) == 0, -EINVAL
);
1982 if (fstat(fd
, &st
) < 0)
1985 if (!S_ISDIR(st
.st_mode
))
1988 j
= journal_new(flags
, NULL
);
1992 j
->toplevel_fd
= fd
;
1994 if (flags
& SD_JOURNAL_OS_ROOT
)
1995 r
= add_search_paths(j
);
1997 r
= add_root_directory(j
, NULL
, false);
2005 _public_
int sd_journal_open_files_fd(sd_journal
**ret
, int fds
[], unsigned n_fds
, int flags
) {
2008 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
2012 assert_return(ret
, -EINVAL
);
2013 assert_return(n_fds
> 0, -EBADF
);
2014 assert_return(flags
== 0, -EINVAL
);
2016 j
= journal_new(flags
, NULL
);
2020 for (i
= 0; i
< n_fds
; i
++) {
2028 if (fstat(fds
[i
], &st
) < 0) {
2033 r
= stat_verify_regular(&st
);
2037 r
= add_any_file(j
, fds
[i
], NULL
);
2042 j
->no_new_files
= true;
2043 j
->no_inotify
= true;
2049 /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
2051 ORDERED_HASHMAP_FOREACH(f
, j
->files
, iterator
)
2052 f
->close_fd
= false;
2057 _public_
void sd_journal_close(sd_journal
*j
) {
2063 sd_journal_flush_matches(j
);
2065 ordered_hashmap_free_with_destructor(j
->files
, journal_file_close
);
2066 iterated_cache_free(j
->files_cache
);
2068 while ((d
= hashmap_first(j
->directories_by_path
)))
2069 remove_directory(j
, d
);
2071 while ((d
= hashmap_first(j
->directories_by_wd
)))
2072 remove_directory(j
, d
);
2074 hashmap_free(j
->directories_by_path
);
2075 hashmap_free(j
->directories_by_wd
);
2077 safe_close(j
->inotify_fd
);
2080 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j
->mmap
), mmap_cache_get_missed(j
->mmap
));
2081 mmap_cache_unref(j
->mmap
);
2084 hashmap_free_free(j
->errors
);
2088 free(j
->unique_field
);
2089 free(j
->fields_buffer
);
2093 _public_
int sd_journal_get_realtime_usec(sd_journal
*j
, uint64_t *ret
) {
2098 assert_return(j
, -EINVAL
);
2099 assert_return(!journal_pid_changed(j
), -ECHILD
);
2100 assert_return(ret
, -EINVAL
);
2102 f
= j
->current_file
;
2104 return -EADDRNOTAVAIL
;
2106 if (f
->current_offset
<= 0)
2107 return -EADDRNOTAVAIL
;
2109 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2113 *ret
= le64toh(o
->entry
.realtime
);
2117 _public_
int sd_journal_get_monotonic_usec(sd_journal
*j
, uint64_t *ret
, sd_id128_t
*ret_boot_id
) {
2123 assert_return(j
, -EINVAL
);
2124 assert_return(!journal_pid_changed(j
), -ECHILD
);
2126 f
= j
->current_file
;
2128 return -EADDRNOTAVAIL
;
2130 if (f
->current_offset
<= 0)
2131 return -EADDRNOTAVAIL
;
2133 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2138 *ret_boot_id
= o
->entry
.boot_id
;
2140 r
= sd_id128_get_boot(&id
);
2144 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
2149 *ret
= le64toh(o
->entry
.monotonic
);
2154 static bool field_is_valid(const char *field
) {
2162 if (startswith(field
, "__"))
2165 for (p
= field
; *p
; p
++) {
2170 if (*p
>= 'A' && *p
<= 'Z')
2173 if (*p
>= '0' && *p
<= '9')
2182 _public_
int sd_journal_get_data(sd_journal
*j
, const char *field
, const void **data
, size_t *size
) {
2185 size_t field_length
;
2189 assert_return(j
, -EINVAL
);
2190 assert_return(!journal_pid_changed(j
), -ECHILD
);
2191 assert_return(field
, -EINVAL
);
2192 assert_return(data
, -EINVAL
);
2193 assert_return(size
, -EINVAL
);
2194 assert_return(field_is_valid(field
), -EINVAL
);
2196 f
= j
->current_file
;
2198 return -EADDRNOTAVAIL
;
2200 if (f
->current_offset
<= 0)
2201 return -EADDRNOTAVAIL
;
2203 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2207 field_length
= strlen(field
);
2209 n
= journal_file_entry_n_items(o
);
2210 for (i
= 0; i
< n
; i
++) {
2216 p
= le64toh(o
->entry
.items
[i
].object_offset
);
2217 le_hash
= o
->entry
.items
[i
].hash
;
2218 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2222 if (le_hash
!= o
->data
.hash
)
2225 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2227 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2229 #if HAVE_XZ || HAVE_LZ4
2230 r
= decompress_startswith(compression
,
2232 &f
->compress_buffer
, &f
->compress_buffer_size
,
2233 field
, field_length
, '=');
2235 log_debug_errno(r
, "Cannot decompress %s object of length %"PRIu64
" at offset "OFSfmt
": %m",
2236 object_compressed_to_string(compression
), l
, p
);
2241 r
= decompress_blob(compression
,
2243 &f
->compress_buffer
, &f
->compress_buffer_size
, &rsize
,
2248 *data
= f
->compress_buffer
;
2249 *size
= (size_t) rsize
;
2254 return -EPROTONOSUPPORT
;
2256 } else if (l
>= field_length
+1 &&
2257 memcmp(o
->data
.payload
, field
, field_length
) == 0 &&
2258 o
->data
.payload
[field_length
] == '=') {
2262 if ((uint64_t) t
!= l
)
2265 *data
= o
->data
.payload
;
2271 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2279 static int return_data(sd_journal
*j
, JournalFile
*f
, Object
*o
, const void **data
, size_t *size
) {
2284 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2287 /* We can't read objects larger than 4G on a 32bit machine */
2288 if ((uint64_t) t
!= l
)
2291 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2293 #if HAVE_XZ || HAVE_LZ4
2297 r
= decompress_blob(compression
,
2298 o
->data
.payload
, l
, &f
->compress_buffer
,
2299 &f
->compress_buffer_size
, &rsize
, j
->data_threshold
);
2303 *data
= f
->compress_buffer
;
2304 *size
= (size_t) rsize
;
2306 return -EPROTONOSUPPORT
;
2309 *data
= o
->data
.payload
;
2316 _public_
int sd_journal_enumerate_data(sd_journal
*j
, const void **data
, size_t *size
) {
2323 assert_return(j
, -EINVAL
);
2324 assert_return(!journal_pid_changed(j
), -ECHILD
);
2325 assert_return(data
, -EINVAL
);
2326 assert_return(size
, -EINVAL
);
2328 f
= j
->current_file
;
2330 return -EADDRNOTAVAIL
;
2332 if (f
->current_offset
<= 0)
2333 return -EADDRNOTAVAIL
;
2335 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2339 n
= journal_file_entry_n_items(o
);
2340 if (j
->current_field
>= n
)
2343 p
= le64toh(o
->entry
.items
[j
->current_field
].object_offset
);
2344 le_hash
= o
->entry
.items
[j
->current_field
].hash
;
2345 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2349 if (le_hash
!= o
->data
.hash
)
2352 r
= return_data(j
, f
, o
, data
, size
);
2361 _public_
void sd_journal_restart_data(sd_journal
*j
) {
2365 j
->current_field
= 0;
2368 static int reiterate_all_paths(sd_journal
*j
) {
2371 if (j
->no_new_files
)
2372 return add_current_paths(j
);
2374 if (j
->flags
& SD_JOURNAL_OS_ROOT
)
2375 return add_search_paths(j
);
2377 if (j
->toplevel_fd
>= 0)
2378 return add_root_directory(j
, NULL
, false);
2381 return add_root_directory(j
, j
->path
, true);
2383 return add_search_paths(j
);
2386 _public_
int sd_journal_get_fd(sd_journal
*j
) {
2389 assert_return(j
, -EINVAL
);
2390 assert_return(!journal_pid_changed(j
), -ECHILD
);
2393 return -EMEDIUMTYPE
;
2395 if (j
->inotify_fd
>= 0)
2396 return j
->inotify_fd
;
2398 r
= allocate_inotify(j
);
2402 log_debug("Reiterating files to get inotify watches established.");
2404 /* Iterate through all dirs again, to add them to the inotify */
2405 r
= reiterate_all_paths(j
);
2409 return j
->inotify_fd
;
2412 _public_
int sd_journal_get_events(sd_journal
*j
) {
2415 assert_return(j
, -EINVAL
);
2416 assert_return(!journal_pid_changed(j
), -ECHILD
);
2418 fd
= sd_journal_get_fd(j
);
2425 _public_
int sd_journal_get_timeout(sd_journal
*j
, uint64_t *timeout_usec
) {
2428 assert_return(j
, -EINVAL
);
2429 assert_return(!journal_pid_changed(j
), -ECHILD
);
2430 assert_return(timeout_usec
, -EINVAL
);
2432 fd
= sd_journal_get_fd(j
);
2436 if (!j
->on_network
) {
2437 *timeout_usec
= (uint64_t) -1;
2441 /* If we are on the network we need to regularly check for
2442 * changes manually */
2444 *timeout_usec
= j
->last_process_usec
+ JOURNAL_FILES_RECHECK_USEC
;
2448 static void process_q_overflow(sd_journal
*j
) {
2455 /* When the inotify queue overruns we need to enumerate and re-validate all journal files to bring our list
2456 * back in sync with what's on disk. For this we pick a new generation counter value. It'll be assigned to all
2457 * journal files we encounter. All journal files and all directories that don't carry it after reenumeration
2458 * are subject for unloading. */
2460 log_debug("Inotify queue overrun, reiterating everything.");
2463 (void) reiterate_all_paths(j
);
2465 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2467 if (f
->last_seen_generation
== j
->generation
)
2470 log_debug("File '%s' hasn't been seen in this enumeration, removing.", f
->path
);
2471 remove_file_real(j
, f
);
2474 HASHMAP_FOREACH(m
, j
->directories_by_path
, i
) {
2476 if (m
->last_seen_generation
== j
->generation
)
2479 if (m
->is_root
) /* Never GC root directories */
2482 log_debug("Directory '%s' hasn't been seen in this enumeration, removing.", f
->path
);
2483 remove_directory(j
, m
);
2486 log_debug("Reiteration complete.");
2489 static void process_inotify_event(sd_journal
*j
, struct inotify_event
*e
) {
2495 if (e
->mask
& IN_Q_OVERFLOW
) {
2496 process_q_overflow(j
);
2500 /* Is this a subdirectory we watch? */
2501 d
= hashmap_get(j
->directories_by_wd
, INT_TO_PTR(e
->wd
));
2503 if (!(e
->mask
& IN_ISDIR
) && e
->len
> 0 &&
2504 (endswith(e
->name
, ".journal") ||
2505 endswith(e
->name
, ".journal~"))) {
2507 /* Event for a journal file */
2509 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2510 (void) add_file_by_name(j
, d
->path
, e
->name
);
2511 else if (e
->mask
& (IN_DELETE
|IN_MOVED_FROM
|IN_UNMOUNT
))
2512 remove_file_by_name(j
, d
->path
, e
->name
);
2514 } else if (!d
->is_root
&& e
->len
== 0) {
2516 /* Event for a subdirectory */
2518 if (e
->mask
& (IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
))
2519 remove_directory(j
, d
);
2521 } else if (d
->is_root
&& (e
->mask
& IN_ISDIR
) && e
->len
> 0 && id128_is_valid(e
->name
)) {
2523 /* Event for root directory */
2525 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2526 (void) add_directory(j
, d
->path
, e
->name
);
2532 if (e
->mask
& IN_IGNORED
)
2535 log_debug("Unexpected inotify event.");
2538 static int determine_change(sd_journal
*j
) {
2543 b
= j
->current_invalidate_counter
!= j
->last_invalidate_counter
;
2544 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2546 return b
? SD_JOURNAL_INVALIDATE
: SD_JOURNAL_APPEND
;
2549 _public_
int sd_journal_process(sd_journal
*j
) {
2550 bool got_something
= false;
2552 assert_return(j
, -EINVAL
);
2553 assert_return(!journal_pid_changed(j
), -ECHILD
);
2555 if (j
->inotify_fd
< 0) /* We have no inotify fd yet? Then there's noting to process. */
2558 j
->last_process_usec
= now(CLOCK_MONOTONIC
);
2559 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2562 union inotify_event_buffer buffer
;
2563 struct inotify_event
*e
;
2566 l
= read(j
->inotify_fd
, &buffer
, sizeof(buffer
));
2568 if (IN_SET(errno
, EAGAIN
, EINTR
))
2569 return got_something
? determine_change(j
) : SD_JOURNAL_NOP
;
2574 got_something
= true;
2576 FOREACH_INOTIFY_EVENT(e
, buffer
, l
)
2577 process_inotify_event(j
, e
);
2581 _public_
int sd_journal_wait(sd_journal
*j
, uint64_t timeout_usec
) {
2585 assert_return(j
, -EINVAL
);
2586 assert_return(!journal_pid_changed(j
), -ECHILD
);
2588 if (j
->inotify_fd
< 0) {
2590 /* This is the first invocation, hence create the
2592 r
= sd_journal_get_fd(j
);
2596 /* The journal might have changed since the context
2597 * object was created and we weren't watching before,
2598 * hence don't wait for anything, and return
2600 return determine_change(j
);
2603 r
= sd_journal_get_timeout(j
, &t
);
2607 if (t
!= (uint64_t) -1) {
2610 n
= now(CLOCK_MONOTONIC
);
2611 t
= t
> n
? t
- n
: 0;
2613 if (timeout_usec
== (uint64_t) -1 || timeout_usec
> t
)
2618 r
= fd_wait_for_event(j
->inotify_fd
, POLLIN
, timeout_usec
);
2619 } while (r
== -EINTR
);
2624 return sd_journal_process(j
);
2627 _public_
int sd_journal_get_cutoff_realtime_usec(sd_journal
*j
, uint64_t *from
, uint64_t *to
) {
2631 uint64_t fmin
= 0, tmax
= 0;
2634 assert_return(j
, -EINVAL
);
2635 assert_return(!journal_pid_changed(j
), -ECHILD
);
2636 assert_return(from
|| to
, -EINVAL
);
2637 assert_return(from
!= to
, -EINVAL
);
2639 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2642 r
= journal_file_get_cutoff_realtime_usec(f
, &fr
, &t
);
2655 fmin
= MIN(fr
, fmin
);
2656 tmax
= MAX(t
, tmax
);
2665 return first
? 0 : 1;
2668 _public_
int sd_journal_get_cutoff_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t *from
, uint64_t *to
) {
2674 assert_return(j
, -EINVAL
);
2675 assert_return(!journal_pid_changed(j
), -ECHILD
);
2676 assert_return(from
|| to
, -EINVAL
);
2677 assert_return(from
!= to
, -EINVAL
);
2679 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2682 r
= journal_file_get_cutoff_monotonic_usec(f
, boot_id
, &fr
, &t
);
2692 *from
= MIN(fr
, *from
);
2707 void journal_print_header(sd_journal
*j
) {
2710 bool newline
= false;
2714 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2720 journal_file_print_header(f
);
2724 _public_
int sd_journal_get_usage(sd_journal
*j
, uint64_t *bytes
) {
2729 assert_return(j
, -EINVAL
);
2730 assert_return(!journal_pid_changed(j
), -ECHILD
);
2731 assert_return(bytes
, -EINVAL
);
2733 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2736 if (fstat(f
->fd
, &st
) < 0)
2739 sum
+= (uint64_t) st
.st_blocks
* 512ULL;
2746 _public_
int sd_journal_query_unique(sd_journal
*j
, const char *field
) {
2749 assert_return(j
, -EINVAL
);
2750 assert_return(!journal_pid_changed(j
), -ECHILD
);
2751 assert_return(!isempty(field
), -EINVAL
);
2752 assert_return(field_is_valid(field
), -EINVAL
);
2758 free(j
->unique_field
);
2759 j
->unique_field
= f
;
2760 j
->unique_file
= NULL
;
2761 j
->unique_offset
= 0;
2762 j
->unique_file_lost
= false;
2767 _public_
int sd_journal_enumerate_unique(sd_journal
*j
, const void **data
, size_t *l
) {
2770 assert_return(j
, -EINVAL
);
2771 assert_return(!journal_pid_changed(j
), -ECHILD
);
2772 assert_return(data
, -EINVAL
);
2773 assert_return(l
, -EINVAL
);
2774 assert_return(j
->unique_field
, -EINVAL
);
2776 k
= strlen(j
->unique_field
);
2778 if (!j
->unique_file
) {
2779 if (j
->unique_file_lost
)
2782 j
->unique_file
= ordered_hashmap_first(j
->files
);
2783 if (!j
->unique_file
)
2786 j
->unique_offset
= 0;
2798 /* Proceed to next data object in the field's linked list */
2799 if (j
->unique_offset
== 0) {
2800 r
= journal_file_find_field_object(j
->unique_file
, j
->unique_field
, k
, &o
, NULL
);
2804 j
->unique_offset
= r
> 0 ? le64toh(o
->field
.head_data_offset
) : 0;
2806 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_DATA
, j
->unique_offset
, &o
);
2810 j
->unique_offset
= le64toh(o
->data
.next_field_offset
);
2813 /* We reached the end of the list? Then start again, with the next file */
2814 if (j
->unique_offset
== 0) {
2815 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
2816 if (!j
->unique_file
)
2822 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2823 * instead, so that we can look at this data object at the same
2824 * time as one on another file */
2825 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_UNUSED
, j
->unique_offset
, &o
);
2829 /* Let's do the type check by hand, since we used 0 context above. */
2830 if (o
->object
.type
!= OBJECT_DATA
) {
2831 log_debug("%s:offset " OFSfmt
": object has type %d, expected %d",
2832 j
->unique_file
->path
, j
->unique_offset
,
2833 o
->object
.type
, OBJECT_DATA
);
2837 r
= return_data(j
, j
->unique_file
, o
, &odata
, &ol
);
2841 /* Check if we have at least the field name and "=". */
2843 log_debug("%s:offset " OFSfmt
": object has size %zu, expected at least %zu",
2844 j
->unique_file
->path
, j
->unique_offset
,
2849 if (memcmp(odata
, j
->unique_field
, k
) || ((const char*) odata
)[k
] != '=') {
2850 log_debug("%s:offset " OFSfmt
": object does not start with \"%s=\"",
2851 j
->unique_file
->path
, j
->unique_offset
,
2856 /* OK, now let's see if we already returned this data
2857 * object by checking if it exists in the earlier
2858 * traversed files. */
2860 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2861 if (of
== j
->unique_file
)
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_data_object_with_hash(of
, odata
, ol
, le64toh(o
->data
.hash
), NULL
, NULL
);
2880 r
= return_data(j
, j
->unique_file
, o
, data
, l
);
2888 _public_
void sd_journal_restart_unique(sd_journal
*j
) {
2892 j
->unique_file
= NULL
;
2893 j
->unique_offset
= 0;
2894 j
->unique_file_lost
= false;
2897 _public_
int sd_journal_enumerate_fields(sd_journal
*j
, const char **field
) {
2900 assert_return(j
, -EINVAL
);
2901 assert_return(!journal_pid_changed(j
), -ECHILD
);
2902 assert_return(field
, -EINVAL
);
2904 if (!j
->fields_file
) {
2905 if (j
->fields_file_lost
)
2908 j
->fields_file
= ordered_hashmap_first(j
->files
);
2909 if (!j
->fields_file
)
2912 j
->fields_hash_table_index
= 0;
2913 j
->fields_offset
= 0;
2917 JournalFile
*f
, *of
;
2926 if (j
->fields_offset
== 0) {
2929 /* We are not yet positioned at any field. Let's pick the first one */
2930 r
= journal_file_map_field_hash_table(f
);
2934 m
= le64toh(f
->header
->field_hash_table_size
) / sizeof(HashItem
);
2936 if (j
->fields_hash_table_index
>= m
) {
2937 /* Reached the end of the hash table, go to the next file. */
2942 j
->fields_offset
= le64toh(f
->field_hash_table
[j
->fields_hash_table_index
].head_hash_offset
);
2944 if (j
->fields_offset
!= 0)
2947 /* Empty hash table bucket, go to next one */
2948 j
->fields_hash_table_index
++;
2952 /* Proceed with next file */
2953 j
->fields_file
= ordered_hashmap_next(j
->files
, f
->path
);
2954 if (!j
->fields_file
) {
2959 j
->fields_offset
= 0;
2960 j
->fields_hash_table_index
= 0;
2965 /* We are already positioned at a field. If so, let's figure out the next field from it */
2967 r
= journal_file_move_to_object(f
, OBJECT_FIELD
, j
->fields_offset
, &o
);
2971 j
->fields_offset
= le64toh(o
->field
.next_hash_offset
);
2972 if (j
->fields_offset
== 0) {
2973 /* Reached the end of the hash table chain */
2974 j
->fields_hash_table_index
++;
2979 /* We use OBJECT_UNUSED here, so that the iterator below doesn't remove our mmap window */
2980 r
= journal_file_move_to_object(f
, OBJECT_UNUSED
, j
->fields_offset
, &o
);
2984 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
2985 if (o
->object
.type
!= OBJECT_FIELD
) {
2986 log_debug("%s:offset " OFSfmt
": object has type %i, expected %i", f
->path
, j
->fields_offset
, o
->object
.type
, OBJECT_FIELD
);
2990 sz
= le64toh(o
->object
.size
) - offsetof(Object
, field
.payload
);
2992 /* Let's see if we already returned this field name before. */
2994 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2998 /* Skip this file it didn't have any fields indexed */
2999 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
3002 r
= journal_file_find_field_object_with_hash(of
, o
->field
.payload
, sz
, le64toh(o
->field
.hash
), NULL
, NULL
);
3014 /* Check if this is really a valid string containing no NUL byte */
3015 if (memchr(o
->field
.payload
, 0, sz
))
3018 if (sz
> j
->data_threshold
)
3019 sz
= j
->data_threshold
;
3021 if (!GREEDY_REALLOC(j
->fields_buffer
, j
->fields_buffer_allocated
, sz
+ 1))
3024 memcpy(j
->fields_buffer
, o
->field
.payload
, sz
);
3025 j
->fields_buffer
[sz
] = 0;
3027 if (!field_is_valid(j
->fields_buffer
))
3030 *field
= j
->fields_buffer
;
3035 _public_
void sd_journal_restart_fields(sd_journal
*j
) {
3039 j
->fields_file
= NULL
;
3040 j
->fields_hash_table_index
= 0;
3041 j
->fields_offset
= 0;
3042 j
->fields_file_lost
= false;
3045 _public_
int sd_journal_reliable_fd(sd_journal
*j
) {
3046 assert_return(j
, -EINVAL
);
3047 assert_return(!journal_pid_changed(j
), -ECHILD
);
3049 return !j
->on_network
;
3052 static char *lookup_field(const char *field
, void *userdata
) {
3053 sd_journal
*j
= userdata
;
3061 r
= sd_journal_get_data(j
, field
, &data
, &size
);
3063 size
> REPLACE_VAR_MAX
)
3064 return strdup(field
);
3066 d
= strlen(field
) + 1;
3068 return strndup((const char*) data
+ d
, size
- d
);
3071 _public_
int sd_journal_get_catalog(sd_journal
*j
, char **ret
) {
3075 _cleanup_free_
char *text
= NULL
, *cid
= NULL
;
3079 assert_return(j
, -EINVAL
);
3080 assert_return(!journal_pid_changed(j
), -ECHILD
);
3081 assert_return(ret
, -EINVAL
);
3083 r
= sd_journal_get_data(j
, "MESSAGE_ID", &data
, &size
);
3087 cid
= strndup((const char*) data
+ 11, size
- 11);
3091 r
= sd_id128_from_string(cid
, &id
);
3095 r
= catalog_get(CATALOG_DATABASE
, id
, &text
);
3099 t
= replace_var(text
, lookup_field
, j
);
3107 _public_
int sd_journal_get_catalog_for_message_id(sd_id128_t id
, char **ret
) {
3108 assert_return(ret
, -EINVAL
);
3110 return catalog_get(CATALOG_DATABASE
, id
, ret
);
3113 _public_
int sd_journal_set_data_threshold(sd_journal
*j
, size_t sz
) {
3114 assert_return(j
, -EINVAL
);
3115 assert_return(!journal_pid_changed(j
), -ECHILD
);
3117 j
->data_threshold
= sz
;
3121 _public_
int sd_journal_get_data_threshold(sd_journal
*j
, size_t *sz
) {
3122 assert_return(j
, -EINVAL
);
3123 assert_return(!journal_pid_changed(j
), -ECHILD
);
3124 assert_return(sz
, -EINVAL
);
3126 *sz
= j
->data_threshold
;
3130 _public_
int sd_journal_has_runtime_files(sd_journal
*j
) {
3131 assert_return(j
, -EINVAL
);
3133 return j
->has_runtime_files
;
3136 _public_
int sd_journal_has_persistent_files(sd_journal
*j
) {
3137 assert_return(j
, -EINVAL
);
3139 return j
->has_persistent_files
;