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 "replace-var.h"
52 #include "stat-util.h"
53 #include "stdio-util.h"
54 #include "string-util.h"
57 #define JOURNAL_FILES_MAX 7168
59 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
61 #define REPLACE_VAR_MAX 256
63 #define DEFAULT_DATA_THRESHOLD (64*1024)
65 static void remove_file_real(sd_journal
*j
, JournalFile
*f
);
67 static bool journal_pid_changed(sd_journal
*j
) {
70 /* We don't support people creating a journal object and
71 * keeping it around over a fork(). Let's complain. */
73 return j
->original_pid
!= getpid_cached();
76 static int journal_put_error(sd_journal
*j
, int r
, const char *path
) {
80 /* Memorize an error we encountered, and store which
81 * file/directory it was generated from. Note that we store
82 * only *one* path per error code, as the error code is the
83 * key into the hashmap, and the path is the value. This means
84 * we keep track only of all error kinds, but not of all error
85 * locations. This has the benefit that the hashmap cannot
88 * We return an error here only if we didn't manage to
89 * memorize the real error. */
94 k
= hashmap_ensure_allocated(&j
->errors
, NULL
);
105 k
= hashmap_put(j
->errors
, INT_TO_PTR(r
), copy
);
118 static void detach_location(sd_journal
*j
) {
124 j
->current_file
= NULL
;
125 j
->current_field
= 0;
127 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
)
128 journal_file_reset_location(f
);
131 static void reset_location(sd_journal
*j
) {
135 zero(j
->current_location
);
138 static void init_location(Location
*l
, LocationType type
, JournalFile
*f
, Object
*o
) {
140 assert(IN_SET(type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
142 assert(o
->object
.type
== OBJECT_ENTRY
);
145 l
->seqnum
= le64toh(o
->entry
.seqnum
);
146 l
->seqnum_id
= f
->header
->seqnum_id
;
147 l
->realtime
= le64toh(o
->entry
.realtime
);
148 l
->monotonic
= le64toh(o
->entry
.monotonic
);
149 l
->boot_id
= o
->entry
.boot_id
;
150 l
->xor_hash
= le64toh(o
->entry
.xor_hash
);
152 l
->seqnum_set
= l
->realtime_set
= l
->monotonic_set
= l
->xor_hash_set
= true;
155 static void set_location(sd_journal
*j
, JournalFile
*f
, Object
*o
) {
160 init_location(&j
->current_location
, LOCATION_DISCRETE
, f
, o
);
163 j
->current_field
= 0;
165 /* Let f know its candidate entry was picked. */
166 assert(f
->location_type
== LOCATION_SEEK
);
167 f
->location_type
= LOCATION_DISCRETE
;
170 static int match_is_valid(const void *data
, size_t size
) {
178 if (startswith(data
, "__"))
182 for (p
= b
; p
< b
+ size
; p
++) {
190 if (*p
>= 'A' && *p
<= 'Z')
193 if (*p
>= '0' && *p
<= '9')
202 static bool same_field(const void *_a
, size_t s
, const void *_b
, size_t t
) {
203 const uint8_t *a
= _a
, *b
= _b
;
206 for (j
= 0; j
< s
&& j
< t
; j
++) {
215 assert_not_reached("\"=\" not found");
218 static Match
*match_new(Match
*p
, MatchType t
) {
229 LIST_PREPEND(matches
, p
->matches
, m
);
235 static void match_free(Match
*m
) {
239 match_free(m
->matches
);
242 LIST_REMOVE(matches
, m
->parent
->matches
, m
);
248 static void match_free_if_empty(Match
*m
) {
249 if (!m
|| m
->matches
)
255 _public_
int sd_journal_add_match(sd_journal
*j
, const void *data
, size_t size
) {
256 Match
*l3
, *l4
, *add_here
= NULL
, *m
;
259 assert_return(j
, -EINVAL
);
260 assert_return(!journal_pid_changed(j
), -ECHILD
);
261 assert_return(data
, -EINVAL
);
266 assert_return(match_is_valid(data
, size
), -EINVAL
);
272 * level 4: concrete matches */
275 j
->level0
= match_new(NULL
, MATCH_AND_TERM
);
281 j
->level1
= match_new(j
->level0
, MATCH_OR_TERM
);
287 j
->level2
= match_new(j
->level1
, MATCH_AND_TERM
);
292 assert(j
->level0
->type
== MATCH_AND_TERM
);
293 assert(j
->level1
->type
== MATCH_OR_TERM
);
294 assert(j
->level2
->type
== MATCH_AND_TERM
);
296 le_hash
= htole64(hash64(data
, size
));
298 LIST_FOREACH(matches
, l3
, j
->level2
->matches
) {
299 assert(l3
->type
== MATCH_OR_TERM
);
301 LIST_FOREACH(matches
, l4
, l3
->matches
) {
302 assert(l4
->type
== MATCH_DISCRETE
);
304 /* Exactly the same match already? Then ignore
306 if (l4
->le_hash
== le_hash
&&
308 memcmp(l4
->data
, data
, size
) == 0)
311 /* Same field? Then let's add this to this OR term */
312 if (same_field(data
, size
, l4
->data
, l4
->size
)) {
323 add_here
= match_new(j
->level2
, MATCH_OR_TERM
);
328 m
= match_new(add_here
, MATCH_DISCRETE
);
332 m
->le_hash
= le_hash
;
334 m
->data
= memdup(data
, size
);
343 match_free_if_empty(add_here
);
344 match_free_if_empty(j
->level2
);
345 match_free_if_empty(j
->level1
);
346 match_free_if_empty(j
->level0
);
351 _public_
int sd_journal_add_conjunction(sd_journal
*j
) {
352 assert_return(j
, -EINVAL
);
353 assert_return(!journal_pid_changed(j
), -ECHILD
);
361 if (!j
->level1
->matches
)
370 _public_
int sd_journal_add_disjunction(sd_journal
*j
) {
371 assert_return(j
, -EINVAL
);
372 assert_return(!journal_pid_changed(j
), -ECHILD
);
383 if (!j
->level2
->matches
)
390 static char *match_make_string(Match
*m
) {
393 bool enclose
= false;
396 return strdup("none");
398 if (m
->type
== MATCH_DISCRETE
)
399 return strndup(m
->data
, m
->size
);
401 LIST_FOREACH(matches
, i
, m
->matches
) {
404 t
= match_make_string(i
);
409 k
= strjoin(p
, m
->type
== MATCH_OR_TERM
? " OR " : " AND ", t
);
424 r
= strjoin("(", p
, ")");
432 char *journal_make_match_string(sd_journal
*j
) {
435 return match_make_string(j
->level0
);
438 _public_
void sd_journal_flush_matches(sd_journal
*j
) {
443 match_free(j
->level0
);
445 j
->level0
= j
->level1
= j
->level2
= NULL
;
450 _pure_
static int compare_with_location(JournalFile
*f
, Location
*l
) {
453 assert(f
->location_type
== LOCATION_SEEK
);
454 assert(IN_SET(l
->type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
456 if (l
->monotonic_set
&&
457 sd_id128_equal(f
->current_boot_id
, l
->boot_id
) &&
459 f
->current_realtime
== l
->realtime
&&
461 f
->current_xor_hash
== l
->xor_hash
)
465 sd_id128_equal(f
->header
->seqnum_id
, l
->seqnum_id
)) {
467 if (f
->current_seqnum
< l
->seqnum
)
469 if (f
->current_seqnum
> l
->seqnum
)
473 if (l
->monotonic_set
&&
474 sd_id128_equal(f
->current_boot_id
, l
->boot_id
)) {
476 if (f
->current_monotonic
< l
->monotonic
)
478 if (f
->current_monotonic
> l
->monotonic
)
482 if (l
->realtime_set
) {
484 if (f
->current_realtime
< l
->realtime
)
486 if (f
->current_realtime
> l
->realtime
)
490 if (l
->xor_hash_set
) {
492 if (f
->current_xor_hash
< l
->xor_hash
)
494 if (f
->current_xor_hash
> l
->xor_hash
)
501 static int next_for_match(
505 uint64_t after_offset
,
506 direction_t direction
,
518 if (m
->type
== MATCH_DISCRETE
) {
521 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
525 return journal_file_move_to_entry_by_offset_for_data(f
, dp
, after_offset
, direction
, ret
, offset
);
527 } else if (m
->type
== MATCH_OR_TERM
) {
530 /* Find the earliest match beyond after_offset */
532 LIST_FOREACH(matches
, i
, m
->matches
) {
535 r
= next_for_match(j
, i
, f
, after_offset
, direction
, NULL
, &cp
);
539 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
< np
: cp
> np
))
547 } else if (m
->type
== MATCH_AND_TERM
) {
548 Match
*i
, *last_moved
;
550 /* Always jump to the next matching entry and repeat
551 * this until we find an offset that matches for all
557 r
= next_for_match(j
, m
->matches
, f
, after_offset
, direction
, NULL
, &np
);
561 assert(direction
== DIRECTION_DOWN
? np
>= after_offset
: np
<= after_offset
);
562 last_moved
= m
->matches
;
564 LIST_LOOP_BUT_ONE(matches
, i
, m
->matches
, last_moved
) {
567 r
= next_for_match(j
, i
, f
, np
, direction
, NULL
, &cp
);
571 assert(direction
== DIRECTION_DOWN
? cp
>= np
: cp
<= np
);
572 if (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
) {
581 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
593 static int find_location_for_match(
597 direction_t direction
,
607 if (m
->type
== MATCH_DISCRETE
) {
610 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
614 /* FIXME: missing: find by monotonic */
616 if (j
->current_location
.type
== LOCATION_HEAD
)
617 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_DOWN
, ret
, offset
);
618 if (j
->current_location
.type
== LOCATION_TAIL
)
619 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_UP
, ret
, offset
);
620 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
621 return journal_file_move_to_entry_by_seqnum_for_data(f
, dp
, j
->current_location
.seqnum
, direction
, ret
, offset
);
622 if (j
->current_location
.monotonic_set
) {
623 r
= journal_file_move_to_entry_by_monotonic_for_data(f
, dp
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
627 if (j
->current_location
.realtime_set
)
628 return journal_file_move_to_entry_by_realtime_for_data(f
, dp
, j
->current_location
.realtime
, direction
, ret
, offset
);
630 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, direction
, ret
, offset
);
632 } else if (m
->type
== MATCH_OR_TERM
) {
637 /* Find the earliest match */
639 LIST_FOREACH(matches
, i
, m
->matches
) {
642 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
646 if (np
== 0 || (direction
== DIRECTION_DOWN
? np
> cp
: np
< cp
))
654 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
669 assert(m
->type
== MATCH_AND_TERM
);
671 /* First jump to the last match, and then find the
672 * next one where all matches match */
677 LIST_FOREACH(matches
, i
, m
->matches
) {
680 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
684 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
))
688 return next_for_match(j
, m
, f
, np
, direction
, ret
, offset
);
692 static int find_location_with_matches(
695 direction_t direction
,
707 /* No matches is simple */
709 if (j
->current_location
.type
== LOCATION_HEAD
)
710 return journal_file_next_entry(f
, 0, DIRECTION_DOWN
, ret
, offset
);
711 if (j
->current_location
.type
== LOCATION_TAIL
)
712 return journal_file_next_entry(f
, 0, DIRECTION_UP
, ret
, offset
);
713 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
714 return journal_file_move_to_entry_by_seqnum(f
, j
->current_location
.seqnum
, direction
, ret
, offset
);
715 if (j
->current_location
.monotonic_set
) {
716 r
= journal_file_move_to_entry_by_monotonic(f
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
720 if (j
->current_location
.realtime_set
)
721 return journal_file_move_to_entry_by_realtime(f
, j
->current_location
.realtime
, direction
, ret
, offset
);
723 return journal_file_next_entry(f
, 0, direction
, ret
, offset
);
725 return find_location_for_match(j
, j
->level0
, f
, direction
, ret
, offset
);
728 static int next_with_matches(
731 direction_t direction
,
740 /* No matches is easy. We simple advance the file
743 return journal_file_next_entry(f
, f
->current_offset
, direction
, ret
, offset
);
745 /* If we have a match then we look for the next matching entry
746 * with an offset at least one step larger */
747 return next_for_match(j
, j
->level0
, f
,
748 direction
== DIRECTION_DOWN
? f
->current_offset
+ 1
749 : f
->current_offset
- 1,
750 direction
, ret
, offset
);
753 static int next_beyond_location(sd_journal
*j
, JournalFile
*f
, direction_t direction
) {
755 uint64_t cp
, n_entries
;
761 n_entries
= le64toh(f
->header
->n_entries
);
763 /* If we hit EOF before, we don't need to look into this file again
764 * unless direction changed or new entries appeared. */
765 if (f
->last_direction
== direction
&& f
->location_type
== LOCATION_TAIL
&&
766 n_entries
== f
->last_n_entries
)
769 f
->last_n_entries
= n_entries
;
771 if (f
->last_direction
== direction
&& f
->current_offset
> 0) {
772 /* LOCATION_SEEK here means we did the work in a previous
773 * iteration and the current location already points to a
774 * candidate entry. */
775 if (f
->location_type
!= LOCATION_SEEK
) {
776 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
780 journal_file_save_location(f
, c
, cp
);
783 f
->last_direction
= direction
;
785 r
= find_location_with_matches(j
, f
, direction
, &c
, &cp
);
789 journal_file_save_location(f
, c
, cp
);
792 /* OK, we found the spot, now let's advance until an entry
793 * that is actually different from what we were previously
794 * looking at. This is necessary to handle entries which exist
795 * in two (or more) journal files, and which shall all be
796 * suppressed but one. */
801 if (j
->current_location
.type
== LOCATION_DISCRETE
) {
804 k
= compare_with_location(f
, &j
->current_location
);
806 found
= direction
== DIRECTION_DOWN
? k
> 0 : k
< 0;
813 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
817 journal_file_save_location(f
, c
, cp
);
821 static int real_journal_next(sd_journal
*j
, direction_t direction
) {
822 JournalFile
*new_file
= NULL
;
828 assert_return(j
, -EINVAL
);
829 assert_return(!journal_pid_changed(j
), -ECHILD
);
831 r
= iterated_cache_get(j
->files_cache
, NULL
, &files
, &n_files
);
835 for (i
= 0; i
< n_files
; i
++) {
836 JournalFile
*f
= (JournalFile
*)files
[i
];
839 r
= next_beyond_location(j
, f
, direction
);
841 log_debug_errno(r
, "Can't iterate through %s, ignoring: %m", f
->path
);
842 remove_file_real(j
, f
);
845 f
->location_type
= LOCATION_TAIL
;
854 k
= journal_file_compare_locations(f
, new_file
);
856 found
= direction
== DIRECTION_DOWN
? k
< 0 : k
> 0;
866 r
= journal_file_move_to_object(new_file
, OBJECT_ENTRY
, new_file
->current_offset
, &o
);
870 set_location(j
, new_file
, o
);
875 _public_
int sd_journal_next(sd_journal
*j
) {
876 return real_journal_next(j
, DIRECTION_DOWN
);
879 _public_
int sd_journal_previous(sd_journal
*j
) {
880 return real_journal_next(j
, DIRECTION_UP
);
883 static int real_journal_next_skip(sd_journal
*j
, direction_t direction
, uint64_t skip
) {
886 assert_return(j
, -EINVAL
);
887 assert_return(!journal_pid_changed(j
), -ECHILD
);
890 /* If this is not a discrete skip, then at least
891 * resolve the current location */
892 if (j
->current_location
.type
!= LOCATION_DISCRETE
) {
893 r
= real_journal_next(j
, direction
);
902 r
= real_journal_next(j
, direction
);
916 _public_
int sd_journal_next_skip(sd_journal
*j
, uint64_t skip
) {
917 return real_journal_next_skip(j
, DIRECTION_DOWN
, skip
);
920 _public_
int sd_journal_previous_skip(sd_journal
*j
, uint64_t skip
) {
921 return real_journal_next_skip(j
, DIRECTION_UP
, skip
);
924 _public_
int sd_journal_get_cursor(sd_journal
*j
, char **cursor
) {
927 char bid
[33], sid
[33];
929 assert_return(j
, -EINVAL
);
930 assert_return(!journal_pid_changed(j
), -ECHILD
);
931 assert_return(cursor
, -EINVAL
);
933 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
934 return -EADDRNOTAVAIL
;
936 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
940 sd_id128_to_string(j
->current_file
->header
->seqnum_id
, sid
);
941 sd_id128_to_string(o
->entry
.boot_id
, bid
);
944 "s=%s;i=%"PRIx64
";b=%s;m=%"PRIx64
";t=%"PRIx64
";x=%"PRIx64
,
945 sid
, le64toh(o
->entry
.seqnum
),
946 bid
, le64toh(o
->entry
.monotonic
),
947 le64toh(o
->entry
.realtime
),
948 le64toh(o
->entry
.xor_hash
)) < 0)
954 _public_
int sd_journal_seek_cursor(sd_journal
*j
, const char *cursor
) {
955 const char *word
, *state
;
957 unsigned long long seqnum
, monotonic
, realtime
, xor_hash
;
959 seqnum_id_set
= false,
962 monotonic_set
= false,
963 realtime_set
= false,
964 xor_hash_set
= false;
965 sd_id128_t seqnum_id
, boot_id
;
967 assert_return(j
, -EINVAL
);
968 assert_return(!journal_pid_changed(j
), -ECHILD
);
969 assert_return(!isempty(cursor
), -EINVAL
);
971 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
975 if (l
< 2 || word
[1] != '=')
978 item
= strndup(word
, l
);
985 seqnum_id_set
= true;
986 k
= sd_id128_from_string(item
+2, &seqnum_id
);
991 if (sscanf(item
+2, "%llx", &seqnum
) != 1)
997 k
= sd_id128_from_string(item
+2, &boot_id
);
1001 monotonic_set
= true;
1002 if (sscanf(item
+2, "%llx", &monotonic
) != 1)
1007 realtime_set
= true;
1008 if (sscanf(item
+2, "%llx", &realtime
) != 1)
1013 xor_hash_set
= true;
1014 if (sscanf(item
+2, "%llx", &xor_hash
) != 1)
1025 if ((!seqnum_set
|| !seqnum_id_set
) &&
1026 (!monotonic_set
|| !boot_id_set
) &&
1032 j
->current_location
.type
= LOCATION_SEEK
;
1035 j
->current_location
.realtime
= (uint64_t) realtime
;
1036 j
->current_location
.realtime_set
= true;
1039 if (seqnum_set
&& seqnum_id_set
) {
1040 j
->current_location
.seqnum
= (uint64_t) seqnum
;
1041 j
->current_location
.seqnum_id
= seqnum_id
;
1042 j
->current_location
.seqnum_set
= true;
1045 if (monotonic_set
&& boot_id_set
) {
1046 j
->current_location
.monotonic
= (uint64_t) monotonic
;
1047 j
->current_location
.boot_id
= boot_id
;
1048 j
->current_location
.monotonic_set
= true;
1052 j
->current_location
.xor_hash
= (uint64_t) xor_hash
;
1053 j
->current_location
.xor_hash_set
= true;
1059 _public_
int sd_journal_test_cursor(sd_journal
*j
, const char *cursor
) {
1063 assert_return(j
, -EINVAL
);
1064 assert_return(!journal_pid_changed(j
), -ECHILD
);
1065 assert_return(!isempty(cursor
), -EINVAL
);
1067 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
1068 return -EADDRNOTAVAIL
;
1070 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
1075 _cleanup_free_
char *item
= NULL
;
1076 unsigned long long ll
;
1080 r
= extract_first_word(&cursor
, &item
, ";", EXTRACT_DONT_COALESCE_SEPARATORS
);
1087 if (strlen(item
) < 2 || item
[1] != '=')
1093 k
= sd_id128_from_string(item
+2, &id
);
1096 if (!sd_id128_equal(id
, j
->current_file
->header
->seqnum_id
))
1101 if (sscanf(item
+2, "%llx", &ll
) != 1)
1103 if (ll
!= le64toh(o
->entry
.seqnum
))
1108 k
= sd_id128_from_string(item
+2, &id
);
1111 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1116 if (sscanf(item
+2, "%llx", &ll
) != 1)
1118 if (ll
!= le64toh(o
->entry
.monotonic
))
1123 if (sscanf(item
+2, "%llx", &ll
) != 1)
1125 if (ll
!= le64toh(o
->entry
.realtime
))
1130 if (sscanf(item
+2, "%llx", &ll
) != 1)
1132 if (ll
!= le64toh(o
->entry
.xor_hash
))
1142 _public_
int sd_journal_seek_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t usec
) {
1143 assert_return(j
, -EINVAL
);
1144 assert_return(!journal_pid_changed(j
), -ECHILD
);
1147 j
->current_location
.type
= LOCATION_SEEK
;
1148 j
->current_location
.boot_id
= boot_id
;
1149 j
->current_location
.monotonic
= usec
;
1150 j
->current_location
.monotonic_set
= true;
1155 _public_
int sd_journal_seek_realtime_usec(sd_journal
*j
, uint64_t usec
) {
1156 assert_return(j
, -EINVAL
);
1157 assert_return(!journal_pid_changed(j
), -ECHILD
);
1160 j
->current_location
.type
= LOCATION_SEEK
;
1161 j
->current_location
.realtime
= usec
;
1162 j
->current_location
.realtime_set
= true;
1167 _public_
int sd_journal_seek_head(sd_journal
*j
) {
1168 assert_return(j
, -EINVAL
);
1169 assert_return(!journal_pid_changed(j
), -ECHILD
);
1172 j
->current_location
.type
= LOCATION_HEAD
;
1177 _public_
int sd_journal_seek_tail(sd_journal
*j
) {
1178 assert_return(j
, -EINVAL
);
1179 assert_return(!journal_pid_changed(j
), -ECHILD
);
1182 j
->current_location
.type
= LOCATION_TAIL
;
1187 static void check_network(sd_journal
*j
, int fd
) {
1195 if (fstatfs(fd
, &sfs
) < 0)
1199 F_TYPE_EQUAL(sfs
.f_type
, CIFS_MAGIC_NUMBER
) ||
1200 F_TYPE_EQUAL(sfs
.f_type
, CODA_SUPER_MAGIC
) ||
1201 F_TYPE_EQUAL(sfs
.f_type
, NCP_SUPER_MAGIC
) ||
1202 F_TYPE_EQUAL(sfs
.f_type
, NFS_SUPER_MAGIC
) ||
1203 F_TYPE_EQUAL(sfs
.f_type
, SMB_SUPER_MAGIC
);
1206 static bool file_has_type_prefix(const char *prefix
, const char *filename
) {
1207 const char *full
, *tilded
, *atted
;
1209 full
= strjoina(prefix
, ".journal");
1210 tilded
= strjoina(full
, "~");
1211 atted
= strjoina(prefix
, "@");
1213 return streq(filename
, full
) ||
1214 streq(filename
, tilded
) ||
1215 startswith(filename
, atted
);
1218 static bool file_type_wanted(int flags
, const char *filename
) {
1221 if (!endswith(filename
, ".journal") && !endswith(filename
, ".journal~"))
1224 /* no flags set → every type is OK */
1225 if (!(flags
& (SD_JOURNAL_SYSTEM
| SD_JOURNAL_CURRENT_USER
)))
1228 if (flags
& SD_JOURNAL_SYSTEM
&& file_has_type_prefix("system", filename
))
1231 if (flags
& SD_JOURNAL_CURRENT_USER
) {
1232 char prefix
[5 + DECIMAL_STR_MAX(uid_t
) + 1];
1234 xsprintf(prefix
, "user-"UID_FMT
, getuid());
1236 if (file_has_type_prefix(prefix
, filename
))
1243 static bool path_has_prefix(sd_journal
*j
, const char *path
, const char *prefix
) {
1248 if (j
->toplevel_fd
>= 0)
1251 return path_startswith(path
, prefix
);
1254 static const char *skip_slash(const char *p
) {
1265 static int add_any_file(sd_journal
*j
, int fd
, const char *path
) {
1266 JournalFile
*f
= NULL
;
1267 bool close_fd
= false;
1271 assert(fd
>= 0 || path
);
1273 if (path
&& ordered_hashmap_get(j
->files
, path
))
1276 if (ordered_hashmap_size(j
->files
) >= JOURNAL_FILES_MAX
) {
1277 log_debug("Too many open journal files, not adding %s.", path
);
1282 if (fd
< 0 && j
->toplevel_fd
>= 0) {
1284 /* If there's a top-level fd defined, open the file relative to this now. (Make the path relative,
1285 * explicitly, since otherwise openat() ignores the first argument.) */
1287 fd
= openat(j
->toplevel_fd
, skip_slash(path
), O_RDONLY
|O_CLOEXEC
);
1289 r
= log_debug_errno(errno
, "Failed to open journal file %s: %m", path
);
1296 r
= journal_file_open(fd
, path
, O_RDONLY
, 0, false, false, NULL
, j
->mmap
, NULL
, NULL
, &f
);
1300 log_debug_errno(r
, "Failed to open journal file %s: %m", path
);
1304 /* journal_file_dump(f); */
1306 r
= ordered_hashmap_put(j
->files
, f
->path
, f
);
1308 f
->close_fd
= close_fd
;
1309 (void) journal_file_close(f
);
1313 if (!j
->has_runtime_files
&& path_has_prefix(j
, f
->path
, "/run"))
1314 j
->has_runtime_files
= true;
1315 else if (!j
->has_persistent_files
&& path_has_prefix(j
, f
->path
, "/var"))
1316 j
->has_persistent_files
= true;
1318 log_debug("File %s added.", f
->path
);
1320 check_network(j
, f
->fd
);
1322 j
->current_invalidate_counter
++;
1327 k
= journal_put_error(j
, r
, path
);
1334 static int add_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1341 if (j
->no_new_files
)
1344 if (!file_type_wanted(j
->flags
, filename
))
1347 path
= strjoina(prefix
, "/", filename
);
1348 return add_any_file(j
, -1, path
);
1351 static void remove_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1359 path
= strjoina(prefix
, "/", filename
);
1360 f
= ordered_hashmap_get(j
->files
, path
);
1364 remove_file_real(j
, f
);
1367 static void remove_file_real(sd_journal
*j
, JournalFile
*f
) {
1371 ordered_hashmap_remove(j
->files
, f
->path
);
1373 log_debug("File %s removed.", f
->path
);
1375 if (j
->current_file
== f
) {
1376 j
->current_file
= NULL
;
1377 j
->current_field
= 0;
1380 if (j
->unique_file
== f
) {
1381 /* Jump to the next unique_file or NULL if that one was last */
1382 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
1383 j
->unique_offset
= 0;
1384 if (!j
->unique_file
)
1385 j
->unique_file_lost
= true;
1388 if (j
->fields_file
== f
) {
1389 j
->fields_file
= ordered_hashmap_next(j
->files
, j
->fields_file
->path
);
1390 j
->fields_offset
= 0;
1391 if (!j
->fields_file
)
1392 j
->fields_file_lost
= true;
1395 (void) journal_file_close(f
);
1397 j
->current_invalidate_counter
++;
1400 static int dirname_is_machine_id(const char *fn
) {
1401 sd_id128_t id
, machine
;
1404 r
= sd_id128_get_machine(&machine
);
1408 r
= sd_id128_from_string(fn
, &id
);
1412 return sd_id128_equal(id
, machine
);
1415 static int add_directory(sd_journal
*j
, const char *prefix
, const char *dirname
) {
1416 _cleanup_free_
char *path
= NULL
;
1417 _cleanup_closedir_
DIR *d
= NULL
;
1418 struct dirent
*de
= NULL
;
1425 /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
1426 * and reenumerates directory contents */
1429 path
= strjoin(prefix
, "/", dirname
);
1431 path
= strdup(prefix
);
1437 log_debug("Considering directory %s.", path
);
1439 /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
1440 if ((j
->flags
& SD_JOURNAL_LOCAL_ONLY
) &&
1441 !((dirname
&& dirname_is_machine_id(dirname
) > 0) || path_has_prefix(j
, path
, "/run")))
1445 if (j
->toplevel_fd
< 0)
1448 /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
1449 * relative, by dropping the initial slash */
1450 d
= xopendirat(j
->toplevel_fd
, skip_slash(path
), 0);
1452 r
= log_debug_errno(errno
, "Failed to open directory %s: %m", path
);
1456 m
= hashmap_get(j
->directories_by_path
, path
);
1458 m
= new0(Directory
, 1);
1467 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1473 path
= NULL
; /* avoid freeing in cleanup */
1474 j
->current_invalidate_counter
++;
1476 log_debug("Directory %s added.", m
->path
);
1478 } else if (m
->is_root
)
1481 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1482 /* Watch this directory, if it not being watched yet. */
1484 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1485 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1486 IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
|IN_MOVED_FROM
|
1489 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1490 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1493 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
1495 if (dirent_is_file_with_suffix(de
, ".journal") ||
1496 dirent_is_file_with_suffix(de
, ".journal~"))
1497 (void) add_file(j
, m
->path
, de
->d_name
);
1500 check_network(j
, dirfd(d
));
1505 k
= journal_put_error(j
, r
, path
?: prefix
);
1512 static int add_root_directory(sd_journal
*j
, const char *p
, bool missing_ok
) {
1514 _cleanup_closedir_
DIR *d
= NULL
;
1521 /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
1522 * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
1523 * populate the set, as well as to update it later. */
1526 /* If there's a path specified, use it. */
1528 if ((j
->flags
& SD_JOURNAL_RUNTIME_ONLY
) &&
1529 !path_has_prefix(j
, p
, "/run"))
1533 p
= strjoina(j
->prefix
, p
);
1535 if (j
->toplevel_fd
< 0)
1538 d
= xopendirat(j
->toplevel_fd
, skip_slash(p
), 0);
1541 if (errno
== ENOENT
&& missing_ok
)
1544 r
= log_debug_errno(errno
, "Failed to open root directory %s: %m", p
);
1550 /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
1551 * opendir() will take possession of the fd, and close it, which we don't want. */
1553 p
= "."; /* store this as "." in the directories hashmap */
1555 dfd
= fcntl(j
->toplevel_fd
, F_DUPFD_CLOEXEC
, 3);
1571 m
= hashmap_get(j
->directories_by_path
, p
);
1573 m
= new0(Directory
, 1);
1581 m
->path
= strdup(p
);
1588 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1595 j
->current_invalidate_counter
++;
1597 log_debug("Root directory %s added.", m
->path
);
1599 } else if (!m
->is_root
)
1602 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1604 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1605 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1608 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1609 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1612 if (j
->no_new_files
)
1615 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
1618 if (dirent_is_file_with_suffix(de
, ".journal") ||
1619 dirent_is_file_with_suffix(de
, ".journal~"))
1620 (void) add_file(j
, m
->path
, de
->d_name
);
1621 else if (IN_SET(de
->d_type
, DT_DIR
, DT_LNK
, DT_UNKNOWN
) &&
1622 sd_id128_from_string(de
->d_name
, &id
) >= 0)
1623 (void) add_directory(j
, m
->path
, de
->d_name
);
1626 check_network(j
, dirfd(d
));
1631 k
= journal_put_error(j
, r
, p
);
1638 static void remove_directory(sd_journal
*j
, Directory
*d
) {
1642 hashmap_remove(j
->directories_by_wd
, INT_TO_PTR(d
->wd
));
1644 if (j
->inotify_fd
>= 0)
1645 inotify_rm_watch(j
->inotify_fd
, d
->wd
);
1648 hashmap_remove(j
->directories_by_path
, d
->path
);
1651 log_debug("Root directory %s removed.", d
->path
);
1653 log_debug("Directory %s removed.", d
->path
);
1659 static int add_search_paths(sd_journal
*j
) {
1661 static const char search_paths
[] =
1662 "/run/log/journal\0"
1663 "/var/log/journal\0";
1668 /* We ignore most errors here, since the idea is to only open
1669 * what's actually accessible, and ignore the rest. */
1671 NULSTR_FOREACH(p
, search_paths
)
1672 (void) add_root_directory(j
, p
, true);
1674 if (!(j
->flags
& SD_JOURNAL_LOCAL_ONLY
))
1675 (void) add_root_directory(j
, "/var/log/journal/remote", true);
1680 static int add_current_paths(sd_journal
*j
) {
1685 assert(j
->no_new_files
);
1687 /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
1688 * treat them as fatal. */
1690 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1691 _cleanup_free_
char *dir
;
1694 dir
= dirname_malloc(f
->path
);
1698 r
= add_directory(j
, dir
, NULL
);
1706 static int allocate_inotify(sd_journal
*j
) {
1709 if (j
->inotify_fd
< 0) {
1710 j
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1711 if (j
->inotify_fd
< 0)
1715 return hashmap_ensure_allocated(&j
->directories_by_wd
, NULL
);
1718 static sd_journal
*journal_new(int flags
, const char *path
) {
1721 j
= new0(sd_journal
, 1);
1725 j
->original_pid
= getpid_cached();
1726 j
->toplevel_fd
= -1;
1729 j
->data_threshold
= DEFAULT_DATA_THRESHOLD
;
1738 if (flags
& SD_JOURNAL_OS_ROOT
)
1744 j
->files
= ordered_hashmap_new(&string_hash_ops
);
1748 j
->files_cache
= ordered_hashmap_iterated_cache_new(j
->files
);
1749 j
->directories_by_path
= hashmap_new(&string_hash_ops
);
1750 j
->mmap
= mmap_cache_new();
1751 if (!j
->files_cache
|| !j
->directories_by_path
|| !j
->mmap
)
1757 sd_journal_close(j
);
1761 #define OPEN_ALLOWED_FLAGS \
1762 (SD_JOURNAL_LOCAL_ONLY | \
1763 SD_JOURNAL_RUNTIME_ONLY | \
1764 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)
1766 _public_
int sd_journal_open(sd_journal
**ret
, int flags
) {
1770 assert_return(ret
, -EINVAL
);
1771 assert_return((flags
& ~OPEN_ALLOWED_FLAGS
) == 0, -EINVAL
);
1773 j
= journal_new(flags
, NULL
);
1777 r
= add_search_paths(j
);
1785 sd_journal_close(j
);
1790 #define OPEN_CONTAINER_ALLOWED_FLAGS \
1791 (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
1793 _public_
int sd_journal_open_container(sd_journal
**ret
, const char *machine
, int flags
) {
1794 _cleanup_free_
char *root
= NULL
, *class = NULL
;
1799 /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
1800 * combination with sd_journal_open_directory_fd(). */
1802 assert_return(machine
, -EINVAL
);
1803 assert_return(ret
, -EINVAL
);
1804 assert_return((flags
& ~OPEN_CONTAINER_ALLOWED_FLAGS
) == 0, -EINVAL
);
1805 assert_return(machine_name_is_valid(machine
), -EINVAL
);
1807 p
= strjoina("/run/systemd/machines/", machine
);
1808 r
= parse_env_file(p
, NEWLINE
, "ROOT", &root
, "CLASS", &class, NULL
);
1816 if (!streq_ptr(class, "container"))
1819 j
= journal_new(flags
, root
);
1823 r
= add_search_paths(j
);
1831 sd_journal_close(j
);
1835 #define OPEN_DIRECTORY_ALLOWED_FLAGS \
1836 (SD_JOURNAL_OS_ROOT | \
1837 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1839 _public_
int sd_journal_open_directory(sd_journal
**ret
, const char *path
, int flags
) {
1843 assert_return(ret
, -EINVAL
);
1844 assert_return(path
, -EINVAL
);
1845 assert_return((flags
& ~OPEN_DIRECTORY_ALLOWED_FLAGS
) == 0, -EINVAL
);
1847 j
= journal_new(flags
, path
);
1851 if (flags
& SD_JOURNAL_OS_ROOT
)
1852 r
= add_search_paths(j
);
1854 r
= add_root_directory(j
, path
, false);
1862 sd_journal_close(j
);
1866 _public_
int sd_journal_open_files(sd_journal
**ret
, const char **paths
, int flags
) {
1871 assert_return(ret
, -EINVAL
);
1872 assert_return(flags
== 0, -EINVAL
);
1874 j
= journal_new(flags
, NULL
);
1878 STRV_FOREACH(path
, paths
) {
1879 r
= add_any_file(j
, -1, *path
);
1884 j
->no_new_files
= true;
1890 sd_journal_close(j
);
1894 #define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
1895 (SD_JOURNAL_OS_ROOT | \
1896 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1898 _public_
int sd_journal_open_directory_fd(sd_journal
**ret
, int fd
, int flags
) {
1903 assert_return(ret
, -EINVAL
);
1904 assert_return(fd
>= 0, -EBADF
);
1905 assert_return((flags
& ~OPEN_DIRECTORY_FD_ALLOWED_FLAGS
) == 0, -EINVAL
);
1907 if (fstat(fd
, &st
) < 0)
1910 if (!S_ISDIR(st
.st_mode
))
1913 j
= journal_new(flags
, NULL
);
1917 j
->toplevel_fd
= fd
;
1919 if (flags
& SD_JOURNAL_OS_ROOT
)
1920 r
= add_search_paths(j
);
1922 r
= add_root_directory(j
, NULL
, false);
1930 sd_journal_close(j
);
1934 _public_
int sd_journal_open_files_fd(sd_journal
**ret
, int fds
[], unsigned n_fds
, int flags
) {
1941 assert_return(ret
, -EINVAL
);
1942 assert_return(n_fds
> 0, -EBADF
);
1943 assert_return(flags
== 0, -EINVAL
);
1945 j
= journal_new(flags
, NULL
);
1949 for (i
= 0; i
< n_fds
; i
++) {
1957 if (fstat(fds
[i
], &st
) < 0) {
1962 if (!S_ISREG(st
.st_mode
)) {
1967 r
= add_any_file(j
, fds
[i
], NULL
);
1972 j
->no_new_files
= true;
1973 j
->no_inotify
= true;
1979 /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
1981 ORDERED_HASHMAP_FOREACH(f
, j
->files
, iterator
)
1982 f
->close_fd
= false;
1984 sd_journal_close(j
);
1988 _public_
void sd_journal_close(sd_journal
*j
) {
1994 sd_journal_flush_matches(j
);
1996 ordered_hashmap_free_with_destructor(j
->files
, journal_file_close
);
1997 iterated_cache_free(j
->files_cache
);
1999 while ((d
= hashmap_first(j
->directories_by_path
)))
2000 remove_directory(j
, d
);
2002 while ((d
= hashmap_first(j
->directories_by_wd
)))
2003 remove_directory(j
, d
);
2005 hashmap_free(j
->directories_by_path
);
2006 hashmap_free(j
->directories_by_wd
);
2008 safe_close(j
->inotify_fd
);
2011 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j
->mmap
), mmap_cache_get_missed(j
->mmap
));
2012 mmap_cache_unref(j
->mmap
);
2015 hashmap_free_free(j
->errors
);
2019 free(j
->unique_field
);
2020 free(j
->fields_buffer
);
2024 _public_
int sd_journal_get_realtime_usec(sd_journal
*j
, uint64_t *ret
) {
2029 assert_return(j
, -EINVAL
);
2030 assert_return(!journal_pid_changed(j
), -ECHILD
);
2031 assert_return(ret
, -EINVAL
);
2033 f
= j
->current_file
;
2035 return -EADDRNOTAVAIL
;
2037 if (f
->current_offset
<= 0)
2038 return -EADDRNOTAVAIL
;
2040 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2044 *ret
= le64toh(o
->entry
.realtime
);
2048 _public_
int sd_journal_get_monotonic_usec(sd_journal
*j
, uint64_t *ret
, sd_id128_t
*ret_boot_id
) {
2054 assert_return(j
, -EINVAL
);
2055 assert_return(!journal_pid_changed(j
), -ECHILD
);
2057 f
= j
->current_file
;
2059 return -EADDRNOTAVAIL
;
2061 if (f
->current_offset
<= 0)
2062 return -EADDRNOTAVAIL
;
2064 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2069 *ret_boot_id
= o
->entry
.boot_id
;
2071 r
= sd_id128_get_boot(&id
);
2075 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
2080 *ret
= le64toh(o
->entry
.monotonic
);
2085 static bool field_is_valid(const char *field
) {
2093 if (startswith(field
, "__"))
2096 for (p
= field
; *p
; p
++) {
2101 if (*p
>= 'A' && *p
<= 'Z')
2104 if (*p
>= '0' && *p
<= '9')
2113 _public_
int sd_journal_get_data(sd_journal
*j
, const char *field
, const void **data
, size_t *size
) {
2116 size_t field_length
;
2120 assert_return(j
, -EINVAL
);
2121 assert_return(!journal_pid_changed(j
), -ECHILD
);
2122 assert_return(field
, -EINVAL
);
2123 assert_return(data
, -EINVAL
);
2124 assert_return(size
, -EINVAL
);
2125 assert_return(field_is_valid(field
), -EINVAL
);
2127 f
= j
->current_file
;
2129 return -EADDRNOTAVAIL
;
2131 if (f
->current_offset
<= 0)
2132 return -EADDRNOTAVAIL
;
2134 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2138 field_length
= strlen(field
);
2140 n
= journal_file_entry_n_items(o
);
2141 for (i
= 0; i
< n
; i
++) {
2147 p
= le64toh(o
->entry
.items
[i
].object_offset
);
2148 le_hash
= o
->entry
.items
[i
].hash
;
2149 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2153 if (le_hash
!= o
->data
.hash
)
2156 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2158 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2160 #if HAVE_XZ || HAVE_LZ4
2161 r
= decompress_startswith(compression
,
2163 &f
->compress_buffer
, &f
->compress_buffer_size
,
2164 field
, field_length
, '=');
2166 log_debug_errno(r
, "Cannot decompress %s object of length %"PRIu64
" at offset "OFSfmt
": %m",
2167 object_compressed_to_string(compression
), l
, p
);
2172 r
= decompress_blob(compression
,
2174 &f
->compress_buffer
, &f
->compress_buffer_size
, &rsize
,
2179 *data
= f
->compress_buffer
;
2180 *size
= (size_t) rsize
;
2185 return -EPROTONOSUPPORT
;
2187 } else if (l
>= field_length
+1 &&
2188 memcmp(o
->data
.payload
, field
, field_length
) == 0 &&
2189 o
->data
.payload
[field_length
] == '=') {
2193 if ((uint64_t) t
!= l
)
2196 *data
= o
->data
.payload
;
2202 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2210 static int return_data(sd_journal
*j
, JournalFile
*f
, Object
*o
, const void **data
, size_t *size
) {
2215 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2218 /* We can't read objects larger than 4G on a 32bit machine */
2219 if ((uint64_t) t
!= l
)
2222 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2224 #if HAVE_XZ || HAVE_LZ4
2228 r
= decompress_blob(compression
,
2229 o
->data
.payload
, l
, &f
->compress_buffer
,
2230 &f
->compress_buffer_size
, &rsize
, j
->data_threshold
);
2234 *data
= f
->compress_buffer
;
2235 *size
= (size_t) rsize
;
2237 return -EPROTONOSUPPORT
;
2240 *data
= o
->data
.payload
;
2247 _public_
int sd_journal_enumerate_data(sd_journal
*j
, const void **data
, size_t *size
) {
2254 assert_return(j
, -EINVAL
);
2255 assert_return(!journal_pid_changed(j
), -ECHILD
);
2256 assert_return(data
, -EINVAL
);
2257 assert_return(size
, -EINVAL
);
2259 f
= j
->current_file
;
2261 return -EADDRNOTAVAIL
;
2263 if (f
->current_offset
<= 0)
2264 return -EADDRNOTAVAIL
;
2266 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2270 n
= journal_file_entry_n_items(o
);
2271 if (j
->current_field
>= n
)
2274 p
= le64toh(o
->entry
.items
[j
->current_field
].object_offset
);
2275 le_hash
= o
->entry
.items
[j
->current_field
].hash
;
2276 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2280 if (le_hash
!= o
->data
.hash
)
2283 r
= return_data(j
, f
, o
, data
, size
);
2292 _public_
void sd_journal_restart_data(sd_journal
*j
) {
2296 j
->current_field
= 0;
2299 _public_
int sd_journal_get_fd(sd_journal
*j
) {
2302 assert_return(j
, -EINVAL
);
2303 assert_return(!journal_pid_changed(j
), -ECHILD
);
2306 return -EMEDIUMTYPE
;
2308 if (j
->inotify_fd
>= 0)
2309 return j
->inotify_fd
;
2311 r
= allocate_inotify(j
);
2315 log_debug("Reiterating files to get inotify watches established");
2317 /* Iterate through all dirs again, to add them to the
2319 if (j
->no_new_files
)
2320 r
= add_current_paths(j
);
2321 else if (j
->flags
& SD_JOURNAL_OS_ROOT
)
2322 r
= add_search_paths(j
);
2323 else if (j
->toplevel_fd
>= 0)
2324 r
= add_root_directory(j
, NULL
, false);
2326 r
= add_root_directory(j
, j
->path
, true);
2328 r
= add_search_paths(j
);
2332 return j
->inotify_fd
;
2335 _public_
int sd_journal_get_events(sd_journal
*j
) {
2338 assert_return(j
, -EINVAL
);
2339 assert_return(!journal_pid_changed(j
), -ECHILD
);
2341 fd
= sd_journal_get_fd(j
);
2348 _public_
int sd_journal_get_timeout(sd_journal
*j
, uint64_t *timeout_usec
) {
2351 assert_return(j
, -EINVAL
);
2352 assert_return(!journal_pid_changed(j
), -ECHILD
);
2353 assert_return(timeout_usec
, -EINVAL
);
2355 fd
= sd_journal_get_fd(j
);
2359 if (!j
->on_network
) {
2360 *timeout_usec
= (uint64_t) -1;
2364 /* If we are on the network we need to regularly check for
2365 * changes manually */
2367 *timeout_usec
= j
->last_process_usec
+ JOURNAL_FILES_RECHECK_USEC
;
2371 static void process_inotify_event(sd_journal
*j
, struct inotify_event
*e
) {
2377 /* Is this a subdirectory we watch? */
2378 d
= hashmap_get(j
->directories_by_wd
, INT_TO_PTR(e
->wd
));
2382 if (!(e
->mask
& IN_ISDIR
) && e
->len
> 0 &&
2383 (endswith(e
->name
, ".journal") ||
2384 endswith(e
->name
, ".journal~"))) {
2386 /* Event for a journal file */
2388 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2389 (void) add_file(j
, d
->path
, e
->name
);
2390 else if (e
->mask
& (IN_DELETE
|IN_MOVED_FROM
|IN_UNMOUNT
))
2391 remove_file(j
, d
->path
, e
->name
);
2393 } else if (!d
->is_root
&& e
->len
== 0) {
2395 /* Event for a subdirectory */
2397 if (e
->mask
& (IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
))
2398 remove_directory(j
, d
);
2400 } else if (d
->is_root
&& (e
->mask
& IN_ISDIR
) && e
->len
> 0 && sd_id128_from_string(e
->name
, &id
) >= 0) {
2402 /* Event for root directory */
2404 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2405 (void) add_directory(j
, d
->path
, e
->name
);
2411 if (e
->mask
& IN_IGNORED
)
2414 log_debug("Unknown inotify event.");
2417 static int determine_change(sd_journal
*j
) {
2422 b
= j
->current_invalidate_counter
!= j
->last_invalidate_counter
;
2423 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2425 return b
? SD_JOURNAL_INVALIDATE
: SD_JOURNAL_APPEND
;
2428 _public_
int sd_journal_process(sd_journal
*j
) {
2429 bool got_something
= false;
2431 assert_return(j
, -EINVAL
);
2432 assert_return(!journal_pid_changed(j
), -ECHILD
);
2434 j
->last_process_usec
= now(CLOCK_MONOTONIC
);
2435 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2438 union inotify_event_buffer buffer
;
2439 struct inotify_event
*e
;
2442 l
= read(j
->inotify_fd
, &buffer
, sizeof(buffer
));
2444 if (IN_SET(errno
, EAGAIN
, EINTR
))
2445 return got_something
? determine_change(j
) : SD_JOURNAL_NOP
;
2450 got_something
= true;
2452 FOREACH_INOTIFY_EVENT(e
, buffer
, l
)
2453 process_inotify_event(j
, e
);
2457 _public_
int sd_journal_wait(sd_journal
*j
, uint64_t timeout_usec
) {
2461 assert_return(j
, -EINVAL
);
2462 assert_return(!journal_pid_changed(j
), -ECHILD
);
2464 if (j
->inotify_fd
< 0) {
2466 /* This is the first invocation, hence create the
2468 r
= sd_journal_get_fd(j
);
2472 /* The journal might have changed since the context
2473 * object was created and we weren't watching before,
2474 * hence don't wait for anything, and return
2476 return determine_change(j
);
2479 r
= sd_journal_get_timeout(j
, &t
);
2483 if (t
!= (uint64_t) -1) {
2486 n
= now(CLOCK_MONOTONIC
);
2487 t
= t
> n
? t
- n
: 0;
2489 if (timeout_usec
== (uint64_t) -1 || timeout_usec
> t
)
2494 r
= fd_wait_for_event(j
->inotify_fd
, POLLIN
, timeout_usec
);
2495 } while (r
== -EINTR
);
2500 return sd_journal_process(j
);
2503 _public_
int sd_journal_get_cutoff_realtime_usec(sd_journal
*j
, uint64_t *from
, uint64_t *to
) {
2507 uint64_t fmin
= 0, tmax
= 0;
2510 assert_return(j
, -EINVAL
);
2511 assert_return(!journal_pid_changed(j
), -ECHILD
);
2512 assert_return(from
|| to
, -EINVAL
);
2513 assert_return(from
!= to
, -EINVAL
);
2515 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2518 r
= journal_file_get_cutoff_realtime_usec(f
, &fr
, &t
);
2531 fmin
= MIN(fr
, fmin
);
2532 tmax
= MAX(t
, tmax
);
2541 return first
? 0 : 1;
2544 _public_
int sd_journal_get_cutoff_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t *from
, uint64_t *to
) {
2550 assert_return(j
, -EINVAL
);
2551 assert_return(!journal_pid_changed(j
), -ECHILD
);
2552 assert_return(from
|| to
, -EINVAL
);
2553 assert_return(from
!= to
, -EINVAL
);
2555 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2558 r
= journal_file_get_cutoff_monotonic_usec(f
, boot_id
, &fr
, &t
);
2568 *from
= MIN(fr
, *from
);
2583 void journal_print_header(sd_journal
*j
) {
2586 bool newline
= false;
2590 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2596 journal_file_print_header(f
);
2600 _public_
int sd_journal_get_usage(sd_journal
*j
, uint64_t *bytes
) {
2605 assert_return(j
, -EINVAL
);
2606 assert_return(!journal_pid_changed(j
), -ECHILD
);
2607 assert_return(bytes
, -EINVAL
);
2609 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2612 if (fstat(f
->fd
, &st
) < 0)
2615 sum
+= (uint64_t) st
.st_blocks
* 512ULL;
2622 _public_
int sd_journal_query_unique(sd_journal
*j
, const char *field
) {
2625 assert_return(j
, -EINVAL
);
2626 assert_return(!journal_pid_changed(j
), -ECHILD
);
2627 assert_return(!isempty(field
), -EINVAL
);
2628 assert_return(field_is_valid(field
), -EINVAL
);
2634 free(j
->unique_field
);
2635 j
->unique_field
= f
;
2636 j
->unique_file
= NULL
;
2637 j
->unique_offset
= 0;
2638 j
->unique_file_lost
= false;
2643 _public_
int sd_journal_enumerate_unique(sd_journal
*j
, const void **data
, size_t *l
) {
2646 assert_return(j
, -EINVAL
);
2647 assert_return(!journal_pid_changed(j
), -ECHILD
);
2648 assert_return(data
, -EINVAL
);
2649 assert_return(l
, -EINVAL
);
2650 assert_return(j
->unique_field
, -EINVAL
);
2652 k
= strlen(j
->unique_field
);
2654 if (!j
->unique_file
) {
2655 if (j
->unique_file_lost
)
2658 j
->unique_file
= ordered_hashmap_first(j
->files
);
2659 if (!j
->unique_file
)
2662 j
->unique_offset
= 0;
2674 /* Proceed to next data object in the field's linked list */
2675 if (j
->unique_offset
== 0) {
2676 r
= journal_file_find_field_object(j
->unique_file
, j
->unique_field
, k
, &o
, NULL
);
2680 j
->unique_offset
= r
> 0 ? le64toh(o
->field
.head_data_offset
) : 0;
2682 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_DATA
, j
->unique_offset
, &o
);
2686 j
->unique_offset
= le64toh(o
->data
.next_field_offset
);
2689 /* We reached the end of the list? Then start again, with the next file */
2690 if (j
->unique_offset
== 0) {
2691 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
2692 if (!j
->unique_file
)
2698 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2699 * instead, so that we can look at this data object at the same
2700 * time as one on another file */
2701 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_UNUSED
, j
->unique_offset
, &o
);
2705 /* Let's do the type check by hand, since we used 0 context above. */
2706 if (o
->object
.type
!= OBJECT_DATA
) {
2707 log_debug("%s:offset " OFSfmt
": object has type %d, expected %d",
2708 j
->unique_file
->path
, j
->unique_offset
,
2709 o
->object
.type
, OBJECT_DATA
);
2713 r
= return_data(j
, j
->unique_file
, o
, &odata
, &ol
);
2717 /* Check if we have at least the field name and "=". */
2719 log_debug("%s:offset " OFSfmt
": object has size %zu, expected at least %zu",
2720 j
->unique_file
->path
, j
->unique_offset
,
2725 if (memcmp(odata
, j
->unique_field
, k
) || ((const char*) odata
)[k
] != '=') {
2726 log_debug("%s:offset " OFSfmt
": object does not start with \"%s=\"",
2727 j
->unique_file
->path
, j
->unique_offset
,
2732 /* OK, now let's see if we already returned this data
2733 * object by checking if it exists in the earlier
2734 * traversed files. */
2736 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2737 if (of
== j
->unique_file
)
2740 /* Skip this file it didn't have any fields indexed */
2741 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2744 r
= journal_file_find_data_object_with_hash(of
, odata
, ol
, le64toh(o
->data
.hash
), NULL
, NULL
);
2756 r
= return_data(j
, j
->unique_file
, o
, data
, l
);
2764 _public_
void sd_journal_restart_unique(sd_journal
*j
) {
2768 j
->unique_file
= NULL
;
2769 j
->unique_offset
= 0;
2770 j
->unique_file_lost
= false;
2773 _public_
int sd_journal_enumerate_fields(sd_journal
*j
, const char **field
) {
2776 assert_return(j
, -EINVAL
);
2777 assert_return(!journal_pid_changed(j
), -ECHILD
);
2778 assert_return(field
, -EINVAL
);
2780 if (!j
->fields_file
) {
2781 if (j
->fields_file_lost
)
2784 j
->fields_file
= ordered_hashmap_first(j
->files
);
2785 if (!j
->fields_file
)
2788 j
->fields_hash_table_index
= 0;
2789 j
->fields_offset
= 0;
2793 JournalFile
*f
, *of
;
2802 if (j
->fields_offset
== 0) {
2805 /* We are not yet positioned at any field. Let's pick the first one */
2806 r
= journal_file_map_field_hash_table(f
);
2810 m
= le64toh(f
->header
->field_hash_table_size
) / sizeof(HashItem
);
2812 if (j
->fields_hash_table_index
>= m
) {
2813 /* Reached the end of the hash table, go to the next file. */
2818 j
->fields_offset
= le64toh(f
->field_hash_table
[j
->fields_hash_table_index
].head_hash_offset
);
2820 if (j
->fields_offset
!= 0)
2823 /* Empty hash table bucket, go to next one */
2824 j
->fields_hash_table_index
++;
2828 /* Proceed with next file */
2829 j
->fields_file
= ordered_hashmap_next(j
->files
, f
->path
);
2830 if (!j
->fields_file
) {
2835 j
->fields_offset
= 0;
2836 j
->fields_hash_table_index
= 0;
2841 /* We are already positioned at a field. If so, let's figure out the next field from it */
2843 r
= journal_file_move_to_object(f
, OBJECT_FIELD
, j
->fields_offset
, &o
);
2847 j
->fields_offset
= le64toh(o
->field
.next_hash_offset
);
2848 if (j
->fields_offset
== 0) {
2849 /* Reached the end of the hash table chain */
2850 j
->fields_hash_table_index
++;
2855 /* We use OBJECT_UNUSED here, so that the iterator below doesn't remove our mmap window */
2856 r
= journal_file_move_to_object(f
, OBJECT_UNUSED
, j
->fields_offset
, &o
);
2860 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
2861 if (o
->object
.type
!= OBJECT_FIELD
) {
2862 log_debug("%s:offset " OFSfmt
": object has type %i, expected %i", f
->path
, j
->fields_offset
, o
->object
.type
, OBJECT_FIELD
);
2866 sz
= le64toh(o
->object
.size
) - offsetof(Object
, field
.payload
);
2868 /* Let's see if we already returned this field name before. */
2870 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2874 /* Skip this file it didn't have any fields indexed */
2875 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2878 r
= journal_file_find_field_object_with_hash(of
, o
->field
.payload
, sz
, le64toh(o
->field
.hash
), NULL
, NULL
);
2890 /* Check if this is really a valid string containing no NUL byte */
2891 if (memchr(o
->field
.payload
, 0, sz
))
2894 if (sz
> j
->data_threshold
)
2895 sz
= j
->data_threshold
;
2897 if (!GREEDY_REALLOC(j
->fields_buffer
, j
->fields_buffer_allocated
, sz
+ 1))
2900 memcpy(j
->fields_buffer
, o
->field
.payload
, sz
);
2901 j
->fields_buffer
[sz
] = 0;
2903 if (!field_is_valid(j
->fields_buffer
))
2906 *field
= j
->fields_buffer
;
2911 _public_
void sd_journal_restart_fields(sd_journal
*j
) {
2915 j
->fields_file
= NULL
;
2916 j
->fields_hash_table_index
= 0;
2917 j
->fields_offset
= 0;
2918 j
->fields_file_lost
= false;
2921 _public_
int sd_journal_reliable_fd(sd_journal
*j
) {
2922 assert_return(j
, -EINVAL
);
2923 assert_return(!journal_pid_changed(j
), -ECHILD
);
2925 return !j
->on_network
;
2928 static char *lookup_field(const char *field
, void *userdata
) {
2929 sd_journal
*j
= userdata
;
2937 r
= sd_journal_get_data(j
, field
, &data
, &size
);
2939 size
> REPLACE_VAR_MAX
)
2940 return strdup(field
);
2942 d
= strlen(field
) + 1;
2944 return strndup((const char*) data
+ d
, size
- d
);
2947 _public_
int sd_journal_get_catalog(sd_journal
*j
, char **ret
) {
2951 _cleanup_free_
char *text
= NULL
, *cid
= NULL
;
2955 assert_return(j
, -EINVAL
);
2956 assert_return(!journal_pid_changed(j
), -ECHILD
);
2957 assert_return(ret
, -EINVAL
);
2959 r
= sd_journal_get_data(j
, "MESSAGE_ID", &data
, &size
);
2963 cid
= strndup((const char*) data
+ 11, size
- 11);
2967 r
= sd_id128_from_string(cid
, &id
);
2971 r
= catalog_get(CATALOG_DATABASE
, id
, &text
);
2975 t
= replace_var(text
, lookup_field
, j
);
2983 _public_
int sd_journal_get_catalog_for_message_id(sd_id128_t id
, char **ret
) {
2984 assert_return(ret
, -EINVAL
);
2986 return catalog_get(CATALOG_DATABASE
, id
, ret
);
2989 _public_
int sd_journal_set_data_threshold(sd_journal
*j
, size_t sz
) {
2990 assert_return(j
, -EINVAL
);
2991 assert_return(!journal_pid_changed(j
), -ECHILD
);
2993 j
->data_threshold
= sz
;
2997 _public_
int sd_journal_get_data_threshold(sd_journal
*j
, size_t *sz
) {
2998 assert_return(j
, -EINVAL
);
2999 assert_return(!journal_pid_changed(j
), -ECHILD
);
3000 assert_return(sz
, -EINVAL
);
3002 *sz
= j
->data_threshold
;
3006 _public_
int sd_journal_has_runtime_files(sd_journal
*j
) {
3007 assert_return(j
, -EINVAL
);
3009 return j
->has_runtime_files
;
3012 _public_
int sd_journal_has_persistent_files(sd_journal
*j
) {
3013 assert_return(j
, -EINVAL
);
3015 return j
->has_persistent_files
;