1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <linux/magic.h>
27 #include <sys/inotify.h>
31 #include "sd-journal.h"
33 #include "alloc-util.h"
36 #include "dirent-util.h"
39 #include "format-util.h"
42 #include "hostname-util.h"
44 #include "journal-def.h"
45 #include "journal-file.h"
46 #include "journal-internal.h"
50 #include "path-util.h"
51 #include "process-util.h"
52 #include "replace-var.h"
53 #include "stat-util.h"
54 #include "stdio-util.h"
55 #include "string-util.h"
58 #define JOURNAL_FILES_MAX 7168
60 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
62 #define REPLACE_VAR_MAX 256
64 #define DEFAULT_DATA_THRESHOLD (64*1024)
66 static void remove_file_real(sd_journal
*j
, JournalFile
*f
);
68 static bool journal_pid_changed(sd_journal
*j
) {
71 /* We don't support people creating a journal object and
72 * keeping it around over a fork(). Let's complain. */
74 return j
->original_pid
!= getpid_cached();
77 static int journal_put_error(sd_journal
*j
, int r
, const char *path
) {
81 /* Memorize an error we encountered, and store which
82 * file/directory it was generated from. Note that we store
83 * only *one* path per error code, as the error code is the
84 * key into the hashmap, and the path is the value. This means
85 * we keep track only of all error kinds, but not of all error
86 * locations. This has the benefit that the hashmap cannot
89 * We return an error here only if we didn't manage to
90 * memorize the real error. */
95 k
= hashmap_ensure_allocated(&j
->errors
, NULL
);
106 k
= hashmap_put(j
->errors
, INT_TO_PTR(r
), copy
);
119 static void detach_location(sd_journal
*j
) {
125 j
->current_file
= NULL
;
126 j
->current_field
= 0;
128 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
)
129 journal_file_reset_location(f
);
132 static void reset_location(sd_journal
*j
) {
136 zero(j
->current_location
);
139 static void init_location(Location
*l
, LocationType type
, JournalFile
*f
, Object
*o
) {
141 assert(IN_SET(type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
143 assert(o
->object
.type
== OBJECT_ENTRY
);
146 l
->seqnum
= le64toh(o
->entry
.seqnum
);
147 l
->seqnum_id
= f
->header
->seqnum_id
;
148 l
->realtime
= le64toh(o
->entry
.realtime
);
149 l
->monotonic
= le64toh(o
->entry
.monotonic
);
150 l
->boot_id
= o
->entry
.boot_id
;
151 l
->xor_hash
= le64toh(o
->entry
.xor_hash
);
153 l
->seqnum_set
= l
->realtime_set
= l
->monotonic_set
= l
->xor_hash_set
= true;
156 static void set_location(sd_journal
*j
, JournalFile
*f
, Object
*o
) {
161 init_location(&j
->current_location
, LOCATION_DISCRETE
, f
, o
);
164 j
->current_field
= 0;
166 /* Let f know its candidate entry was picked. */
167 assert(f
->location_type
== LOCATION_SEEK
);
168 f
->location_type
= LOCATION_DISCRETE
;
171 static int match_is_valid(const void *data
, size_t size
) {
179 if (startswith(data
, "__"))
183 for (p
= b
; p
< b
+ size
; p
++) {
191 if (*p
>= 'A' && *p
<= 'Z')
194 if (*p
>= '0' && *p
<= '9')
203 static bool same_field(const void *_a
, size_t s
, const void *_b
, size_t t
) {
204 const uint8_t *a
= _a
, *b
= _b
;
207 for (j
= 0; j
< s
&& j
< t
; j
++) {
216 assert_not_reached("\"=\" not found");
219 static Match
*match_new(Match
*p
, MatchType t
) {
230 LIST_PREPEND(matches
, p
->matches
, m
);
236 static void match_free(Match
*m
) {
240 match_free(m
->matches
);
243 LIST_REMOVE(matches
, m
->parent
->matches
, m
);
249 static void match_free_if_empty(Match
*m
) {
250 if (!m
|| m
->matches
)
256 _public_
int sd_journal_add_match(sd_journal
*j
, const void *data
, size_t size
) {
257 Match
*l3
, *l4
, *add_here
= NULL
, *m
;
260 assert_return(j
, -EINVAL
);
261 assert_return(!journal_pid_changed(j
), -ECHILD
);
262 assert_return(data
, -EINVAL
);
267 assert_return(match_is_valid(data
, size
), -EINVAL
);
273 * level 4: concrete matches */
276 j
->level0
= match_new(NULL
, MATCH_AND_TERM
);
282 j
->level1
= match_new(j
->level0
, MATCH_OR_TERM
);
288 j
->level2
= match_new(j
->level1
, MATCH_AND_TERM
);
293 assert(j
->level0
->type
== MATCH_AND_TERM
);
294 assert(j
->level1
->type
== MATCH_OR_TERM
);
295 assert(j
->level2
->type
== MATCH_AND_TERM
);
297 le_hash
= htole64(hash64(data
, size
));
299 LIST_FOREACH(matches
, l3
, j
->level2
->matches
) {
300 assert(l3
->type
== MATCH_OR_TERM
);
302 LIST_FOREACH(matches
, l4
, l3
->matches
) {
303 assert(l4
->type
== MATCH_DISCRETE
);
305 /* Exactly the same match already? Then ignore
307 if (l4
->le_hash
== le_hash
&&
309 memcmp(l4
->data
, data
, size
) == 0)
312 /* Same field? Then let's add this to this OR term */
313 if (same_field(data
, size
, l4
->data
, l4
->size
)) {
324 add_here
= match_new(j
->level2
, MATCH_OR_TERM
);
329 m
= match_new(add_here
, MATCH_DISCRETE
);
333 m
->le_hash
= le_hash
;
335 m
->data
= memdup(data
, size
);
344 match_free_if_empty(add_here
);
345 match_free_if_empty(j
->level2
);
346 match_free_if_empty(j
->level1
);
347 match_free_if_empty(j
->level0
);
352 _public_
int sd_journal_add_conjunction(sd_journal
*j
) {
353 assert_return(j
, -EINVAL
);
354 assert_return(!journal_pid_changed(j
), -ECHILD
);
362 if (!j
->level1
->matches
)
371 _public_
int sd_journal_add_disjunction(sd_journal
*j
) {
372 assert_return(j
, -EINVAL
);
373 assert_return(!journal_pid_changed(j
), -ECHILD
);
384 if (!j
->level2
->matches
)
391 static char *match_make_string(Match
*m
) {
394 bool enclose
= false;
397 return strdup("none");
399 if (m
->type
== MATCH_DISCRETE
)
400 return strndup(m
->data
, m
->size
);
402 LIST_FOREACH(matches
, i
, m
->matches
) {
405 t
= match_make_string(i
);
410 k
= strjoin(p
, m
->type
== MATCH_OR_TERM
? " OR " : " AND ", t
);
425 r
= strjoin("(", p
, ")");
433 char *journal_make_match_string(sd_journal
*j
) {
436 return match_make_string(j
->level0
);
439 _public_
void sd_journal_flush_matches(sd_journal
*j
) {
444 match_free(j
->level0
);
446 j
->level0
= j
->level1
= j
->level2
= NULL
;
451 _pure_
static int compare_with_location(JournalFile
*f
, Location
*l
) {
454 assert(f
->location_type
== LOCATION_SEEK
);
455 assert(IN_SET(l
->type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
457 if (l
->monotonic_set
&&
458 sd_id128_equal(f
->current_boot_id
, l
->boot_id
) &&
460 f
->current_realtime
== l
->realtime
&&
462 f
->current_xor_hash
== l
->xor_hash
)
466 sd_id128_equal(f
->header
->seqnum_id
, l
->seqnum_id
)) {
468 if (f
->current_seqnum
< l
->seqnum
)
470 if (f
->current_seqnum
> l
->seqnum
)
474 if (l
->monotonic_set
&&
475 sd_id128_equal(f
->current_boot_id
, l
->boot_id
)) {
477 if (f
->current_monotonic
< l
->monotonic
)
479 if (f
->current_monotonic
> l
->monotonic
)
483 if (l
->realtime_set
) {
485 if (f
->current_realtime
< l
->realtime
)
487 if (f
->current_realtime
> l
->realtime
)
491 if (l
->xor_hash_set
) {
493 if (f
->current_xor_hash
< l
->xor_hash
)
495 if (f
->current_xor_hash
> l
->xor_hash
)
502 static int next_for_match(
506 uint64_t after_offset
,
507 direction_t direction
,
519 if (m
->type
== MATCH_DISCRETE
) {
522 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
526 return journal_file_move_to_entry_by_offset_for_data(f
, dp
, after_offset
, direction
, ret
, offset
);
528 } else if (m
->type
== MATCH_OR_TERM
) {
531 /* Find the earliest match beyond after_offset */
533 LIST_FOREACH(matches
, i
, m
->matches
) {
536 r
= next_for_match(j
, i
, f
, after_offset
, direction
, NULL
, &cp
);
540 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
< np
: cp
> np
))
548 } else if (m
->type
== MATCH_AND_TERM
) {
549 Match
*i
, *last_moved
;
551 /* Always jump to the next matching entry and repeat
552 * this until we find an offset that matches for all
558 r
= next_for_match(j
, m
->matches
, f
, after_offset
, direction
, NULL
, &np
);
562 assert(direction
== DIRECTION_DOWN
? np
>= after_offset
: np
<= after_offset
);
563 last_moved
= m
->matches
;
565 LIST_LOOP_BUT_ONE(matches
, i
, m
->matches
, last_moved
) {
568 r
= next_for_match(j
, i
, f
, np
, direction
, NULL
, &cp
);
572 assert(direction
== DIRECTION_DOWN
? cp
>= np
: cp
<= np
);
573 if (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
) {
582 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
594 static int find_location_for_match(
598 direction_t direction
,
608 if (m
->type
== MATCH_DISCRETE
) {
611 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
615 /* FIXME: missing: find by monotonic */
617 if (j
->current_location
.type
== LOCATION_HEAD
)
618 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_DOWN
, ret
, offset
);
619 if (j
->current_location
.type
== LOCATION_TAIL
)
620 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_UP
, ret
, offset
);
621 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
622 return journal_file_move_to_entry_by_seqnum_for_data(f
, dp
, j
->current_location
.seqnum
, direction
, ret
, offset
);
623 if (j
->current_location
.monotonic_set
) {
624 r
= journal_file_move_to_entry_by_monotonic_for_data(f
, dp
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
628 if (j
->current_location
.realtime_set
)
629 return journal_file_move_to_entry_by_realtime_for_data(f
, dp
, j
->current_location
.realtime
, direction
, ret
, offset
);
631 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, direction
, ret
, offset
);
633 } else if (m
->type
== MATCH_OR_TERM
) {
638 /* Find the earliest match */
640 LIST_FOREACH(matches
, i
, m
->matches
) {
643 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
647 if (np
== 0 || (direction
== DIRECTION_DOWN
? np
> cp
: np
< cp
))
655 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
670 assert(m
->type
== MATCH_AND_TERM
);
672 /* First jump to the last match, and then find the
673 * next one where all matches match */
678 LIST_FOREACH(matches
, i
, m
->matches
) {
681 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
685 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
))
689 return next_for_match(j
, m
, f
, np
, direction
, ret
, offset
);
693 static int find_location_with_matches(
696 direction_t direction
,
708 /* No matches is simple */
710 if (j
->current_location
.type
== LOCATION_HEAD
)
711 return journal_file_next_entry(f
, 0, DIRECTION_DOWN
, ret
, offset
);
712 if (j
->current_location
.type
== LOCATION_TAIL
)
713 return journal_file_next_entry(f
, 0, DIRECTION_UP
, ret
, offset
);
714 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
715 return journal_file_move_to_entry_by_seqnum(f
, j
->current_location
.seqnum
, direction
, ret
, offset
);
716 if (j
->current_location
.monotonic_set
) {
717 r
= journal_file_move_to_entry_by_monotonic(f
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
721 if (j
->current_location
.realtime_set
)
722 return journal_file_move_to_entry_by_realtime(f
, j
->current_location
.realtime
, direction
, ret
, offset
);
724 return journal_file_next_entry(f
, 0, direction
, ret
, offset
);
726 return find_location_for_match(j
, j
->level0
, f
, direction
, ret
, offset
);
729 static int next_with_matches(
732 direction_t direction
,
741 /* No matches is easy. We simple advance the file
744 return journal_file_next_entry(f
, f
->current_offset
, direction
, ret
, offset
);
746 /* If we have a match then we look for the next matching entry
747 * with an offset at least one step larger */
748 return next_for_match(j
, j
->level0
, f
,
749 direction
== DIRECTION_DOWN
? f
->current_offset
+ 1
750 : f
->current_offset
- 1,
751 direction
, ret
, offset
);
754 static int next_beyond_location(sd_journal
*j
, JournalFile
*f
, direction_t direction
) {
756 uint64_t cp
, n_entries
;
762 n_entries
= le64toh(f
->header
->n_entries
);
764 /* If we hit EOF before, we don't need to look into this file again
765 * unless direction changed or new entries appeared. */
766 if (f
->last_direction
== direction
&& f
->location_type
== LOCATION_TAIL
&&
767 n_entries
== f
->last_n_entries
)
770 f
->last_n_entries
= n_entries
;
772 if (f
->last_direction
== direction
&& f
->current_offset
> 0) {
773 /* LOCATION_SEEK here means we did the work in a previous
774 * iteration and the current location already points to a
775 * candidate entry. */
776 if (f
->location_type
!= LOCATION_SEEK
) {
777 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
781 journal_file_save_location(f
, c
, cp
);
784 f
->last_direction
= direction
;
786 r
= find_location_with_matches(j
, f
, direction
, &c
, &cp
);
790 journal_file_save_location(f
, c
, cp
);
793 /* OK, we found the spot, now let's advance until an entry
794 * that is actually different from what we were previously
795 * looking at. This is necessary to handle entries which exist
796 * in two (or more) journal files, and which shall all be
797 * suppressed but one. */
802 if (j
->current_location
.type
== LOCATION_DISCRETE
) {
805 k
= compare_with_location(f
, &j
->current_location
);
807 found
= direction
== DIRECTION_DOWN
? k
> 0 : k
< 0;
814 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
818 journal_file_save_location(f
, c
, cp
);
822 static int real_journal_next(sd_journal
*j
, direction_t direction
) {
823 JournalFile
*new_file
= NULL
;
829 assert_return(j
, -EINVAL
);
830 assert_return(!journal_pid_changed(j
), -ECHILD
);
832 r
= iterated_cache_get(j
->files_cache
, NULL
, &files
, &n_files
);
836 for (i
= 0; i
< n_files
; i
++) {
837 JournalFile
*f
= (JournalFile
*)files
[i
];
840 r
= next_beyond_location(j
, f
, direction
);
842 log_debug_errno(r
, "Can't iterate through %s, ignoring: %m", f
->path
);
843 remove_file_real(j
, f
);
846 f
->location_type
= LOCATION_TAIL
;
855 k
= journal_file_compare_locations(f
, new_file
);
857 found
= direction
== DIRECTION_DOWN
? k
< 0 : k
> 0;
867 r
= journal_file_move_to_object(new_file
, OBJECT_ENTRY
, new_file
->current_offset
, &o
);
871 set_location(j
, new_file
, o
);
876 _public_
int sd_journal_next(sd_journal
*j
) {
877 return real_journal_next(j
, DIRECTION_DOWN
);
880 _public_
int sd_journal_previous(sd_journal
*j
) {
881 return real_journal_next(j
, DIRECTION_UP
);
884 static int real_journal_next_skip(sd_journal
*j
, direction_t direction
, uint64_t skip
) {
887 assert_return(j
, -EINVAL
);
888 assert_return(!journal_pid_changed(j
), -ECHILD
);
891 /* If this is not a discrete skip, then at least
892 * resolve the current location */
893 if (j
->current_location
.type
!= LOCATION_DISCRETE
) {
894 r
= real_journal_next(j
, direction
);
903 r
= real_journal_next(j
, direction
);
917 _public_
int sd_journal_next_skip(sd_journal
*j
, uint64_t skip
) {
918 return real_journal_next_skip(j
, DIRECTION_DOWN
, skip
);
921 _public_
int sd_journal_previous_skip(sd_journal
*j
, uint64_t skip
) {
922 return real_journal_next_skip(j
, DIRECTION_UP
, skip
);
925 _public_
int sd_journal_get_cursor(sd_journal
*j
, char **cursor
) {
928 char bid
[33], sid
[33];
930 assert_return(j
, -EINVAL
);
931 assert_return(!journal_pid_changed(j
), -ECHILD
);
932 assert_return(cursor
, -EINVAL
);
934 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
935 return -EADDRNOTAVAIL
;
937 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
941 sd_id128_to_string(j
->current_file
->header
->seqnum_id
, sid
);
942 sd_id128_to_string(o
->entry
.boot_id
, bid
);
945 "s=%s;i=%"PRIx64
";b=%s;m=%"PRIx64
";t=%"PRIx64
";x=%"PRIx64
,
946 sid
, le64toh(o
->entry
.seqnum
),
947 bid
, le64toh(o
->entry
.monotonic
),
948 le64toh(o
->entry
.realtime
),
949 le64toh(o
->entry
.xor_hash
)) < 0)
955 _public_
int sd_journal_seek_cursor(sd_journal
*j
, const char *cursor
) {
956 const char *word
, *state
;
958 unsigned long long seqnum
, monotonic
, realtime
, xor_hash
;
960 seqnum_id_set
= false,
963 monotonic_set
= false,
964 realtime_set
= false,
965 xor_hash_set
= false;
966 sd_id128_t seqnum_id
, boot_id
;
968 assert_return(j
, -EINVAL
);
969 assert_return(!journal_pid_changed(j
), -ECHILD
);
970 assert_return(!isempty(cursor
), -EINVAL
);
972 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
976 if (l
< 2 || word
[1] != '=')
979 item
= strndup(word
, l
);
986 seqnum_id_set
= true;
987 k
= sd_id128_from_string(item
+2, &seqnum_id
);
992 if (sscanf(item
+2, "%llx", &seqnum
) != 1)
998 k
= sd_id128_from_string(item
+2, &boot_id
);
1002 monotonic_set
= true;
1003 if (sscanf(item
+2, "%llx", &monotonic
) != 1)
1008 realtime_set
= true;
1009 if (sscanf(item
+2, "%llx", &realtime
) != 1)
1014 xor_hash_set
= true;
1015 if (sscanf(item
+2, "%llx", &xor_hash
) != 1)
1026 if ((!seqnum_set
|| !seqnum_id_set
) &&
1027 (!monotonic_set
|| !boot_id_set
) &&
1033 j
->current_location
.type
= LOCATION_SEEK
;
1036 j
->current_location
.realtime
= (uint64_t) realtime
;
1037 j
->current_location
.realtime_set
= true;
1040 if (seqnum_set
&& seqnum_id_set
) {
1041 j
->current_location
.seqnum
= (uint64_t) seqnum
;
1042 j
->current_location
.seqnum_id
= seqnum_id
;
1043 j
->current_location
.seqnum_set
= true;
1046 if (monotonic_set
&& boot_id_set
) {
1047 j
->current_location
.monotonic
= (uint64_t) monotonic
;
1048 j
->current_location
.boot_id
= boot_id
;
1049 j
->current_location
.monotonic_set
= true;
1053 j
->current_location
.xor_hash
= (uint64_t) xor_hash
;
1054 j
->current_location
.xor_hash_set
= true;
1060 _public_
int sd_journal_test_cursor(sd_journal
*j
, const char *cursor
) {
1064 assert_return(j
, -EINVAL
);
1065 assert_return(!journal_pid_changed(j
), -ECHILD
);
1066 assert_return(!isempty(cursor
), -EINVAL
);
1068 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
1069 return -EADDRNOTAVAIL
;
1071 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
1076 _cleanup_free_
char *item
= NULL
;
1077 unsigned long long ll
;
1081 r
= extract_first_word(&cursor
, &item
, ";", EXTRACT_DONT_COALESCE_SEPARATORS
);
1088 if (strlen(item
) < 2 || item
[1] != '=')
1094 k
= sd_id128_from_string(item
+2, &id
);
1097 if (!sd_id128_equal(id
, j
->current_file
->header
->seqnum_id
))
1102 if (sscanf(item
+2, "%llx", &ll
) != 1)
1104 if (ll
!= le64toh(o
->entry
.seqnum
))
1109 k
= sd_id128_from_string(item
+2, &id
);
1112 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1117 if (sscanf(item
+2, "%llx", &ll
) != 1)
1119 if (ll
!= le64toh(o
->entry
.monotonic
))
1124 if (sscanf(item
+2, "%llx", &ll
) != 1)
1126 if (ll
!= le64toh(o
->entry
.realtime
))
1131 if (sscanf(item
+2, "%llx", &ll
) != 1)
1133 if (ll
!= le64toh(o
->entry
.xor_hash
))
1143 _public_
int sd_journal_seek_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t usec
) {
1144 assert_return(j
, -EINVAL
);
1145 assert_return(!journal_pid_changed(j
), -ECHILD
);
1148 j
->current_location
.type
= LOCATION_SEEK
;
1149 j
->current_location
.boot_id
= boot_id
;
1150 j
->current_location
.monotonic
= usec
;
1151 j
->current_location
.monotonic_set
= true;
1156 _public_
int sd_journal_seek_realtime_usec(sd_journal
*j
, uint64_t usec
) {
1157 assert_return(j
, -EINVAL
);
1158 assert_return(!journal_pid_changed(j
), -ECHILD
);
1161 j
->current_location
.type
= LOCATION_SEEK
;
1162 j
->current_location
.realtime
= usec
;
1163 j
->current_location
.realtime_set
= true;
1168 _public_
int sd_journal_seek_head(sd_journal
*j
) {
1169 assert_return(j
, -EINVAL
);
1170 assert_return(!journal_pid_changed(j
), -ECHILD
);
1173 j
->current_location
.type
= LOCATION_HEAD
;
1178 _public_
int sd_journal_seek_tail(sd_journal
*j
) {
1179 assert_return(j
, -EINVAL
);
1180 assert_return(!journal_pid_changed(j
), -ECHILD
);
1183 j
->current_location
.type
= LOCATION_TAIL
;
1188 static void check_network(sd_journal
*j
, int fd
) {
1196 if (fstatfs(fd
, &sfs
) < 0)
1200 F_TYPE_EQUAL(sfs
.f_type
, CIFS_MAGIC_NUMBER
) ||
1201 F_TYPE_EQUAL(sfs
.f_type
, CODA_SUPER_MAGIC
) ||
1202 F_TYPE_EQUAL(sfs
.f_type
, NCP_SUPER_MAGIC
) ||
1203 F_TYPE_EQUAL(sfs
.f_type
, NFS_SUPER_MAGIC
) ||
1204 F_TYPE_EQUAL(sfs
.f_type
, SMB_SUPER_MAGIC
);
1207 static bool file_has_type_prefix(const char *prefix
, const char *filename
) {
1208 const char *full
, *tilded
, *atted
;
1210 full
= strjoina(prefix
, ".journal");
1211 tilded
= strjoina(full
, "~");
1212 atted
= strjoina(prefix
, "@");
1214 return streq(filename
, full
) ||
1215 streq(filename
, tilded
) ||
1216 startswith(filename
, atted
);
1219 static bool file_type_wanted(int flags
, const char *filename
) {
1222 if (!endswith(filename
, ".journal") && !endswith(filename
, ".journal~"))
1225 /* no flags set → every type is OK */
1226 if (!(flags
& (SD_JOURNAL_SYSTEM
| SD_JOURNAL_CURRENT_USER
)))
1229 if (flags
& SD_JOURNAL_SYSTEM
&& file_has_type_prefix("system", filename
))
1232 if (flags
& SD_JOURNAL_CURRENT_USER
) {
1233 char prefix
[5 + DECIMAL_STR_MAX(uid_t
) + 1];
1235 xsprintf(prefix
, "user-"UID_FMT
, getuid());
1237 if (file_has_type_prefix(prefix
, filename
))
1244 static bool path_has_prefix(sd_journal
*j
, const char *path
, const char *prefix
) {
1249 if (j
->toplevel_fd
>= 0)
1252 return path_startswith(path
, prefix
);
1255 static const char *skip_slash(const char *p
) {
1266 static int add_any_file(sd_journal
*j
, int fd
, const char *path
) {
1267 JournalFile
*f
= NULL
;
1268 bool close_fd
= false;
1272 assert(fd
>= 0 || path
);
1274 if (path
&& ordered_hashmap_get(j
->files
, path
))
1277 if (ordered_hashmap_size(j
->files
) >= JOURNAL_FILES_MAX
) {
1278 log_debug("Too many open journal files, not adding %s.", path
);
1283 if (fd
< 0 && j
->toplevel_fd
>= 0) {
1285 /* If there's a top-level fd defined, open the file relative to this now. (Make the path relative,
1286 * explicitly, since otherwise openat() ignores the first argument.) */
1288 fd
= openat(j
->toplevel_fd
, skip_slash(path
), O_RDONLY
|O_CLOEXEC
);
1290 r
= log_debug_errno(errno
, "Failed to open journal file %s: %m", path
);
1297 r
= journal_file_open(fd
, path
, O_RDONLY
, 0, false, false, NULL
, j
->mmap
, NULL
, NULL
, &f
);
1301 log_debug_errno(r
, "Failed to open journal file %s: %m", path
);
1305 /* journal_file_dump(f); */
1307 r
= ordered_hashmap_put(j
->files
, f
->path
, f
);
1309 f
->close_fd
= close_fd
;
1310 (void) journal_file_close(f
);
1314 if (!j
->has_runtime_files
&& path_has_prefix(j
, f
->path
, "/run"))
1315 j
->has_runtime_files
= true;
1316 else if (!j
->has_persistent_files
&& path_has_prefix(j
, f
->path
, "/var"))
1317 j
->has_persistent_files
= true;
1319 log_debug("File %s added.", f
->path
);
1321 check_network(j
, f
->fd
);
1323 j
->current_invalidate_counter
++;
1328 k
= journal_put_error(j
, r
, path
);
1335 static int add_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1342 if (j
->no_new_files
)
1345 if (!file_type_wanted(j
->flags
, filename
))
1348 path
= strjoina(prefix
, "/", filename
);
1349 return add_any_file(j
, -1, path
);
1352 static void remove_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1360 path
= strjoina(prefix
, "/", filename
);
1361 f
= ordered_hashmap_get(j
->files
, path
);
1365 remove_file_real(j
, f
);
1368 static void remove_file_real(sd_journal
*j
, JournalFile
*f
) {
1372 ordered_hashmap_remove(j
->files
, f
->path
);
1374 log_debug("File %s removed.", f
->path
);
1376 if (j
->current_file
== f
) {
1377 j
->current_file
= NULL
;
1378 j
->current_field
= 0;
1381 if (j
->unique_file
== f
) {
1382 /* Jump to the next unique_file or NULL if that one was last */
1383 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
1384 j
->unique_offset
= 0;
1385 if (!j
->unique_file
)
1386 j
->unique_file_lost
= true;
1389 if (j
->fields_file
== f
) {
1390 j
->fields_file
= ordered_hashmap_next(j
->files
, j
->fields_file
->path
);
1391 j
->fields_offset
= 0;
1392 if (!j
->fields_file
)
1393 j
->fields_file_lost
= true;
1396 (void) journal_file_close(f
);
1398 j
->current_invalidate_counter
++;
1401 static int dirname_is_machine_id(const char *fn
) {
1402 sd_id128_t id
, machine
;
1405 r
= sd_id128_get_machine(&machine
);
1409 r
= sd_id128_from_string(fn
, &id
);
1413 return sd_id128_equal(id
, machine
);
1416 static int add_directory(sd_journal
*j
, const char *prefix
, const char *dirname
) {
1417 _cleanup_free_
char *path
= NULL
;
1418 _cleanup_closedir_
DIR *d
= NULL
;
1419 struct dirent
*de
= NULL
;
1426 /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
1427 * and reenumerates directory contents */
1430 path
= strjoin(prefix
, "/", dirname
);
1432 path
= strdup(prefix
);
1438 log_debug("Considering directory %s.", path
);
1440 /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
1441 if ((j
->flags
& SD_JOURNAL_LOCAL_ONLY
) &&
1442 !((dirname
&& dirname_is_machine_id(dirname
) > 0) || path_has_prefix(j
, path
, "/run")))
1446 if (j
->toplevel_fd
< 0)
1449 /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
1450 * relative, by dropping the initial slash */
1451 d
= xopendirat(j
->toplevel_fd
, skip_slash(path
), 0);
1453 r
= log_debug_errno(errno
, "Failed to open directory %s: %m", path
);
1457 m
= hashmap_get(j
->directories_by_path
, path
);
1459 m
= new0(Directory
, 1);
1468 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1474 path
= NULL
; /* avoid freeing in cleanup */
1475 j
->current_invalidate_counter
++;
1477 log_debug("Directory %s added.", m
->path
);
1479 } else if (m
->is_root
)
1482 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1483 /* Watch this directory, if it not being watched yet. */
1485 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1486 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1487 IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
|IN_MOVED_FROM
|
1490 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1491 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1494 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
1496 if (dirent_is_file_with_suffix(de
, ".journal") ||
1497 dirent_is_file_with_suffix(de
, ".journal~"))
1498 (void) add_file(j
, m
->path
, de
->d_name
);
1501 check_network(j
, dirfd(d
));
1506 k
= journal_put_error(j
, r
, path
?: prefix
);
1513 static int add_root_directory(sd_journal
*j
, const char *p
, bool missing_ok
) {
1515 _cleanup_closedir_
DIR *d
= NULL
;
1522 /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
1523 * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
1524 * populate the set, as well as to update it later. */
1527 /* If there's a path specified, use it. */
1529 if ((j
->flags
& SD_JOURNAL_RUNTIME_ONLY
) &&
1530 !path_has_prefix(j
, p
, "/run"))
1534 p
= strjoina(j
->prefix
, p
);
1536 if (j
->toplevel_fd
< 0)
1539 d
= xopendirat(j
->toplevel_fd
, skip_slash(p
), 0);
1542 if (errno
== ENOENT
&& missing_ok
)
1545 r
= log_debug_errno(errno
, "Failed to open root directory %s: %m", p
);
1551 /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
1552 * opendir() will take possession of the fd, and close it, which we don't want. */
1554 p
= "."; /* store this as "." in the directories hashmap */
1556 dfd
= fcntl(j
->toplevel_fd
, F_DUPFD_CLOEXEC
, 3);
1572 m
= hashmap_get(j
->directories_by_path
, p
);
1574 m
= new0(Directory
, 1);
1582 m
->path
= strdup(p
);
1589 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1596 j
->current_invalidate_counter
++;
1598 log_debug("Root directory %s added.", m
->path
);
1600 } else if (!m
->is_root
)
1603 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1605 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1606 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1609 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1610 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1613 if (j
->no_new_files
)
1616 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
1619 if (dirent_is_file_with_suffix(de
, ".journal") ||
1620 dirent_is_file_with_suffix(de
, ".journal~"))
1621 (void) add_file(j
, m
->path
, de
->d_name
);
1622 else if (IN_SET(de
->d_type
, DT_DIR
, DT_LNK
, DT_UNKNOWN
) &&
1623 sd_id128_from_string(de
->d_name
, &id
) >= 0)
1624 (void) add_directory(j
, m
->path
, de
->d_name
);
1627 check_network(j
, dirfd(d
));
1632 k
= journal_put_error(j
, r
, p
);
1639 static void remove_directory(sd_journal
*j
, Directory
*d
) {
1643 hashmap_remove(j
->directories_by_wd
, INT_TO_PTR(d
->wd
));
1645 if (j
->inotify_fd
>= 0)
1646 inotify_rm_watch(j
->inotify_fd
, d
->wd
);
1649 hashmap_remove(j
->directories_by_path
, d
->path
);
1652 log_debug("Root directory %s removed.", d
->path
);
1654 log_debug("Directory %s removed.", d
->path
);
1660 static int add_search_paths(sd_journal
*j
) {
1662 static const char search_paths
[] =
1663 "/run/log/journal\0"
1664 "/var/log/journal\0";
1669 /* We ignore most errors here, since the idea is to only open
1670 * what's actually accessible, and ignore the rest. */
1672 NULSTR_FOREACH(p
, search_paths
)
1673 (void) add_root_directory(j
, p
, true);
1675 if (!(j
->flags
& SD_JOURNAL_LOCAL_ONLY
))
1676 (void) add_root_directory(j
, "/var/log/journal/remote", true);
1681 static int add_current_paths(sd_journal
*j
) {
1686 assert(j
->no_new_files
);
1688 /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
1689 * treat them as fatal. */
1691 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1692 _cleanup_free_
char *dir
;
1695 dir
= dirname_malloc(f
->path
);
1699 r
= add_directory(j
, dir
, NULL
);
1707 static int allocate_inotify(sd_journal
*j
) {
1710 if (j
->inotify_fd
< 0) {
1711 j
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1712 if (j
->inotify_fd
< 0)
1716 return hashmap_ensure_allocated(&j
->directories_by_wd
, NULL
);
1719 static sd_journal
*journal_new(int flags
, const char *path
) {
1722 j
= new0(sd_journal
, 1);
1726 j
->original_pid
= getpid_cached();
1727 j
->toplevel_fd
= -1;
1730 j
->data_threshold
= DEFAULT_DATA_THRESHOLD
;
1739 if (flags
& SD_JOURNAL_OS_ROOT
)
1745 j
->files
= ordered_hashmap_new(&string_hash_ops
);
1749 j
->files_cache
= ordered_hashmap_iterated_cache_new(j
->files
);
1750 j
->directories_by_path
= hashmap_new(&string_hash_ops
);
1751 j
->mmap
= mmap_cache_new();
1752 if (!j
->files_cache
|| !j
->directories_by_path
|| !j
->mmap
)
1758 sd_journal_close(j
);
1762 #define OPEN_ALLOWED_FLAGS \
1763 (SD_JOURNAL_LOCAL_ONLY | \
1764 SD_JOURNAL_RUNTIME_ONLY | \
1765 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)
1767 _public_
int sd_journal_open(sd_journal
**ret
, int flags
) {
1771 assert_return(ret
, -EINVAL
);
1772 assert_return((flags
& ~OPEN_ALLOWED_FLAGS
) == 0, -EINVAL
);
1774 j
= journal_new(flags
, NULL
);
1778 r
= add_search_paths(j
);
1786 sd_journal_close(j
);
1791 #define OPEN_CONTAINER_ALLOWED_FLAGS \
1792 (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
1794 _public_
int sd_journal_open_container(sd_journal
**ret
, const char *machine
, int flags
) {
1795 _cleanup_free_
char *root
= NULL
, *class = NULL
;
1800 /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
1801 * combination with sd_journal_open_directory_fd(). */
1803 assert_return(machine
, -EINVAL
);
1804 assert_return(ret
, -EINVAL
);
1805 assert_return((flags
& ~OPEN_CONTAINER_ALLOWED_FLAGS
) == 0, -EINVAL
);
1806 assert_return(machine_name_is_valid(machine
), -EINVAL
);
1808 p
= strjoina("/run/systemd/machines/", machine
);
1809 r
= parse_env_file(p
, NEWLINE
, "ROOT", &root
, "CLASS", &class, NULL
);
1817 if (!streq_ptr(class, "container"))
1820 j
= journal_new(flags
, root
);
1824 r
= add_search_paths(j
);
1832 sd_journal_close(j
);
1836 #define OPEN_DIRECTORY_ALLOWED_FLAGS \
1837 (SD_JOURNAL_OS_ROOT | \
1838 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1840 _public_
int sd_journal_open_directory(sd_journal
**ret
, const char *path
, int flags
) {
1844 assert_return(ret
, -EINVAL
);
1845 assert_return(path
, -EINVAL
);
1846 assert_return((flags
& ~OPEN_DIRECTORY_ALLOWED_FLAGS
) == 0, -EINVAL
);
1848 j
= journal_new(flags
, path
);
1852 if (flags
& SD_JOURNAL_OS_ROOT
)
1853 r
= add_search_paths(j
);
1855 r
= add_root_directory(j
, path
, false);
1863 sd_journal_close(j
);
1867 _public_
int sd_journal_open_files(sd_journal
**ret
, const char **paths
, int flags
) {
1872 assert_return(ret
, -EINVAL
);
1873 assert_return(flags
== 0, -EINVAL
);
1875 j
= journal_new(flags
, NULL
);
1879 STRV_FOREACH(path
, paths
) {
1880 r
= add_any_file(j
, -1, *path
);
1885 j
->no_new_files
= true;
1891 sd_journal_close(j
);
1895 #define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
1896 (SD_JOURNAL_OS_ROOT | \
1897 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1899 _public_
int sd_journal_open_directory_fd(sd_journal
**ret
, int fd
, int flags
) {
1904 assert_return(ret
, -EINVAL
);
1905 assert_return(fd
>= 0, -EBADF
);
1906 assert_return((flags
& ~OPEN_DIRECTORY_FD_ALLOWED_FLAGS
) == 0, -EINVAL
);
1908 if (fstat(fd
, &st
) < 0)
1911 if (!S_ISDIR(st
.st_mode
))
1914 j
= journal_new(flags
, NULL
);
1918 j
->toplevel_fd
= fd
;
1920 if (flags
& SD_JOURNAL_OS_ROOT
)
1921 r
= add_search_paths(j
);
1923 r
= add_root_directory(j
, NULL
, false);
1931 sd_journal_close(j
);
1935 _public_
int sd_journal_open_files_fd(sd_journal
**ret
, int fds
[], unsigned n_fds
, int flags
) {
1942 assert_return(ret
, -EINVAL
);
1943 assert_return(n_fds
> 0, -EBADF
);
1944 assert_return(flags
== 0, -EINVAL
);
1946 j
= journal_new(flags
, NULL
);
1950 for (i
= 0; i
< n_fds
; i
++) {
1958 if (fstat(fds
[i
], &st
) < 0) {
1963 if (!S_ISREG(st
.st_mode
)) {
1968 r
= add_any_file(j
, fds
[i
], NULL
);
1973 j
->no_new_files
= true;
1974 j
->no_inotify
= true;
1980 /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
1982 ORDERED_HASHMAP_FOREACH(f
, j
->files
, iterator
)
1983 f
->close_fd
= false;
1985 sd_journal_close(j
);
1989 _public_
void sd_journal_close(sd_journal
*j
) {
1995 sd_journal_flush_matches(j
);
1997 ordered_hashmap_free_with_destructor(j
->files
, journal_file_close
);
1998 iterated_cache_free(j
->files_cache
);
2000 while ((d
= hashmap_first(j
->directories_by_path
)))
2001 remove_directory(j
, d
);
2003 while ((d
= hashmap_first(j
->directories_by_wd
)))
2004 remove_directory(j
, d
);
2006 hashmap_free(j
->directories_by_path
);
2007 hashmap_free(j
->directories_by_wd
);
2009 safe_close(j
->inotify_fd
);
2012 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j
->mmap
), mmap_cache_get_missed(j
->mmap
));
2013 mmap_cache_unref(j
->mmap
);
2016 hashmap_free_free(j
->errors
);
2020 free(j
->unique_field
);
2021 free(j
->fields_buffer
);
2025 _public_
int sd_journal_get_realtime_usec(sd_journal
*j
, uint64_t *ret
) {
2030 assert_return(j
, -EINVAL
);
2031 assert_return(!journal_pid_changed(j
), -ECHILD
);
2032 assert_return(ret
, -EINVAL
);
2034 f
= j
->current_file
;
2036 return -EADDRNOTAVAIL
;
2038 if (f
->current_offset
<= 0)
2039 return -EADDRNOTAVAIL
;
2041 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2045 *ret
= le64toh(o
->entry
.realtime
);
2049 _public_
int sd_journal_get_monotonic_usec(sd_journal
*j
, uint64_t *ret
, sd_id128_t
*ret_boot_id
) {
2055 assert_return(j
, -EINVAL
);
2056 assert_return(!journal_pid_changed(j
), -ECHILD
);
2058 f
= j
->current_file
;
2060 return -EADDRNOTAVAIL
;
2062 if (f
->current_offset
<= 0)
2063 return -EADDRNOTAVAIL
;
2065 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2070 *ret_boot_id
= o
->entry
.boot_id
;
2072 r
= sd_id128_get_boot(&id
);
2076 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
2081 *ret
= le64toh(o
->entry
.monotonic
);
2086 static bool field_is_valid(const char *field
) {
2094 if (startswith(field
, "__"))
2097 for (p
= field
; *p
; p
++) {
2102 if (*p
>= 'A' && *p
<= 'Z')
2105 if (*p
>= '0' && *p
<= '9')
2114 _public_
int sd_journal_get_data(sd_journal
*j
, const char *field
, const void **data
, size_t *size
) {
2117 size_t field_length
;
2121 assert_return(j
, -EINVAL
);
2122 assert_return(!journal_pid_changed(j
), -ECHILD
);
2123 assert_return(field
, -EINVAL
);
2124 assert_return(data
, -EINVAL
);
2125 assert_return(size
, -EINVAL
);
2126 assert_return(field_is_valid(field
), -EINVAL
);
2128 f
= j
->current_file
;
2130 return -EADDRNOTAVAIL
;
2132 if (f
->current_offset
<= 0)
2133 return -EADDRNOTAVAIL
;
2135 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2139 field_length
= strlen(field
);
2141 n
= journal_file_entry_n_items(o
);
2142 for (i
= 0; i
< n
; i
++) {
2148 p
= le64toh(o
->entry
.items
[i
].object_offset
);
2149 le_hash
= o
->entry
.items
[i
].hash
;
2150 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2154 if (le_hash
!= o
->data
.hash
)
2157 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2159 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2161 #if HAVE_XZ || HAVE_LZ4
2162 r
= decompress_startswith(compression
,
2164 &f
->compress_buffer
, &f
->compress_buffer_size
,
2165 field
, field_length
, '=');
2167 log_debug_errno(r
, "Cannot decompress %s object of length %"PRIu64
" at offset "OFSfmt
": %m",
2168 object_compressed_to_string(compression
), l
, p
);
2173 r
= decompress_blob(compression
,
2175 &f
->compress_buffer
, &f
->compress_buffer_size
, &rsize
,
2180 *data
= f
->compress_buffer
;
2181 *size
= (size_t) rsize
;
2186 return -EPROTONOSUPPORT
;
2188 } else if (l
>= field_length
+1 &&
2189 memcmp(o
->data
.payload
, field
, field_length
) == 0 &&
2190 o
->data
.payload
[field_length
] == '=') {
2194 if ((uint64_t) t
!= l
)
2197 *data
= o
->data
.payload
;
2203 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2211 static int return_data(sd_journal
*j
, JournalFile
*f
, Object
*o
, const void **data
, size_t *size
) {
2216 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2219 /* We can't read objects larger than 4G on a 32bit machine */
2220 if ((uint64_t) t
!= l
)
2223 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2225 #if HAVE_XZ || HAVE_LZ4
2229 r
= decompress_blob(compression
,
2230 o
->data
.payload
, l
, &f
->compress_buffer
,
2231 &f
->compress_buffer_size
, &rsize
, j
->data_threshold
);
2235 *data
= f
->compress_buffer
;
2236 *size
= (size_t) rsize
;
2238 return -EPROTONOSUPPORT
;
2241 *data
= o
->data
.payload
;
2248 _public_
int sd_journal_enumerate_data(sd_journal
*j
, const void **data
, size_t *size
) {
2255 assert_return(j
, -EINVAL
);
2256 assert_return(!journal_pid_changed(j
), -ECHILD
);
2257 assert_return(data
, -EINVAL
);
2258 assert_return(size
, -EINVAL
);
2260 f
= j
->current_file
;
2262 return -EADDRNOTAVAIL
;
2264 if (f
->current_offset
<= 0)
2265 return -EADDRNOTAVAIL
;
2267 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2271 n
= journal_file_entry_n_items(o
);
2272 if (j
->current_field
>= n
)
2275 p
= le64toh(o
->entry
.items
[j
->current_field
].object_offset
);
2276 le_hash
= o
->entry
.items
[j
->current_field
].hash
;
2277 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2281 if (le_hash
!= o
->data
.hash
)
2284 r
= return_data(j
, f
, o
, data
, size
);
2293 _public_
void sd_journal_restart_data(sd_journal
*j
) {
2297 j
->current_field
= 0;
2300 _public_
int sd_journal_get_fd(sd_journal
*j
) {
2303 assert_return(j
, -EINVAL
);
2304 assert_return(!journal_pid_changed(j
), -ECHILD
);
2307 return -EMEDIUMTYPE
;
2309 if (j
->inotify_fd
>= 0)
2310 return j
->inotify_fd
;
2312 r
= allocate_inotify(j
);
2316 log_debug("Reiterating files to get inotify watches established");
2318 /* Iterate through all dirs again, to add them to the
2320 if (j
->no_new_files
)
2321 r
= add_current_paths(j
);
2322 else if (j
->flags
& SD_JOURNAL_OS_ROOT
)
2323 r
= add_search_paths(j
);
2324 else if (j
->toplevel_fd
>= 0)
2325 r
= add_root_directory(j
, NULL
, false);
2327 r
= add_root_directory(j
, j
->path
, true);
2329 r
= add_search_paths(j
);
2333 return j
->inotify_fd
;
2336 _public_
int sd_journal_get_events(sd_journal
*j
) {
2339 assert_return(j
, -EINVAL
);
2340 assert_return(!journal_pid_changed(j
), -ECHILD
);
2342 fd
= sd_journal_get_fd(j
);
2349 _public_
int sd_journal_get_timeout(sd_journal
*j
, uint64_t *timeout_usec
) {
2352 assert_return(j
, -EINVAL
);
2353 assert_return(!journal_pid_changed(j
), -ECHILD
);
2354 assert_return(timeout_usec
, -EINVAL
);
2356 fd
= sd_journal_get_fd(j
);
2360 if (!j
->on_network
) {
2361 *timeout_usec
= (uint64_t) -1;
2365 /* If we are on the network we need to regularly check for
2366 * changes manually */
2368 *timeout_usec
= j
->last_process_usec
+ JOURNAL_FILES_RECHECK_USEC
;
2372 static void process_inotify_event(sd_journal
*j
, struct inotify_event
*e
) {
2378 /* Is this a subdirectory we watch? */
2379 d
= hashmap_get(j
->directories_by_wd
, INT_TO_PTR(e
->wd
));
2383 if (!(e
->mask
& IN_ISDIR
) && e
->len
> 0 &&
2384 (endswith(e
->name
, ".journal") ||
2385 endswith(e
->name
, ".journal~"))) {
2387 /* Event for a journal file */
2389 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2390 (void) add_file(j
, d
->path
, e
->name
);
2391 else if (e
->mask
& (IN_DELETE
|IN_MOVED_FROM
|IN_UNMOUNT
))
2392 remove_file(j
, d
->path
, e
->name
);
2394 } else if (!d
->is_root
&& e
->len
== 0) {
2396 /* Event for a subdirectory */
2398 if (e
->mask
& (IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
))
2399 remove_directory(j
, d
);
2401 } else if (d
->is_root
&& (e
->mask
& IN_ISDIR
) && e
->len
> 0 && sd_id128_from_string(e
->name
, &id
) >= 0) {
2403 /* Event for root directory */
2405 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2406 (void) add_directory(j
, d
->path
, e
->name
);
2412 if (e
->mask
& IN_IGNORED
)
2415 log_debug("Unknown inotify event.");
2418 static int determine_change(sd_journal
*j
) {
2423 b
= j
->current_invalidate_counter
!= j
->last_invalidate_counter
;
2424 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2426 return b
? SD_JOURNAL_INVALIDATE
: SD_JOURNAL_APPEND
;
2429 _public_
int sd_journal_process(sd_journal
*j
) {
2430 bool got_something
= false;
2432 assert_return(j
, -EINVAL
);
2433 assert_return(!journal_pid_changed(j
), -ECHILD
);
2435 j
->last_process_usec
= now(CLOCK_MONOTONIC
);
2436 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2439 union inotify_event_buffer buffer
;
2440 struct inotify_event
*e
;
2443 l
= read(j
->inotify_fd
, &buffer
, sizeof(buffer
));
2445 if (IN_SET(errno
, EAGAIN
, EINTR
))
2446 return got_something
? determine_change(j
) : SD_JOURNAL_NOP
;
2451 got_something
= true;
2453 FOREACH_INOTIFY_EVENT(e
, buffer
, l
)
2454 process_inotify_event(j
, e
);
2458 _public_
int sd_journal_wait(sd_journal
*j
, uint64_t timeout_usec
) {
2462 assert_return(j
, -EINVAL
);
2463 assert_return(!journal_pid_changed(j
), -ECHILD
);
2465 if (j
->inotify_fd
< 0) {
2467 /* This is the first invocation, hence create the
2469 r
= sd_journal_get_fd(j
);
2473 /* The journal might have changed since the context
2474 * object was created and we weren't watching before,
2475 * hence don't wait for anything, and return
2477 return determine_change(j
);
2480 r
= sd_journal_get_timeout(j
, &t
);
2484 if (t
!= (uint64_t) -1) {
2487 n
= now(CLOCK_MONOTONIC
);
2488 t
= t
> n
? t
- n
: 0;
2490 if (timeout_usec
== (uint64_t) -1 || timeout_usec
> t
)
2495 r
= fd_wait_for_event(j
->inotify_fd
, POLLIN
, timeout_usec
);
2496 } while (r
== -EINTR
);
2501 return sd_journal_process(j
);
2504 _public_
int sd_journal_get_cutoff_realtime_usec(sd_journal
*j
, uint64_t *from
, uint64_t *to
) {
2508 uint64_t fmin
= 0, tmax
= 0;
2511 assert_return(j
, -EINVAL
);
2512 assert_return(!journal_pid_changed(j
), -ECHILD
);
2513 assert_return(from
|| to
, -EINVAL
);
2514 assert_return(from
!= to
, -EINVAL
);
2516 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2519 r
= journal_file_get_cutoff_realtime_usec(f
, &fr
, &t
);
2532 fmin
= MIN(fr
, fmin
);
2533 tmax
= MAX(t
, tmax
);
2542 return first
? 0 : 1;
2545 _public_
int sd_journal_get_cutoff_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t *from
, uint64_t *to
) {
2551 assert_return(j
, -EINVAL
);
2552 assert_return(!journal_pid_changed(j
), -ECHILD
);
2553 assert_return(from
|| to
, -EINVAL
);
2554 assert_return(from
!= to
, -EINVAL
);
2556 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2559 r
= journal_file_get_cutoff_monotonic_usec(f
, boot_id
, &fr
, &t
);
2569 *from
= MIN(fr
, *from
);
2584 void journal_print_header(sd_journal
*j
) {
2587 bool newline
= false;
2591 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2597 journal_file_print_header(f
);
2601 _public_
int sd_journal_get_usage(sd_journal
*j
, uint64_t *bytes
) {
2606 assert_return(j
, -EINVAL
);
2607 assert_return(!journal_pid_changed(j
), -ECHILD
);
2608 assert_return(bytes
, -EINVAL
);
2610 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2613 if (fstat(f
->fd
, &st
) < 0)
2616 sum
+= (uint64_t) st
.st_blocks
* 512ULL;
2623 _public_
int sd_journal_query_unique(sd_journal
*j
, const char *field
) {
2626 assert_return(j
, -EINVAL
);
2627 assert_return(!journal_pid_changed(j
), -ECHILD
);
2628 assert_return(!isempty(field
), -EINVAL
);
2629 assert_return(field_is_valid(field
), -EINVAL
);
2635 free(j
->unique_field
);
2636 j
->unique_field
= f
;
2637 j
->unique_file
= NULL
;
2638 j
->unique_offset
= 0;
2639 j
->unique_file_lost
= false;
2644 _public_
int sd_journal_enumerate_unique(sd_journal
*j
, const void **data
, size_t *l
) {
2647 assert_return(j
, -EINVAL
);
2648 assert_return(!journal_pid_changed(j
), -ECHILD
);
2649 assert_return(data
, -EINVAL
);
2650 assert_return(l
, -EINVAL
);
2651 assert_return(j
->unique_field
, -EINVAL
);
2653 k
= strlen(j
->unique_field
);
2655 if (!j
->unique_file
) {
2656 if (j
->unique_file_lost
)
2659 j
->unique_file
= ordered_hashmap_first(j
->files
);
2660 if (!j
->unique_file
)
2663 j
->unique_offset
= 0;
2675 /* Proceed to next data object in the field's linked list */
2676 if (j
->unique_offset
== 0) {
2677 r
= journal_file_find_field_object(j
->unique_file
, j
->unique_field
, k
, &o
, NULL
);
2681 j
->unique_offset
= r
> 0 ? le64toh(o
->field
.head_data_offset
) : 0;
2683 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_DATA
, j
->unique_offset
, &o
);
2687 j
->unique_offset
= le64toh(o
->data
.next_field_offset
);
2690 /* We reached the end of the list? Then start again, with the next file */
2691 if (j
->unique_offset
== 0) {
2692 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
2693 if (!j
->unique_file
)
2699 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2700 * instead, so that we can look at this data object at the same
2701 * time as one on another file */
2702 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_UNUSED
, j
->unique_offset
, &o
);
2706 /* Let's do the type check by hand, since we used 0 context above. */
2707 if (o
->object
.type
!= OBJECT_DATA
) {
2708 log_debug("%s:offset " OFSfmt
": object has type %d, expected %d",
2709 j
->unique_file
->path
, j
->unique_offset
,
2710 o
->object
.type
, OBJECT_DATA
);
2714 r
= return_data(j
, j
->unique_file
, o
, &odata
, &ol
);
2718 /* Check if we have at least the field name and "=". */
2720 log_debug("%s:offset " OFSfmt
": object has size %zu, expected at least %zu",
2721 j
->unique_file
->path
, j
->unique_offset
,
2726 if (memcmp(odata
, j
->unique_field
, k
) || ((const char*) odata
)[k
] != '=') {
2727 log_debug("%s:offset " OFSfmt
": object does not start with \"%s=\"",
2728 j
->unique_file
->path
, j
->unique_offset
,
2733 /* OK, now let's see if we already returned this data
2734 * object by checking if it exists in the earlier
2735 * traversed files. */
2737 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2738 if (of
== j
->unique_file
)
2741 /* Skip this file it didn't have any fields indexed */
2742 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2745 r
= journal_file_find_data_object_with_hash(of
, odata
, ol
, le64toh(o
->data
.hash
), NULL
, NULL
);
2757 r
= return_data(j
, j
->unique_file
, o
, data
, l
);
2765 _public_
void sd_journal_restart_unique(sd_journal
*j
) {
2769 j
->unique_file
= NULL
;
2770 j
->unique_offset
= 0;
2771 j
->unique_file_lost
= false;
2774 _public_
int sd_journal_enumerate_fields(sd_journal
*j
, const char **field
) {
2777 assert_return(j
, -EINVAL
);
2778 assert_return(!journal_pid_changed(j
), -ECHILD
);
2779 assert_return(field
, -EINVAL
);
2781 if (!j
->fields_file
) {
2782 if (j
->fields_file_lost
)
2785 j
->fields_file
= ordered_hashmap_first(j
->files
);
2786 if (!j
->fields_file
)
2789 j
->fields_hash_table_index
= 0;
2790 j
->fields_offset
= 0;
2794 JournalFile
*f
, *of
;
2803 if (j
->fields_offset
== 0) {
2806 /* We are not yet positioned at any field. Let's pick the first one */
2807 r
= journal_file_map_field_hash_table(f
);
2811 m
= le64toh(f
->header
->field_hash_table_size
) / sizeof(HashItem
);
2813 if (j
->fields_hash_table_index
>= m
) {
2814 /* Reached the end of the hash table, go to the next file. */
2819 j
->fields_offset
= le64toh(f
->field_hash_table
[j
->fields_hash_table_index
].head_hash_offset
);
2821 if (j
->fields_offset
!= 0)
2824 /* Empty hash table bucket, go to next one */
2825 j
->fields_hash_table_index
++;
2829 /* Proceed with next file */
2830 j
->fields_file
= ordered_hashmap_next(j
->files
, f
->path
);
2831 if (!j
->fields_file
) {
2836 j
->fields_offset
= 0;
2837 j
->fields_hash_table_index
= 0;
2842 /* We are already positioned at a field. If so, let's figure out the next field from it */
2844 r
= journal_file_move_to_object(f
, OBJECT_FIELD
, j
->fields_offset
, &o
);
2848 j
->fields_offset
= le64toh(o
->field
.next_hash_offset
);
2849 if (j
->fields_offset
== 0) {
2850 /* Reached the end of the hash table chain */
2851 j
->fields_hash_table_index
++;
2856 /* We use OBJECT_UNUSED here, so that the iterator below doesn't remove our mmap window */
2857 r
= journal_file_move_to_object(f
, OBJECT_UNUSED
, j
->fields_offset
, &o
);
2861 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
2862 if (o
->object
.type
!= OBJECT_FIELD
) {
2863 log_debug("%s:offset " OFSfmt
": object has type %i, expected %i", f
->path
, j
->fields_offset
, o
->object
.type
, OBJECT_FIELD
);
2867 sz
= le64toh(o
->object
.size
) - offsetof(Object
, field
.payload
);
2869 /* Let's see if we already returned this field name before. */
2871 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2875 /* Skip this file it didn't have any fields indexed */
2876 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2879 r
= journal_file_find_field_object_with_hash(of
, o
->field
.payload
, sz
, le64toh(o
->field
.hash
), NULL
, NULL
);
2891 /* Check if this is really a valid string containing no NUL byte */
2892 if (memchr(o
->field
.payload
, 0, sz
))
2895 if (sz
> j
->data_threshold
)
2896 sz
= j
->data_threshold
;
2898 if (!GREEDY_REALLOC(j
->fields_buffer
, j
->fields_buffer_allocated
, sz
+ 1))
2901 memcpy(j
->fields_buffer
, o
->field
.payload
, sz
);
2902 j
->fields_buffer
[sz
] = 0;
2904 if (!field_is_valid(j
->fields_buffer
))
2907 *field
= j
->fields_buffer
;
2912 _public_
void sd_journal_restart_fields(sd_journal
*j
) {
2916 j
->fields_file
= NULL
;
2917 j
->fields_hash_table_index
= 0;
2918 j
->fields_offset
= 0;
2919 j
->fields_file_lost
= false;
2922 _public_
int sd_journal_reliable_fd(sd_journal
*j
) {
2923 assert_return(j
, -EINVAL
);
2924 assert_return(!journal_pid_changed(j
), -ECHILD
);
2926 return !j
->on_network
;
2929 static char *lookup_field(const char *field
, void *userdata
) {
2930 sd_journal
*j
= userdata
;
2938 r
= sd_journal_get_data(j
, field
, &data
, &size
);
2940 size
> REPLACE_VAR_MAX
)
2941 return strdup(field
);
2943 d
= strlen(field
) + 1;
2945 return strndup((const char*) data
+ d
, size
- d
);
2948 _public_
int sd_journal_get_catalog(sd_journal
*j
, char **ret
) {
2952 _cleanup_free_
char *text
= NULL
, *cid
= NULL
;
2956 assert_return(j
, -EINVAL
);
2957 assert_return(!journal_pid_changed(j
), -ECHILD
);
2958 assert_return(ret
, -EINVAL
);
2960 r
= sd_journal_get_data(j
, "MESSAGE_ID", &data
, &size
);
2964 cid
= strndup((const char*) data
+ 11, size
- 11);
2968 r
= sd_id128_from_string(cid
, &id
);
2972 r
= catalog_get(CATALOG_DATABASE
, id
, &text
);
2976 t
= replace_var(text
, lookup_field
, j
);
2984 _public_
int sd_journal_get_catalog_for_message_id(sd_id128_t id
, char **ret
) {
2985 assert_return(ret
, -EINVAL
);
2987 return catalog_get(CATALOG_DATABASE
, id
, ret
);
2990 _public_
int sd_journal_set_data_threshold(sd_journal
*j
, size_t sz
) {
2991 assert_return(j
, -EINVAL
);
2992 assert_return(!journal_pid_changed(j
), -ECHILD
);
2994 j
->data_threshold
= sz
;
2998 _public_
int sd_journal_get_data_threshold(sd_journal
*j
, size_t *sz
) {
2999 assert_return(j
, -EINVAL
);
3000 assert_return(!journal_pid_changed(j
), -ECHILD
);
3001 assert_return(sz
, -EINVAL
);
3003 *sz
= j
->data_threshold
;
3007 _public_
int sd_journal_has_runtime_files(sd_journal
*j
) {
3008 assert_return(j
, -EINVAL
);
3010 return j
->has_runtime_files
;
3013 _public_
int sd_journal_has_persistent_files(sd_journal
*j
) {
3014 assert_return(j
, -EINVAL
);
3016 return j
->has_persistent_files
;