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
*f
, *new_file
= NULL
;
827 assert_return(j
, -EINVAL
);
828 assert_return(!journal_pid_changed(j
), -ECHILD
);
830 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
833 r
= next_beyond_location(j
, f
, direction
);
835 log_debug_errno(r
, "Can't iterate through %s, ignoring: %m", f
->path
);
836 remove_file_real(j
, f
);
839 f
->location_type
= LOCATION_TAIL
;
848 k
= journal_file_compare_locations(f
, new_file
);
850 found
= direction
== DIRECTION_DOWN
? k
< 0 : k
> 0;
860 r
= journal_file_move_to_object(new_file
, OBJECT_ENTRY
, new_file
->current_offset
, &o
);
864 set_location(j
, new_file
, o
);
869 _public_
int sd_journal_next(sd_journal
*j
) {
870 return real_journal_next(j
, DIRECTION_DOWN
);
873 _public_
int sd_journal_previous(sd_journal
*j
) {
874 return real_journal_next(j
, DIRECTION_UP
);
877 static int real_journal_next_skip(sd_journal
*j
, direction_t direction
, uint64_t skip
) {
880 assert_return(j
, -EINVAL
);
881 assert_return(!journal_pid_changed(j
), -ECHILD
);
884 /* If this is not a discrete skip, then at least
885 * resolve the current location */
886 if (j
->current_location
.type
!= LOCATION_DISCRETE
) {
887 r
= real_journal_next(j
, direction
);
896 r
= real_journal_next(j
, direction
);
910 _public_
int sd_journal_next_skip(sd_journal
*j
, uint64_t skip
) {
911 return real_journal_next_skip(j
, DIRECTION_DOWN
, skip
);
914 _public_
int sd_journal_previous_skip(sd_journal
*j
, uint64_t skip
) {
915 return real_journal_next_skip(j
, DIRECTION_UP
, skip
);
918 _public_
int sd_journal_get_cursor(sd_journal
*j
, char **cursor
) {
921 char bid
[33], sid
[33];
923 assert_return(j
, -EINVAL
);
924 assert_return(!journal_pid_changed(j
), -ECHILD
);
925 assert_return(cursor
, -EINVAL
);
927 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
928 return -EADDRNOTAVAIL
;
930 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
934 sd_id128_to_string(j
->current_file
->header
->seqnum_id
, sid
);
935 sd_id128_to_string(o
->entry
.boot_id
, bid
);
938 "s=%s;i=%"PRIx64
";b=%s;m=%"PRIx64
";t=%"PRIx64
";x=%"PRIx64
,
939 sid
, le64toh(o
->entry
.seqnum
),
940 bid
, le64toh(o
->entry
.monotonic
),
941 le64toh(o
->entry
.realtime
),
942 le64toh(o
->entry
.xor_hash
)) < 0)
948 _public_
int sd_journal_seek_cursor(sd_journal
*j
, const char *cursor
) {
949 const char *word
, *state
;
951 unsigned long long seqnum
, monotonic
, realtime
, xor_hash
;
953 seqnum_id_set
= false,
956 monotonic_set
= false,
957 realtime_set
= false,
958 xor_hash_set
= false;
959 sd_id128_t seqnum_id
, boot_id
;
961 assert_return(j
, -EINVAL
);
962 assert_return(!journal_pid_changed(j
), -ECHILD
);
963 assert_return(!isempty(cursor
), -EINVAL
);
965 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
969 if (l
< 2 || word
[1] != '=')
972 item
= strndup(word
, l
);
979 seqnum_id_set
= true;
980 k
= sd_id128_from_string(item
+2, &seqnum_id
);
985 if (sscanf(item
+2, "%llx", &seqnum
) != 1)
991 k
= sd_id128_from_string(item
+2, &boot_id
);
995 monotonic_set
= true;
996 if (sscanf(item
+2, "%llx", &monotonic
) != 1)
1001 realtime_set
= true;
1002 if (sscanf(item
+2, "%llx", &realtime
) != 1)
1007 xor_hash_set
= true;
1008 if (sscanf(item
+2, "%llx", &xor_hash
) != 1)
1019 if ((!seqnum_set
|| !seqnum_id_set
) &&
1020 (!monotonic_set
|| !boot_id_set
) &&
1026 j
->current_location
.type
= LOCATION_SEEK
;
1029 j
->current_location
.realtime
= (uint64_t) realtime
;
1030 j
->current_location
.realtime_set
= true;
1033 if (seqnum_set
&& seqnum_id_set
) {
1034 j
->current_location
.seqnum
= (uint64_t) seqnum
;
1035 j
->current_location
.seqnum_id
= seqnum_id
;
1036 j
->current_location
.seqnum_set
= true;
1039 if (monotonic_set
&& boot_id_set
) {
1040 j
->current_location
.monotonic
= (uint64_t) monotonic
;
1041 j
->current_location
.boot_id
= boot_id
;
1042 j
->current_location
.monotonic_set
= true;
1046 j
->current_location
.xor_hash
= (uint64_t) xor_hash
;
1047 j
->current_location
.xor_hash_set
= true;
1053 _public_
int sd_journal_test_cursor(sd_journal
*j
, const char *cursor
) {
1057 assert_return(j
, -EINVAL
);
1058 assert_return(!journal_pid_changed(j
), -ECHILD
);
1059 assert_return(!isempty(cursor
), -EINVAL
);
1061 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
1062 return -EADDRNOTAVAIL
;
1064 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
1069 _cleanup_free_
char *item
= NULL
;
1070 unsigned long long ll
;
1074 r
= extract_first_word(&cursor
, &item
, ";", EXTRACT_DONT_COALESCE_SEPARATORS
);
1081 if (strlen(item
) < 2 || item
[1] != '=')
1087 k
= sd_id128_from_string(item
+2, &id
);
1090 if (!sd_id128_equal(id
, j
->current_file
->header
->seqnum_id
))
1095 if (sscanf(item
+2, "%llx", &ll
) != 1)
1097 if (ll
!= le64toh(o
->entry
.seqnum
))
1102 k
= sd_id128_from_string(item
+2, &id
);
1105 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1110 if (sscanf(item
+2, "%llx", &ll
) != 1)
1112 if (ll
!= le64toh(o
->entry
.monotonic
))
1117 if (sscanf(item
+2, "%llx", &ll
) != 1)
1119 if (ll
!= le64toh(o
->entry
.realtime
))
1124 if (sscanf(item
+2, "%llx", &ll
) != 1)
1126 if (ll
!= le64toh(o
->entry
.xor_hash
))
1136 _public_
int sd_journal_seek_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t usec
) {
1137 assert_return(j
, -EINVAL
);
1138 assert_return(!journal_pid_changed(j
), -ECHILD
);
1141 j
->current_location
.type
= LOCATION_SEEK
;
1142 j
->current_location
.boot_id
= boot_id
;
1143 j
->current_location
.monotonic
= usec
;
1144 j
->current_location
.monotonic_set
= true;
1149 _public_
int sd_journal_seek_realtime_usec(sd_journal
*j
, uint64_t usec
) {
1150 assert_return(j
, -EINVAL
);
1151 assert_return(!journal_pid_changed(j
), -ECHILD
);
1154 j
->current_location
.type
= LOCATION_SEEK
;
1155 j
->current_location
.realtime
= usec
;
1156 j
->current_location
.realtime_set
= true;
1161 _public_
int sd_journal_seek_head(sd_journal
*j
) {
1162 assert_return(j
, -EINVAL
);
1163 assert_return(!journal_pid_changed(j
), -ECHILD
);
1166 j
->current_location
.type
= LOCATION_HEAD
;
1171 _public_
int sd_journal_seek_tail(sd_journal
*j
) {
1172 assert_return(j
, -EINVAL
);
1173 assert_return(!journal_pid_changed(j
), -ECHILD
);
1176 j
->current_location
.type
= LOCATION_TAIL
;
1181 static void check_network(sd_journal
*j
, int fd
) {
1189 if (fstatfs(fd
, &sfs
) < 0)
1193 F_TYPE_EQUAL(sfs
.f_type
, CIFS_MAGIC_NUMBER
) ||
1194 F_TYPE_EQUAL(sfs
.f_type
, CODA_SUPER_MAGIC
) ||
1195 F_TYPE_EQUAL(sfs
.f_type
, NCP_SUPER_MAGIC
) ||
1196 F_TYPE_EQUAL(sfs
.f_type
, NFS_SUPER_MAGIC
) ||
1197 F_TYPE_EQUAL(sfs
.f_type
, SMB_SUPER_MAGIC
);
1200 static bool file_has_type_prefix(const char *prefix
, const char *filename
) {
1201 const char *full
, *tilded
, *atted
;
1203 full
= strjoina(prefix
, ".journal");
1204 tilded
= strjoina(full
, "~");
1205 atted
= strjoina(prefix
, "@");
1207 return streq(filename
, full
) ||
1208 streq(filename
, tilded
) ||
1209 startswith(filename
, atted
);
1212 static bool file_type_wanted(int flags
, const char *filename
) {
1215 if (!endswith(filename
, ".journal") && !endswith(filename
, ".journal~"))
1218 /* no flags set → every type is OK */
1219 if (!(flags
& (SD_JOURNAL_SYSTEM
| SD_JOURNAL_CURRENT_USER
)))
1222 if (flags
& SD_JOURNAL_SYSTEM
&& file_has_type_prefix("system", filename
))
1225 if (flags
& SD_JOURNAL_CURRENT_USER
) {
1226 char prefix
[5 + DECIMAL_STR_MAX(uid_t
) + 1];
1228 xsprintf(prefix
, "user-"UID_FMT
, getuid());
1230 if (file_has_type_prefix(prefix
, filename
))
1237 static bool path_has_prefix(sd_journal
*j
, const char *path
, const char *prefix
) {
1242 if (j
->toplevel_fd
>= 0)
1245 return path_startswith(path
, prefix
);
1248 static const char *skip_slash(const char *p
) {
1259 static int add_any_file(sd_journal
*j
, int fd
, const char *path
) {
1260 JournalFile
*f
= NULL
;
1261 bool close_fd
= false;
1265 assert(fd
>= 0 || path
);
1267 if (path
&& ordered_hashmap_get(j
->files
, path
))
1270 if (ordered_hashmap_size(j
->files
) >= JOURNAL_FILES_MAX
) {
1271 log_debug("Too many open journal files, not adding %s.", path
);
1276 if (fd
< 0 && j
->toplevel_fd
>= 0) {
1278 /* If there's a top-level fd defined, open the file relative to this now. (Make the path relative,
1279 * explicitly, since otherwise openat() ignores the first argument.) */
1281 fd
= openat(j
->toplevel_fd
, skip_slash(path
), O_RDONLY
|O_CLOEXEC
);
1283 r
= log_debug_errno(errno
, "Failed to open journal file %s: %m", path
);
1290 r
= journal_file_open(fd
, path
, O_RDONLY
, 0, false, false, NULL
, j
->mmap
, NULL
, NULL
, &f
);
1294 log_debug_errno(r
, "Failed to open journal file %s: %m", path
);
1298 /* journal_file_dump(f); */
1300 r
= ordered_hashmap_put(j
->files
, f
->path
, f
);
1302 f
->close_fd
= close_fd
;
1303 (void) journal_file_close(f
);
1307 if (!j
->has_runtime_files
&& path_has_prefix(j
, f
->path
, "/run"))
1308 j
->has_runtime_files
= true;
1309 else if (!j
->has_persistent_files
&& path_has_prefix(j
, f
->path
, "/var"))
1310 j
->has_persistent_files
= true;
1312 log_debug("File %s added.", f
->path
);
1314 check_network(j
, f
->fd
);
1316 j
->current_invalidate_counter
++;
1321 k
= journal_put_error(j
, r
, path
);
1328 static int add_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1335 if (j
->no_new_files
)
1338 if (!file_type_wanted(j
->flags
, filename
))
1341 path
= strjoina(prefix
, "/", filename
);
1342 return add_any_file(j
, -1, path
);
1345 static void remove_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1353 path
= strjoina(prefix
, "/", filename
);
1354 f
= ordered_hashmap_get(j
->files
, path
);
1358 remove_file_real(j
, f
);
1361 static void remove_file_real(sd_journal
*j
, JournalFile
*f
) {
1365 ordered_hashmap_remove(j
->files
, f
->path
);
1367 log_debug("File %s removed.", f
->path
);
1369 if (j
->current_file
== f
) {
1370 j
->current_file
= NULL
;
1371 j
->current_field
= 0;
1374 if (j
->unique_file
== f
) {
1375 /* Jump to the next unique_file or NULL if that one was last */
1376 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
1377 j
->unique_offset
= 0;
1378 if (!j
->unique_file
)
1379 j
->unique_file_lost
= true;
1382 if (j
->fields_file
== f
) {
1383 j
->fields_file
= ordered_hashmap_next(j
->files
, j
->fields_file
->path
);
1384 j
->fields_offset
= 0;
1385 if (!j
->fields_file
)
1386 j
->fields_file_lost
= true;
1389 (void) journal_file_close(f
);
1391 j
->current_invalidate_counter
++;
1394 static int dirname_is_machine_id(const char *fn
) {
1395 sd_id128_t id
, machine
;
1398 r
= sd_id128_get_machine(&machine
);
1402 r
= sd_id128_from_string(fn
, &id
);
1406 return sd_id128_equal(id
, machine
);
1409 static int add_directory(sd_journal
*j
, const char *prefix
, const char *dirname
) {
1410 _cleanup_free_
char *path
= NULL
;
1411 _cleanup_closedir_
DIR *d
= NULL
;
1412 struct dirent
*de
= NULL
;
1419 /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
1420 * and reenumerates directory contents */
1423 path
= strjoin(prefix
, "/", dirname
);
1425 path
= strdup(prefix
);
1431 log_debug("Considering directory %s.", path
);
1433 /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
1434 if ((j
->flags
& SD_JOURNAL_LOCAL_ONLY
) &&
1435 !((dirname
&& dirname_is_machine_id(dirname
) > 0) || path_has_prefix(j
, path
, "/run")))
1439 if (j
->toplevel_fd
< 0)
1442 /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
1443 * relative, by dropping the initial slash */
1444 d
= xopendirat(j
->toplevel_fd
, skip_slash(path
), 0);
1446 r
= log_debug_errno(errno
, "Failed to open directory %s: %m", path
);
1450 m
= hashmap_get(j
->directories_by_path
, path
);
1452 m
= new0(Directory
, 1);
1461 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1467 path
= NULL
; /* avoid freeing in cleanup */
1468 j
->current_invalidate_counter
++;
1470 log_debug("Directory %s added.", m
->path
);
1472 } else if (m
->is_root
)
1475 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1476 /* Watch this directory, if it not being watched yet. */
1478 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1479 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1480 IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
|IN_MOVED_FROM
|
1483 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1484 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1487 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
1489 if (dirent_is_file_with_suffix(de
, ".journal") ||
1490 dirent_is_file_with_suffix(de
, ".journal~"))
1491 (void) add_file(j
, m
->path
, de
->d_name
);
1494 check_network(j
, dirfd(d
));
1499 k
= journal_put_error(j
, r
, path
?: prefix
);
1506 static int add_root_directory(sd_journal
*j
, const char *p
, bool missing_ok
) {
1508 _cleanup_closedir_
DIR *d
= NULL
;
1515 /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
1516 * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
1517 * populate the set, as well as to update it later. */
1520 /* If there's a path specified, use it. */
1522 if ((j
->flags
& SD_JOURNAL_RUNTIME_ONLY
) &&
1523 !path_has_prefix(j
, p
, "/run"))
1527 p
= strjoina(j
->prefix
, p
);
1529 if (j
->toplevel_fd
< 0)
1532 d
= xopendirat(j
->toplevel_fd
, skip_slash(p
), 0);
1535 if (errno
== ENOENT
&& missing_ok
)
1538 r
= log_debug_errno(errno
, "Failed to open root directory %s: %m", p
);
1544 /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
1545 * opendir() will take possession of the fd, and close it, which we don't want. */
1547 p
= "."; /* store this as "." in the directories hashmap */
1549 dfd
= fcntl(j
->toplevel_fd
, F_DUPFD_CLOEXEC
, 3);
1565 m
= hashmap_get(j
->directories_by_path
, p
);
1567 m
= new0(Directory
, 1);
1575 m
->path
= strdup(p
);
1582 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1589 j
->current_invalidate_counter
++;
1591 log_debug("Root directory %s added.", m
->path
);
1593 } else if (!m
->is_root
)
1596 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1598 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1599 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1602 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1603 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1606 if (j
->no_new_files
)
1609 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
1612 if (dirent_is_file_with_suffix(de
, ".journal") ||
1613 dirent_is_file_with_suffix(de
, ".journal~"))
1614 (void) add_file(j
, m
->path
, de
->d_name
);
1615 else if (IN_SET(de
->d_type
, DT_DIR
, DT_LNK
, DT_UNKNOWN
) &&
1616 sd_id128_from_string(de
->d_name
, &id
) >= 0)
1617 (void) add_directory(j
, m
->path
, de
->d_name
);
1620 check_network(j
, dirfd(d
));
1625 k
= journal_put_error(j
, r
, p
);
1632 static void remove_directory(sd_journal
*j
, Directory
*d
) {
1636 hashmap_remove(j
->directories_by_wd
, INT_TO_PTR(d
->wd
));
1638 if (j
->inotify_fd
>= 0)
1639 inotify_rm_watch(j
->inotify_fd
, d
->wd
);
1642 hashmap_remove(j
->directories_by_path
, d
->path
);
1645 log_debug("Root directory %s removed.", d
->path
);
1647 log_debug("Directory %s removed.", d
->path
);
1653 static int add_search_paths(sd_journal
*j
) {
1655 static const char search_paths
[] =
1656 "/run/log/journal\0"
1657 "/var/log/journal\0";
1662 /* We ignore most errors here, since the idea is to only open
1663 * what's actually accessible, and ignore the rest. */
1665 NULSTR_FOREACH(p
, search_paths
)
1666 (void) add_root_directory(j
, p
, true);
1668 if (!(j
->flags
& SD_JOURNAL_LOCAL_ONLY
))
1669 (void) add_root_directory(j
, "/var/log/journal/remote", true);
1674 static int add_current_paths(sd_journal
*j
) {
1679 assert(j
->no_new_files
);
1681 /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
1682 * treat them as fatal. */
1684 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1685 _cleanup_free_
char *dir
;
1688 dir
= dirname_malloc(f
->path
);
1692 r
= add_directory(j
, dir
, NULL
);
1700 static int allocate_inotify(sd_journal
*j
) {
1703 if (j
->inotify_fd
< 0) {
1704 j
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1705 if (j
->inotify_fd
< 0)
1709 return hashmap_ensure_allocated(&j
->directories_by_wd
, NULL
);
1712 static sd_journal
*journal_new(int flags
, const char *path
) {
1715 j
= new0(sd_journal
, 1);
1719 j
->original_pid
= getpid_cached();
1720 j
->toplevel_fd
= -1;
1723 j
->data_threshold
= DEFAULT_DATA_THRESHOLD
;
1732 if (flags
& SD_JOURNAL_OS_ROOT
)
1738 j
->files
= ordered_hashmap_new(&string_hash_ops
);
1739 j
->directories_by_path
= hashmap_new(&string_hash_ops
);
1740 j
->mmap
= mmap_cache_new();
1741 if (!j
->files
|| !j
->directories_by_path
|| !j
->mmap
)
1747 sd_journal_close(j
);
1751 #define OPEN_ALLOWED_FLAGS \
1752 (SD_JOURNAL_LOCAL_ONLY | \
1753 SD_JOURNAL_RUNTIME_ONLY | \
1754 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)
1756 _public_
int sd_journal_open(sd_journal
**ret
, int flags
) {
1760 assert_return(ret
, -EINVAL
);
1761 assert_return((flags
& ~OPEN_ALLOWED_FLAGS
) == 0, -EINVAL
);
1763 j
= journal_new(flags
, NULL
);
1767 r
= add_search_paths(j
);
1775 sd_journal_close(j
);
1780 #define OPEN_CONTAINER_ALLOWED_FLAGS \
1781 (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
1783 _public_
int sd_journal_open_container(sd_journal
**ret
, const char *machine
, int flags
) {
1784 _cleanup_free_
char *root
= NULL
, *class = NULL
;
1789 /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
1790 * combination with sd_journal_open_directory_fd(). */
1792 assert_return(machine
, -EINVAL
);
1793 assert_return(ret
, -EINVAL
);
1794 assert_return((flags
& ~OPEN_CONTAINER_ALLOWED_FLAGS
) == 0, -EINVAL
);
1795 assert_return(machine_name_is_valid(machine
), -EINVAL
);
1797 p
= strjoina("/run/systemd/machines/", machine
);
1798 r
= parse_env_file(p
, NEWLINE
, "ROOT", &root
, "CLASS", &class, NULL
);
1806 if (!streq_ptr(class, "container"))
1809 j
= journal_new(flags
, root
);
1813 r
= add_search_paths(j
);
1821 sd_journal_close(j
);
1825 #define OPEN_DIRECTORY_ALLOWED_FLAGS \
1826 (SD_JOURNAL_OS_ROOT | \
1827 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1829 _public_
int sd_journal_open_directory(sd_journal
**ret
, const char *path
, int flags
) {
1833 assert_return(ret
, -EINVAL
);
1834 assert_return(path
, -EINVAL
);
1835 assert_return((flags
& ~OPEN_DIRECTORY_ALLOWED_FLAGS
) == 0, -EINVAL
);
1837 j
= journal_new(flags
, path
);
1841 if (flags
& SD_JOURNAL_OS_ROOT
)
1842 r
= add_search_paths(j
);
1844 r
= add_root_directory(j
, path
, false);
1852 sd_journal_close(j
);
1856 _public_
int sd_journal_open_files(sd_journal
**ret
, const char **paths
, int flags
) {
1861 assert_return(ret
, -EINVAL
);
1862 assert_return(flags
== 0, -EINVAL
);
1864 j
= journal_new(flags
, NULL
);
1868 STRV_FOREACH(path
, paths
) {
1869 r
= add_any_file(j
, -1, *path
);
1874 j
->no_new_files
= true;
1880 sd_journal_close(j
);
1884 #define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
1885 (SD_JOURNAL_OS_ROOT | \
1886 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1888 _public_
int sd_journal_open_directory_fd(sd_journal
**ret
, int fd
, int flags
) {
1893 assert_return(ret
, -EINVAL
);
1894 assert_return(fd
>= 0, -EBADF
);
1895 assert_return((flags
& ~OPEN_DIRECTORY_FD_ALLOWED_FLAGS
) == 0, -EINVAL
);
1897 if (fstat(fd
, &st
) < 0)
1900 if (!S_ISDIR(st
.st_mode
))
1903 j
= journal_new(flags
, NULL
);
1907 j
->toplevel_fd
= fd
;
1909 if (flags
& SD_JOURNAL_OS_ROOT
)
1910 r
= add_search_paths(j
);
1912 r
= add_root_directory(j
, NULL
, false);
1920 sd_journal_close(j
);
1924 _public_
int sd_journal_open_files_fd(sd_journal
**ret
, int fds
[], unsigned n_fds
, int flags
) {
1931 assert_return(ret
, -EINVAL
);
1932 assert_return(n_fds
> 0, -EBADF
);
1933 assert_return(flags
== 0, -EINVAL
);
1935 j
= journal_new(flags
, NULL
);
1939 for (i
= 0; i
< n_fds
; i
++) {
1947 if (fstat(fds
[i
], &st
) < 0) {
1952 if (!S_ISREG(st
.st_mode
)) {
1957 r
= add_any_file(j
, fds
[i
], NULL
);
1962 j
->no_new_files
= true;
1963 j
->no_inotify
= true;
1969 /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
1971 ORDERED_HASHMAP_FOREACH(f
, j
->files
, iterator
)
1972 f
->close_fd
= false;
1974 sd_journal_close(j
);
1978 _public_
void sd_journal_close(sd_journal
*j
) {
1986 sd_journal_flush_matches(j
);
1988 while ((f
= ordered_hashmap_steal_first(j
->files
)))
1989 (void) journal_file_close(f
);
1991 ordered_hashmap_free(j
->files
);
1993 while ((d
= hashmap_first(j
->directories_by_path
)))
1994 remove_directory(j
, d
);
1996 while ((d
= hashmap_first(j
->directories_by_wd
)))
1997 remove_directory(j
, d
);
1999 hashmap_free(j
->directories_by_path
);
2000 hashmap_free(j
->directories_by_wd
);
2002 safe_close(j
->inotify_fd
);
2005 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j
->mmap
), mmap_cache_get_missed(j
->mmap
));
2006 mmap_cache_unref(j
->mmap
);
2009 while ((p
= hashmap_steal_first(j
->errors
)))
2011 hashmap_free(j
->errors
);
2015 free(j
->unique_field
);
2016 free(j
->fields_buffer
);
2020 _public_
int sd_journal_get_realtime_usec(sd_journal
*j
, uint64_t *ret
) {
2025 assert_return(j
, -EINVAL
);
2026 assert_return(!journal_pid_changed(j
), -ECHILD
);
2027 assert_return(ret
, -EINVAL
);
2029 f
= j
->current_file
;
2031 return -EADDRNOTAVAIL
;
2033 if (f
->current_offset
<= 0)
2034 return -EADDRNOTAVAIL
;
2036 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2040 *ret
= le64toh(o
->entry
.realtime
);
2044 _public_
int sd_journal_get_monotonic_usec(sd_journal
*j
, uint64_t *ret
, sd_id128_t
*ret_boot_id
) {
2050 assert_return(j
, -EINVAL
);
2051 assert_return(!journal_pid_changed(j
), -ECHILD
);
2053 f
= j
->current_file
;
2055 return -EADDRNOTAVAIL
;
2057 if (f
->current_offset
<= 0)
2058 return -EADDRNOTAVAIL
;
2060 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2065 *ret_boot_id
= o
->entry
.boot_id
;
2067 r
= sd_id128_get_boot(&id
);
2071 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
2076 *ret
= le64toh(o
->entry
.monotonic
);
2081 static bool field_is_valid(const char *field
) {
2089 if (startswith(field
, "__"))
2092 for (p
= field
; *p
; p
++) {
2097 if (*p
>= 'A' && *p
<= 'Z')
2100 if (*p
>= '0' && *p
<= '9')
2109 _public_
int sd_journal_get_data(sd_journal
*j
, const char *field
, const void **data
, size_t *size
) {
2112 size_t field_length
;
2116 assert_return(j
, -EINVAL
);
2117 assert_return(!journal_pid_changed(j
), -ECHILD
);
2118 assert_return(field
, -EINVAL
);
2119 assert_return(data
, -EINVAL
);
2120 assert_return(size
, -EINVAL
);
2121 assert_return(field_is_valid(field
), -EINVAL
);
2123 f
= j
->current_file
;
2125 return -EADDRNOTAVAIL
;
2127 if (f
->current_offset
<= 0)
2128 return -EADDRNOTAVAIL
;
2130 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2134 field_length
= strlen(field
);
2136 n
= journal_file_entry_n_items(o
);
2137 for (i
= 0; i
< n
; i
++) {
2143 p
= le64toh(o
->entry
.items
[i
].object_offset
);
2144 le_hash
= o
->entry
.items
[i
].hash
;
2145 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2149 if (le_hash
!= o
->data
.hash
)
2152 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2154 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2156 #if HAVE_XZ || HAVE_LZ4
2157 r
= decompress_startswith(compression
,
2159 &f
->compress_buffer
, &f
->compress_buffer_size
,
2160 field
, field_length
, '=');
2162 log_debug_errno(r
, "Cannot decompress %s object of length %"PRIu64
" at offset "OFSfmt
": %m",
2163 object_compressed_to_string(compression
), l
, p
);
2168 r
= decompress_blob(compression
,
2170 &f
->compress_buffer
, &f
->compress_buffer_size
, &rsize
,
2175 *data
= f
->compress_buffer
;
2176 *size
= (size_t) rsize
;
2181 return -EPROTONOSUPPORT
;
2183 } else if (l
>= field_length
+1 &&
2184 memcmp(o
->data
.payload
, field
, field_length
) == 0 &&
2185 o
->data
.payload
[field_length
] == '=') {
2189 if ((uint64_t) t
!= l
)
2192 *data
= o
->data
.payload
;
2198 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2206 static int return_data(sd_journal
*j
, JournalFile
*f
, Object
*o
, const void **data
, size_t *size
) {
2211 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2214 /* We can't read objects larger than 4G on a 32bit machine */
2215 if ((uint64_t) t
!= l
)
2218 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2220 #if HAVE_XZ || HAVE_LZ4
2224 r
= decompress_blob(compression
,
2225 o
->data
.payload
, l
, &f
->compress_buffer
,
2226 &f
->compress_buffer_size
, &rsize
, j
->data_threshold
);
2230 *data
= f
->compress_buffer
;
2231 *size
= (size_t) rsize
;
2233 return -EPROTONOSUPPORT
;
2236 *data
= o
->data
.payload
;
2243 _public_
int sd_journal_enumerate_data(sd_journal
*j
, const void **data
, size_t *size
) {
2250 assert_return(j
, -EINVAL
);
2251 assert_return(!journal_pid_changed(j
), -ECHILD
);
2252 assert_return(data
, -EINVAL
);
2253 assert_return(size
, -EINVAL
);
2255 f
= j
->current_file
;
2257 return -EADDRNOTAVAIL
;
2259 if (f
->current_offset
<= 0)
2260 return -EADDRNOTAVAIL
;
2262 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2266 n
= journal_file_entry_n_items(o
);
2267 if (j
->current_field
>= n
)
2270 p
= le64toh(o
->entry
.items
[j
->current_field
].object_offset
);
2271 le_hash
= o
->entry
.items
[j
->current_field
].hash
;
2272 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2276 if (le_hash
!= o
->data
.hash
)
2279 r
= return_data(j
, f
, o
, data
, size
);
2288 _public_
void sd_journal_restart_data(sd_journal
*j
) {
2292 j
->current_field
= 0;
2295 _public_
int sd_journal_get_fd(sd_journal
*j
) {
2298 assert_return(j
, -EINVAL
);
2299 assert_return(!journal_pid_changed(j
), -ECHILD
);
2302 return -EMEDIUMTYPE
;
2304 if (j
->inotify_fd
>= 0)
2305 return j
->inotify_fd
;
2307 r
= allocate_inotify(j
);
2311 log_debug("Reiterating files to get inotify watches established");
2313 /* Iterate through all dirs again, to add them to the
2315 if (j
->no_new_files
)
2316 r
= add_current_paths(j
);
2317 else if (j
->flags
& SD_JOURNAL_OS_ROOT
)
2318 r
= add_search_paths(j
);
2319 else if (j
->toplevel_fd
>= 0)
2320 r
= add_root_directory(j
, NULL
, false);
2322 r
= add_root_directory(j
, j
->path
, true);
2324 r
= add_search_paths(j
);
2328 return j
->inotify_fd
;
2331 _public_
int sd_journal_get_events(sd_journal
*j
) {
2334 assert_return(j
, -EINVAL
);
2335 assert_return(!journal_pid_changed(j
), -ECHILD
);
2337 fd
= sd_journal_get_fd(j
);
2344 _public_
int sd_journal_get_timeout(sd_journal
*j
, uint64_t *timeout_usec
) {
2347 assert_return(j
, -EINVAL
);
2348 assert_return(!journal_pid_changed(j
), -ECHILD
);
2349 assert_return(timeout_usec
, -EINVAL
);
2351 fd
= sd_journal_get_fd(j
);
2355 if (!j
->on_network
) {
2356 *timeout_usec
= (uint64_t) -1;
2360 /* If we are on the network we need to regularly check for
2361 * changes manually */
2363 *timeout_usec
= j
->last_process_usec
+ JOURNAL_FILES_RECHECK_USEC
;
2367 static void process_inotify_event(sd_journal
*j
, struct inotify_event
*e
) {
2373 /* Is this a subdirectory we watch? */
2374 d
= hashmap_get(j
->directories_by_wd
, INT_TO_PTR(e
->wd
));
2378 if (!(e
->mask
& IN_ISDIR
) && e
->len
> 0 &&
2379 (endswith(e
->name
, ".journal") ||
2380 endswith(e
->name
, ".journal~"))) {
2382 /* Event for a journal file */
2384 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2385 (void) add_file(j
, d
->path
, e
->name
);
2386 else if (e
->mask
& (IN_DELETE
|IN_MOVED_FROM
|IN_UNMOUNT
))
2387 remove_file(j
, d
->path
, e
->name
);
2389 } else if (!d
->is_root
&& e
->len
== 0) {
2391 /* Event for a subdirectory */
2393 if (e
->mask
& (IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
))
2394 remove_directory(j
, d
);
2396 } else if (d
->is_root
&& (e
->mask
& IN_ISDIR
) && e
->len
> 0 && sd_id128_from_string(e
->name
, &id
) >= 0) {
2398 /* Event for root directory */
2400 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2401 (void) add_directory(j
, d
->path
, e
->name
);
2407 if (e
->mask
& IN_IGNORED
)
2410 log_debug("Unknown inotify event.");
2413 static int determine_change(sd_journal
*j
) {
2418 b
= j
->current_invalidate_counter
!= j
->last_invalidate_counter
;
2419 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2421 return b
? SD_JOURNAL_INVALIDATE
: SD_JOURNAL_APPEND
;
2424 _public_
int sd_journal_process(sd_journal
*j
) {
2425 bool got_something
= false;
2427 assert_return(j
, -EINVAL
);
2428 assert_return(!journal_pid_changed(j
), -ECHILD
);
2430 j
->last_process_usec
= now(CLOCK_MONOTONIC
);
2431 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2434 union inotify_event_buffer buffer
;
2435 struct inotify_event
*e
;
2438 l
= read(j
->inotify_fd
, &buffer
, sizeof(buffer
));
2440 if (IN_SET(errno
, EAGAIN
, EINTR
))
2441 return got_something
? determine_change(j
) : SD_JOURNAL_NOP
;
2446 got_something
= true;
2448 FOREACH_INOTIFY_EVENT(e
, buffer
, l
)
2449 process_inotify_event(j
, e
);
2453 _public_
int sd_journal_wait(sd_journal
*j
, uint64_t timeout_usec
) {
2457 assert_return(j
, -EINVAL
);
2458 assert_return(!journal_pid_changed(j
), -ECHILD
);
2460 if (j
->inotify_fd
< 0) {
2462 /* This is the first invocation, hence create the
2464 r
= sd_journal_get_fd(j
);
2468 /* The journal might have changed since the context
2469 * object was created and we weren't watching before,
2470 * hence don't wait for anything, and return
2472 return determine_change(j
);
2475 r
= sd_journal_get_timeout(j
, &t
);
2479 if (t
!= (uint64_t) -1) {
2482 n
= now(CLOCK_MONOTONIC
);
2483 t
= t
> n
? t
- n
: 0;
2485 if (timeout_usec
== (uint64_t) -1 || timeout_usec
> t
)
2490 r
= fd_wait_for_event(j
->inotify_fd
, POLLIN
, timeout_usec
);
2491 } while (r
== -EINTR
);
2496 return sd_journal_process(j
);
2499 _public_
int sd_journal_get_cutoff_realtime_usec(sd_journal
*j
, uint64_t *from
, uint64_t *to
) {
2503 uint64_t fmin
= 0, tmax
= 0;
2506 assert_return(j
, -EINVAL
);
2507 assert_return(!journal_pid_changed(j
), -ECHILD
);
2508 assert_return(from
|| to
, -EINVAL
);
2509 assert_return(from
!= to
, -EINVAL
);
2511 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2514 r
= journal_file_get_cutoff_realtime_usec(f
, &fr
, &t
);
2527 fmin
= MIN(fr
, fmin
);
2528 tmax
= MAX(t
, tmax
);
2537 return first
? 0 : 1;
2540 _public_
int sd_journal_get_cutoff_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t *from
, uint64_t *to
) {
2546 assert_return(j
, -EINVAL
);
2547 assert_return(!journal_pid_changed(j
), -ECHILD
);
2548 assert_return(from
|| to
, -EINVAL
);
2549 assert_return(from
!= to
, -EINVAL
);
2551 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2554 r
= journal_file_get_cutoff_monotonic_usec(f
, boot_id
, &fr
, &t
);
2564 *from
= MIN(fr
, *from
);
2579 void journal_print_header(sd_journal
*j
) {
2582 bool newline
= false;
2586 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2592 journal_file_print_header(f
);
2596 _public_
int sd_journal_get_usage(sd_journal
*j
, uint64_t *bytes
) {
2601 assert_return(j
, -EINVAL
);
2602 assert_return(!journal_pid_changed(j
), -ECHILD
);
2603 assert_return(bytes
, -EINVAL
);
2605 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2608 if (fstat(f
->fd
, &st
) < 0)
2611 sum
+= (uint64_t) st
.st_blocks
* 512ULL;
2618 _public_
int sd_journal_query_unique(sd_journal
*j
, const char *field
) {
2621 assert_return(j
, -EINVAL
);
2622 assert_return(!journal_pid_changed(j
), -ECHILD
);
2623 assert_return(!isempty(field
), -EINVAL
);
2624 assert_return(field_is_valid(field
), -EINVAL
);
2630 free(j
->unique_field
);
2631 j
->unique_field
= f
;
2632 j
->unique_file
= NULL
;
2633 j
->unique_offset
= 0;
2634 j
->unique_file_lost
= false;
2639 _public_
int sd_journal_enumerate_unique(sd_journal
*j
, const void **data
, size_t *l
) {
2642 assert_return(j
, -EINVAL
);
2643 assert_return(!journal_pid_changed(j
), -ECHILD
);
2644 assert_return(data
, -EINVAL
);
2645 assert_return(l
, -EINVAL
);
2646 assert_return(j
->unique_field
, -EINVAL
);
2648 k
= strlen(j
->unique_field
);
2650 if (!j
->unique_file
) {
2651 if (j
->unique_file_lost
)
2654 j
->unique_file
= ordered_hashmap_first(j
->files
);
2655 if (!j
->unique_file
)
2658 j
->unique_offset
= 0;
2670 /* Proceed to next data object in the field's linked list */
2671 if (j
->unique_offset
== 0) {
2672 r
= journal_file_find_field_object(j
->unique_file
, j
->unique_field
, k
, &o
, NULL
);
2676 j
->unique_offset
= r
> 0 ? le64toh(o
->field
.head_data_offset
) : 0;
2678 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_DATA
, j
->unique_offset
, &o
);
2682 j
->unique_offset
= le64toh(o
->data
.next_field_offset
);
2685 /* We reached the end of the list? Then start again, with the next file */
2686 if (j
->unique_offset
== 0) {
2687 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
2688 if (!j
->unique_file
)
2694 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2695 * instead, so that we can look at this data object at the same
2696 * time as one on another file */
2697 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_UNUSED
, j
->unique_offset
, &o
);
2701 /* Let's do the type check by hand, since we used 0 context above. */
2702 if (o
->object
.type
!= OBJECT_DATA
) {
2703 log_debug("%s:offset " OFSfmt
": object has type %d, expected %d",
2704 j
->unique_file
->path
, j
->unique_offset
,
2705 o
->object
.type
, OBJECT_DATA
);
2709 r
= return_data(j
, j
->unique_file
, o
, &odata
, &ol
);
2713 /* Check if we have at least the field name and "=". */
2715 log_debug("%s:offset " OFSfmt
": object has size %zu, expected at least %zu",
2716 j
->unique_file
->path
, j
->unique_offset
,
2721 if (memcmp(odata
, j
->unique_field
, k
) || ((const char*) odata
)[k
] != '=') {
2722 log_debug("%s:offset " OFSfmt
": object does not start with \"%s=\"",
2723 j
->unique_file
->path
, j
->unique_offset
,
2728 /* OK, now let's see if we already returned this data
2729 * object by checking if it exists in the earlier
2730 * traversed files. */
2732 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2733 if (of
== j
->unique_file
)
2736 /* Skip this file it didn't have any fields indexed */
2737 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2740 r
= journal_file_find_data_object_with_hash(of
, odata
, ol
, le64toh(o
->data
.hash
), NULL
, NULL
);
2752 r
= return_data(j
, j
->unique_file
, o
, data
, l
);
2760 _public_
void sd_journal_restart_unique(sd_journal
*j
) {
2764 j
->unique_file
= NULL
;
2765 j
->unique_offset
= 0;
2766 j
->unique_file_lost
= false;
2769 _public_
int sd_journal_enumerate_fields(sd_journal
*j
, const char **field
) {
2772 assert_return(j
, -EINVAL
);
2773 assert_return(!journal_pid_changed(j
), -ECHILD
);
2774 assert_return(field
, -EINVAL
);
2776 if (!j
->fields_file
) {
2777 if (j
->fields_file_lost
)
2780 j
->fields_file
= ordered_hashmap_first(j
->files
);
2781 if (!j
->fields_file
)
2784 j
->fields_hash_table_index
= 0;
2785 j
->fields_offset
= 0;
2789 JournalFile
*f
, *of
;
2798 if (j
->fields_offset
== 0) {
2801 /* We are not yet positioned at any field. Let's pick the first one */
2802 r
= journal_file_map_field_hash_table(f
);
2806 m
= le64toh(f
->header
->field_hash_table_size
) / sizeof(HashItem
);
2808 if (j
->fields_hash_table_index
>= m
) {
2809 /* Reached the end of the hash table, go to the next file. */
2814 j
->fields_offset
= le64toh(f
->field_hash_table
[j
->fields_hash_table_index
].head_hash_offset
);
2816 if (j
->fields_offset
!= 0)
2819 /* Empty hash table bucket, go to next one */
2820 j
->fields_hash_table_index
++;
2824 /* Proceed with next file */
2825 j
->fields_file
= ordered_hashmap_next(j
->files
, f
->path
);
2826 if (!j
->fields_file
) {
2831 j
->fields_offset
= 0;
2832 j
->fields_hash_table_index
= 0;
2837 /* We are already positioned at a field. If so, let's figure out the next field from it */
2839 r
= journal_file_move_to_object(f
, OBJECT_FIELD
, j
->fields_offset
, &o
);
2843 j
->fields_offset
= le64toh(o
->field
.next_hash_offset
);
2844 if (j
->fields_offset
== 0) {
2845 /* Reached the end of the hash table chain */
2846 j
->fields_hash_table_index
++;
2851 /* We use OBJECT_UNUSED here, so that the iterator below doesn't remove our mmap window */
2852 r
= journal_file_move_to_object(f
, OBJECT_UNUSED
, j
->fields_offset
, &o
);
2856 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
2857 if (o
->object
.type
!= OBJECT_FIELD
) {
2858 log_debug("%s:offset " OFSfmt
": object has type %i, expected %i", f
->path
, j
->fields_offset
, o
->object
.type
, OBJECT_FIELD
);
2862 sz
= le64toh(o
->object
.size
) - offsetof(Object
, field
.payload
);
2864 /* Let's see if we already returned this field name before. */
2866 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2870 /* Skip this file it didn't have any fields indexed */
2871 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2874 r
= journal_file_find_field_object_with_hash(of
, o
->field
.payload
, sz
, le64toh(o
->field
.hash
), NULL
, NULL
);
2886 /* Check if this is really a valid string containing no NUL byte */
2887 if (memchr(o
->field
.payload
, 0, sz
))
2890 if (sz
> j
->data_threshold
)
2891 sz
= j
->data_threshold
;
2893 if (!GREEDY_REALLOC(j
->fields_buffer
, j
->fields_buffer_allocated
, sz
+ 1))
2896 memcpy(j
->fields_buffer
, o
->field
.payload
, sz
);
2897 j
->fields_buffer
[sz
] = 0;
2899 if (!field_is_valid(j
->fields_buffer
))
2902 *field
= j
->fields_buffer
;
2907 _public_
void sd_journal_restart_fields(sd_journal
*j
) {
2911 j
->fields_file
= NULL
;
2912 j
->fields_hash_table_index
= 0;
2913 j
->fields_offset
= 0;
2914 j
->fields_file_lost
= false;
2917 _public_
int sd_journal_reliable_fd(sd_journal
*j
) {
2918 assert_return(j
, -EINVAL
);
2919 assert_return(!journal_pid_changed(j
), -ECHILD
);
2921 return !j
->on_network
;
2924 static char *lookup_field(const char *field
, void *userdata
) {
2925 sd_journal
*j
= userdata
;
2933 r
= sd_journal_get_data(j
, field
, &data
, &size
);
2935 size
> REPLACE_VAR_MAX
)
2936 return strdup(field
);
2938 d
= strlen(field
) + 1;
2940 return strndup((const char*) data
+ d
, size
- d
);
2943 _public_
int sd_journal_get_catalog(sd_journal
*j
, char **ret
) {
2947 _cleanup_free_
char *text
= NULL
, *cid
= NULL
;
2951 assert_return(j
, -EINVAL
);
2952 assert_return(!journal_pid_changed(j
), -ECHILD
);
2953 assert_return(ret
, -EINVAL
);
2955 r
= sd_journal_get_data(j
, "MESSAGE_ID", &data
, &size
);
2959 cid
= strndup((const char*) data
+ 11, size
- 11);
2963 r
= sd_id128_from_string(cid
, &id
);
2967 r
= catalog_get(CATALOG_DATABASE
, id
, &text
);
2971 t
= replace_var(text
, lookup_field
, j
);
2979 _public_
int sd_journal_get_catalog_for_message_id(sd_id128_t id
, char **ret
) {
2980 assert_return(ret
, -EINVAL
);
2982 return catalog_get(CATALOG_DATABASE
, id
, ret
);
2985 _public_
int sd_journal_set_data_threshold(sd_journal
*j
, size_t sz
) {
2986 assert_return(j
, -EINVAL
);
2987 assert_return(!journal_pid_changed(j
), -ECHILD
);
2989 j
->data_threshold
= sz
;
2993 _public_
int sd_journal_get_data_threshold(sd_journal
*j
, size_t *sz
) {
2994 assert_return(j
, -EINVAL
);
2995 assert_return(!journal_pid_changed(j
), -ECHILD
);
2996 assert_return(sz
, -EINVAL
);
2998 *sz
= j
->data_threshold
;
3002 _public_
int sd_journal_has_runtime_files(sd_journal
*j
) {
3003 assert_return(j
, -EINVAL
);
3005 return j
->has_runtime_files
;
3008 _public_
int sd_journal_has_persistent_files(sd_journal
*j
) {
3009 assert_return(j
, -EINVAL
);
3011 return j
->has_persistent_files
;