2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/magic.h>
26 #include <sys/inotify.h>
30 #include "sd-journal.h"
32 #include "alloc-util.h"
35 #include "dirent-util.h"
38 #include "format-util.h"
41 #include "hostname-util.h"
43 #include "journal-def.h"
44 #include "journal-file.h"
45 #include "journal-internal.h"
49 #include "path-util.h"
50 #include "replace-var.h"
51 #include "stat-util.h"
52 #include "stdio-util.h"
53 #include "string-util.h"
56 #define JOURNAL_FILES_MAX 7168
58 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
60 #define REPLACE_VAR_MAX 256
62 #define DEFAULT_DATA_THRESHOLD (64*1024)
64 static void remove_file_real(sd_journal
*j
, JournalFile
*f
);
66 static bool journal_pid_changed(sd_journal
*j
) {
69 /* We don't support people creating a journal object and
70 * keeping it around over a fork(). Let's complain. */
72 return j
->original_pid
!= getpid_cached();
75 static int journal_put_error(sd_journal
*j
, int r
, const char *path
) {
79 /* Memorize an error we encountered, and store which
80 * file/directory it was generated from. Note that we store
81 * only *one* path per error code, as the error code is the
82 * key into the hashmap, and the path is the value. This means
83 * we keep track only of all error kinds, but not of all error
84 * locations. This has the benefit that the hashmap cannot
87 * We return an error here only if we didn't manage to
88 * memorize the real error. */
93 k
= hashmap_ensure_allocated(&j
->errors
, NULL
);
104 k
= hashmap_put(j
->errors
, INT_TO_PTR(r
), copy
);
117 static void detach_location(sd_journal
*j
) {
123 j
->current_file
= NULL
;
124 j
->current_field
= 0;
126 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
)
127 journal_file_reset_location(f
);
130 static void reset_location(sd_journal
*j
) {
134 zero(j
->current_location
);
137 static void init_location(Location
*l
, LocationType type
, JournalFile
*f
, Object
*o
) {
139 assert(IN_SET(type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
141 assert(o
->object
.type
== OBJECT_ENTRY
);
144 l
->seqnum
= le64toh(o
->entry
.seqnum
);
145 l
->seqnum_id
= f
->header
->seqnum_id
;
146 l
->realtime
= le64toh(o
->entry
.realtime
);
147 l
->monotonic
= le64toh(o
->entry
.monotonic
);
148 l
->boot_id
= o
->entry
.boot_id
;
149 l
->xor_hash
= le64toh(o
->entry
.xor_hash
);
151 l
->seqnum_set
= l
->realtime_set
= l
->monotonic_set
= l
->xor_hash_set
= true;
154 static void set_location(sd_journal
*j
, JournalFile
*f
, Object
*o
) {
159 init_location(&j
->current_location
, LOCATION_DISCRETE
, f
, o
);
162 j
->current_field
= 0;
164 /* Let f know its candidate entry was picked. */
165 assert(f
->location_type
== LOCATION_SEEK
);
166 f
->location_type
= LOCATION_DISCRETE
;
169 static int match_is_valid(const void *data
, size_t size
) {
177 if (startswith(data
, "__"))
181 for (p
= b
; p
< b
+ size
; p
++) {
189 if (*p
>= 'A' && *p
<= 'Z')
192 if (*p
>= '0' && *p
<= '9')
201 static bool same_field(const void *_a
, size_t s
, const void *_b
, size_t t
) {
202 const uint8_t *a
= _a
, *b
= _b
;
205 for (j
= 0; j
< s
&& j
< t
; j
++) {
214 assert_not_reached("\"=\" not found");
217 static Match
*match_new(Match
*p
, MatchType t
) {
228 LIST_PREPEND(matches
, p
->matches
, m
);
234 static void match_free(Match
*m
) {
238 match_free(m
->matches
);
241 LIST_REMOVE(matches
, m
->parent
->matches
, m
);
247 static void match_free_if_empty(Match
*m
) {
248 if (!m
|| m
->matches
)
254 _public_
int sd_journal_add_match(sd_journal
*j
, const void *data
, size_t size
) {
255 Match
*l3
, *l4
, *add_here
= NULL
, *m
;
258 assert_return(j
, -EINVAL
);
259 assert_return(!journal_pid_changed(j
), -ECHILD
);
260 assert_return(data
, -EINVAL
);
265 assert_return(match_is_valid(data
, size
), -EINVAL
);
271 * level 4: concrete matches */
274 j
->level0
= match_new(NULL
, MATCH_AND_TERM
);
280 j
->level1
= match_new(j
->level0
, MATCH_OR_TERM
);
286 j
->level2
= match_new(j
->level1
, MATCH_AND_TERM
);
291 assert(j
->level0
->type
== MATCH_AND_TERM
);
292 assert(j
->level1
->type
== MATCH_OR_TERM
);
293 assert(j
->level2
->type
== MATCH_AND_TERM
);
295 le_hash
= htole64(hash64(data
, size
));
297 LIST_FOREACH(matches
, l3
, j
->level2
->matches
) {
298 assert(l3
->type
== MATCH_OR_TERM
);
300 LIST_FOREACH(matches
, l4
, l3
->matches
) {
301 assert(l4
->type
== MATCH_DISCRETE
);
303 /* Exactly the same match already? Then ignore
305 if (l4
->le_hash
== le_hash
&&
307 memcmp(l4
->data
, data
, size
) == 0)
310 /* Same field? Then let's add this to this OR term */
311 if (same_field(data
, size
, l4
->data
, l4
->size
)) {
322 add_here
= match_new(j
->level2
, MATCH_OR_TERM
);
327 m
= match_new(add_here
, MATCH_DISCRETE
);
331 m
->le_hash
= le_hash
;
333 m
->data
= memdup(data
, size
);
342 match_free_if_empty(add_here
);
343 match_free_if_empty(j
->level2
);
344 match_free_if_empty(j
->level1
);
345 match_free_if_empty(j
->level0
);
350 _public_
int sd_journal_add_conjunction(sd_journal
*j
) {
351 assert_return(j
, -EINVAL
);
352 assert_return(!journal_pid_changed(j
), -ECHILD
);
360 if (!j
->level1
->matches
)
369 _public_
int sd_journal_add_disjunction(sd_journal
*j
) {
370 assert_return(j
, -EINVAL
);
371 assert_return(!journal_pid_changed(j
), -ECHILD
);
382 if (!j
->level2
->matches
)
389 static char *match_make_string(Match
*m
) {
392 bool enclose
= false;
395 return strdup("none");
397 if (m
->type
== MATCH_DISCRETE
)
398 return strndup(m
->data
, m
->size
);
400 LIST_FOREACH(matches
, i
, m
->matches
) {
403 t
= match_make_string(i
);
408 k
= strjoin(p
, m
->type
== MATCH_OR_TERM
? " OR " : " AND ", t
);
423 r
= strjoin("(", p
, ")");
431 char *journal_make_match_string(sd_journal
*j
) {
434 return match_make_string(j
->level0
);
437 _public_
void sd_journal_flush_matches(sd_journal
*j
) {
442 match_free(j
->level0
);
444 j
->level0
= j
->level1
= j
->level2
= NULL
;
449 _pure_
static int compare_with_location(JournalFile
*f
, Location
*l
) {
452 assert(f
->location_type
== LOCATION_SEEK
);
453 assert(IN_SET(l
->type
, LOCATION_DISCRETE
, LOCATION_SEEK
));
455 if (l
->monotonic_set
&&
456 sd_id128_equal(f
->current_boot_id
, l
->boot_id
) &&
458 f
->current_realtime
== l
->realtime
&&
460 f
->current_xor_hash
== l
->xor_hash
)
464 sd_id128_equal(f
->header
->seqnum_id
, l
->seqnum_id
)) {
466 if (f
->current_seqnum
< l
->seqnum
)
468 if (f
->current_seqnum
> l
->seqnum
)
472 if (l
->monotonic_set
&&
473 sd_id128_equal(f
->current_boot_id
, l
->boot_id
)) {
475 if (f
->current_monotonic
< l
->monotonic
)
477 if (f
->current_monotonic
> l
->monotonic
)
481 if (l
->realtime_set
) {
483 if (f
->current_realtime
< l
->realtime
)
485 if (f
->current_realtime
> l
->realtime
)
489 if (l
->xor_hash_set
) {
491 if (f
->current_xor_hash
< l
->xor_hash
)
493 if (f
->current_xor_hash
> l
->xor_hash
)
500 static int next_for_match(
504 uint64_t after_offset
,
505 direction_t direction
,
517 if (m
->type
== MATCH_DISCRETE
) {
520 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
524 return journal_file_move_to_entry_by_offset_for_data(f
, dp
, after_offset
, direction
, ret
, offset
);
526 } else if (m
->type
== MATCH_OR_TERM
) {
529 /* Find the earliest match beyond after_offset */
531 LIST_FOREACH(matches
, i
, m
->matches
) {
534 r
= next_for_match(j
, i
, f
, after_offset
, direction
, NULL
, &cp
);
538 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
< np
: cp
> np
))
546 } else if (m
->type
== MATCH_AND_TERM
) {
547 Match
*i
, *last_moved
;
549 /* Always jump to the next matching entry and repeat
550 * this until we find an offset that matches for all
556 r
= next_for_match(j
, m
->matches
, f
, after_offset
, direction
, NULL
, &np
);
560 assert(direction
== DIRECTION_DOWN
? np
>= after_offset
: np
<= after_offset
);
561 last_moved
= m
->matches
;
563 LIST_LOOP_BUT_ONE(matches
, i
, m
->matches
, last_moved
) {
566 r
= next_for_match(j
, i
, f
, np
, direction
, NULL
, &cp
);
570 assert(direction
== DIRECTION_DOWN
? cp
>= np
: cp
<= np
);
571 if (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
) {
580 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
592 static int find_location_for_match(
596 direction_t direction
,
606 if (m
->type
== MATCH_DISCRETE
) {
609 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
613 /* FIXME: missing: find by monotonic */
615 if (j
->current_location
.type
== LOCATION_HEAD
)
616 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_DOWN
, ret
, offset
);
617 if (j
->current_location
.type
== LOCATION_TAIL
)
618 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_UP
, ret
, offset
);
619 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
620 return journal_file_move_to_entry_by_seqnum_for_data(f
, dp
, j
->current_location
.seqnum
, direction
, ret
, offset
);
621 if (j
->current_location
.monotonic_set
) {
622 r
= journal_file_move_to_entry_by_monotonic_for_data(f
, dp
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
626 if (j
->current_location
.realtime_set
)
627 return journal_file_move_to_entry_by_realtime_for_data(f
, dp
, j
->current_location
.realtime
, direction
, ret
, offset
);
629 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, direction
, ret
, offset
);
631 } else if (m
->type
== MATCH_OR_TERM
) {
636 /* Find the earliest match */
638 LIST_FOREACH(matches
, i
, m
->matches
) {
641 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
645 if (np
== 0 || (direction
== DIRECTION_DOWN
? np
> cp
: np
< cp
))
653 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
668 assert(m
->type
== MATCH_AND_TERM
);
670 /* First jump to the last match, and then find the
671 * next one where all matches match */
676 LIST_FOREACH(matches
, i
, m
->matches
) {
679 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
683 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
))
687 return next_for_match(j
, m
, f
, np
, direction
, ret
, offset
);
691 static int find_location_with_matches(
694 direction_t direction
,
706 /* No matches is simple */
708 if (j
->current_location
.type
== LOCATION_HEAD
)
709 return journal_file_next_entry(f
, 0, DIRECTION_DOWN
, ret
, offset
);
710 if (j
->current_location
.type
== LOCATION_TAIL
)
711 return journal_file_next_entry(f
, 0, DIRECTION_UP
, ret
, offset
);
712 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
713 return journal_file_move_to_entry_by_seqnum(f
, j
->current_location
.seqnum
, direction
, ret
, offset
);
714 if (j
->current_location
.monotonic_set
) {
715 r
= journal_file_move_to_entry_by_monotonic(f
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
719 if (j
->current_location
.realtime_set
)
720 return journal_file_move_to_entry_by_realtime(f
, j
->current_location
.realtime
, direction
, ret
, offset
);
722 return journal_file_next_entry(f
, 0, direction
, ret
, offset
);
724 return find_location_for_match(j
, j
->level0
, f
, direction
, ret
, offset
);
727 static int next_with_matches(
730 direction_t direction
,
739 /* No matches is easy. We simple advance the file
742 return journal_file_next_entry(f
, f
->current_offset
, direction
, ret
, offset
);
744 /* If we have a match then we look for the next matching entry
745 * with an offset at least one step larger */
746 return next_for_match(j
, j
->level0
, f
,
747 direction
== DIRECTION_DOWN
? f
->current_offset
+ 1
748 : f
->current_offset
- 1,
749 direction
, ret
, offset
);
752 static int next_beyond_location(sd_journal
*j
, JournalFile
*f
, direction_t direction
) {
754 uint64_t cp
, n_entries
;
760 n_entries
= le64toh(f
->header
->n_entries
);
762 /* If we hit EOF before, we don't need to look into this file again
763 * unless direction changed or new entries appeared. */
764 if (f
->last_direction
== direction
&& f
->location_type
== LOCATION_TAIL
&&
765 n_entries
== f
->last_n_entries
)
768 f
->last_n_entries
= n_entries
;
770 if (f
->last_direction
== direction
&& f
->current_offset
> 0) {
771 /* LOCATION_SEEK here means we did the work in a previous
772 * iteration and the current location already points to a
773 * candidate entry. */
774 if (f
->location_type
!= LOCATION_SEEK
) {
775 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
779 journal_file_save_location(f
, c
, cp
);
782 f
->last_direction
= direction
;
784 r
= find_location_with_matches(j
, f
, direction
, &c
, &cp
);
788 journal_file_save_location(f
, c
, cp
);
791 /* OK, we found the spot, now let's advance until an entry
792 * that is actually different from what we were previously
793 * looking at. This is necessary to handle entries which exist
794 * in two (or more) journal files, and which shall all be
795 * suppressed but one. */
800 if (j
->current_location
.type
== LOCATION_DISCRETE
) {
803 k
= compare_with_location(f
, &j
->current_location
);
805 found
= direction
== DIRECTION_DOWN
? k
> 0 : k
< 0;
812 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
816 journal_file_save_location(f
, c
, cp
);
820 static int real_journal_next(sd_journal
*j
, direction_t direction
) {
821 JournalFile
*f
, *new_file
= NULL
;
826 assert_return(j
, -EINVAL
);
827 assert_return(!journal_pid_changed(j
), -ECHILD
);
829 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
832 r
= next_beyond_location(j
, f
, direction
);
834 log_debug_errno(r
, "Can't iterate through %s, ignoring: %m", f
->path
);
835 remove_file_real(j
, f
);
838 f
->location_type
= LOCATION_TAIL
;
847 k
= journal_file_compare_locations(f
, new_file
);
849 found
= direction
== DIRECTION_DOWN
? k
< 0 : k
> 0;
859 r
= journal_file_move_to_object(new_file
, OBJECT_ENTRY
, new_file
->current_offset
, &o
);
863 set_location(j
, new_file
, o
);
868 _public_
int sd_journal_next(sd_journal
*j
) {
869 return real_journal_next(j
, DIRECTION_DOWN
);
872 _public_
int sd_journal_previous(sd_journal
*j
) {
873 return real_journal_next(j
, DIRECTION_UP
);
876 static int real_journal_next_skip(sd_journal
*j
, direction_t direction
, uint64_t skip
) {
879 assert_return(j
, -EINVAL
);
880 assert_return(!journal_pid_changed(j
), -ECHILD
);
883 /* If this is not a discrete skip, then at least
884 * resolve the current location */
885 if (j
->current_location
.type
!= LOCATION_DISCRETE
) {
886 r
= real_journal_next(j
, direction
);
895 r
= real_journal_next(j
, direction
);
909 _public_
int sd_journal_next_skip(sd_journal
*j
, uint64_t skip
) {
910 return real_journal_next_skip(j
, DIRECTION_DOWN
, skip
);
913 _public_
int sd_journal_previous_skip(sd_journal
*j
, uint64_t skip
) {
914 return real_journal_next_skip(j
, DIRECTION_UP
, skip
);
917 _public_
int sd_journal_get_cursor(sd_journal
*j
, char **cursor
) {
920 char bid
[33], sid
[33];
922 assert_return(j
, -EINVAL
);
923 assert_return(!journal_pid_changed(j
), -ECHILD
);
924 assert_return(cursor
, -EINVAL
);
926 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
927 return -EADDRNOTAVAIL
;
929 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
933 sd_id128_to_string(j
->current_file
->header
->seqnum_id
, sid
);
934 sd_id128_to_string(o
->entry
.boot_id
, bid
);
937 "s=%s;i=%"PRIx64
";b=%s;m=%"PRIx64
";t=%"PRIx64
";x=%"PRIx64
,
938 sid
, le64toh(o
->entry
.seqnum
),
939 bid
, le64toh(o
->entry
.monotonic
),
940 le64toh(o
->entry
.realtime
),
941 le64toh(o
->entry
.xor_hash
)) < 0)
947 _public_
int sd_journal_seek_cursor(sd_journal
*j
, const char *cursor
) {
948 const char *word
, *state
;
950 unsigned long long seqnum
, monotonic
, realtime
, xor_hash
;
952 seqnum_id_set
= false,
955 monotonic_set
= false,
956 realtime_set
= false,
957 xor_hash_set
= false;
958 sd_id128_t seqnum_id
, boot_id
;
960 assert_return(j
, -EINVAL
);
961 assert_return(!journal_pid_changed(j
), -ECHILD
);
962 assert_return(!isempty(cursor
), -EINVAL
);
964 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
968 if (l
< 2 || word
[1] != '=')
971 item
= strndup(word
, l
);
978 seqnum_id_set
= true;
979 k
= sd_id128_from_string(item
+2, &seqnum_id
);
984 if (sscanf(item
+2, "%llx", &seqnum
) != 1)
990 k
= sd_id128_from_string(item
+2, &boot_id
);
994 monotonic_set
= true;
995 if (sscanf(item
+2, "%llx", &monotonic
) != 1)
1000 realtime_set
= true;
1001 if (sscanf(item
+2, "%llx", &realtime
) != 1)
1006 xor_hash_set
= true;
1007 if (sscanf(item
+2, "%llx", &xor_hash
) != 1)
1018 if ((!seqnum_set
|| !seqnum_id_set
) &&
1019 (!monotonic_set
|| !boot_id_set
) &&
1025 j
->current_location
.type
= LOCATION_SEEK
;
1028 j
->current_location
.realtime
= (uint64_t) realtime
;
1029 j
->current_location
.realtime_set
= true;
1032 if (seqnum_set
&& seqnum_id_set
) {
1033 j
->current_location
.seqnum
= (uint64_t) seqnum
;
1034 j
->current_location
.seqnum_id
= seqnum_id
;
1035 j
->current_location
.seqnum_set
= true;
1038 if (monotonic_set
&& boot_id_set
) {
1039 j
->current_location
.monotonic
= (uint64_t) monotonic
;
1040 j
->current_location
.boot_id
= boot_id
;
1041 j
->current_location
.monotonic_set
= true;
1045 j
->current_location
.xor_hash
= (uint64_t) xor_hash
;
1046 j
->current_location
.xor_hash_set
= true;
1052 _public_
int sd_journal_test_cursor(sd_journal
*j
, const char *cursor
) {
1056 assert_return(j
, -EINVAL
);
1057 assert_return(!journal_pid_changed(j
), -ECHILD
);
1058 assert_return(!isempty(cursor
), -EINVAL
);
1060 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
1061 return -EADDRNOTAVAIL
;
1063 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
1068 _cleanup_free_
char *item
= NULL
;
1069 unsigned long long ll
;
1073 r
= extract_first_word(&cursor
, &item
, ";", EXTRACT_DONT_COALESCE_SEPARATORS
);
1080 if (strlen(item
) < 2 || item
[1] != '=')
1086 k
= sd_id128_from_string(item
+2, &id
);
1089 if (!sd_id128_equal(id
, j
->current_file
->header
->seqnum_id
))
1094 if (sscanf(item
+2, "%llx", &ll
) != 1)
1096 if (ll
!= le64toh(o
->entry
.seqnum
))
1101 k
= sd_id128_from_string(item
+2, &id
);
1104 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1109 if (sscanf(item
+2, "%llx", &ll
) != 1)
1111 if (ll
!= le64toh(o
->entry
.monotonic
))
1116 if (sscanf(item
+2, "%llx", &ll
) != 1)
1118 if (ll
!= le64toh(o
->entry
.realtime
))
1123 if (sscanf(item
+2, "%llx", &ll
) != 1)
1125 if (ll
!= le64toh(o
->entry
.xor_hash
))
1135 _public_
int sd_journal_seek_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t usec
) {
1136 assert_return(j
, -EINVAL
);
1137 assert_return(!journal_pid_changed(j
), -ECHILD
);
1140 j
->current_location
.type
= LOCATION_SEEK
;
1141 j
->current_location
.boot_id
= boot_id
;
1142 j
->current_location
.monotonic
= usec
;
1143 j
->current_location
.monotonic_set
= true;
1148 _public_
int sd_journal_seek_realtime_usec(sd_journal
*j
, uint64_t usec
) {
1149 assert_return(j
, -EINVAL
);
1150 assert_return(!journal_pid_changed(j
), -ECHILD
);
1153 j
->current_location
.type
= LOCATION_SEEK
;
1154 j
->current_location
.realtime
= usec
;
1155 j
->current_location
.realtime_set
= true;
1160 _public_
int sd_journal_seek_head(sd_journal
*j
) {
1161 assert_return(j
, -EINVAL
);
1162 assert_return(!journal_pid_changed(j
), -ECHILD
);
1165 j
->current_location
.type
= LOCATION_HEAD
;
1170 _public_
int sd_journal_seek_tail(sd_journal
*j
) {
1171 assert_return(j
, -EINVAL
);
1172 assert_return(!journal_pid_changed(j
), -ECHILD
);
1175 j
->current_location
.type
= LOCATION_TAIL
;
1180 static void check_network(sd_journal
*j
, int fd
) {
1188 if (fstatfs(fd
, &sfs
) < 0)
1192 F_TYPE_EQUAL(sfs
.f_type
, CIFS_MAGIC_NUMBER
) ||
1193 F_TYPE_EQUAL(sfs
.f_type
, CODA_SUPER_MAGIC
) ||
1194 F_TYPE_EQUAL(sfs
.f_type
, NCP_SUPER_MAGIC
) ||
1195 F_TYPE_EQUAL(sfs
.f_type
, NFS_SUPER_MAGIC
) ||
1196 F_TYPE_EQUAL(sfs
.f_type
, SMB_SUPER_MAGIC
);
1199 static bool file_has_type_prefix(const char *prefix
, const char *filename
) {
1200 const char *full
, *tilded
, *atted
;
1202 full
= strjoina(prefix
, ".journal");
1203 tilded
= strjoina(full
, "~");
1204 atted
= strjoina(prefix
, "@");
1206 return streq(filename
, full
) ||
1207 streq(filename
, tilded
) ||
1208 startswith(filename
, atted
);
1211 static bool file_type_wanted(int flags
, const char *filename
) {
1214 if (!endswith(filename
, ".journal") && !endswith(filename
, ".journal~"))
1217 /* no flags set → every type is OK */
1218 if (!(flags
& (SD_JOURNAL_SYSTEM
| SD_JOURNAL_CURRENT_USER
)))
1221 if (flags
& SD_JOURNAL_SYSTEM
&& file_has_type_prefix("system", filename
))
1224 if (flags
& SD_JOURNAL_CURRENT_USER
) {
1225 char prefix
[5 + DECIMAL_STR_MAX(uid_t
) + 1];
1227 xsprintf(prefix
, "user-"UID_FMT
, getuid());
1229 if (file_has_type_prefix(prefix
, filename
))
1236 static bool path_has_prefix(sd_journal
*j
, const char *path
, const char *prefix
) {
1241 if (j
->toplevel_fd
>= 0)
1244 return path_startswith(path
, prefix
);
1247 static const char *skip_slash(const char *p
) {
1258 static int add_any_file(sd_journal
*j
, int fd
, const char *path
) {
1259 JournalFile
*f
= NULL
;
1260 bool close_fd
= false;
1264 assert(fd
>= 0 || path
);
1266 if (path
&& ordered_hashmap_get(j
->files
, path
))
1269 if (ordered_hashmap_size(j
->files
) >= JOURNAL_FILES_MAX
) {
1270 log_debug("Too many open journal files, not adding %s.", path
);
1275 if (fd
< 0 && j
->toplevel_fd
>= 0) {
1277 /* If there's a top-level fd defined, open the file relative to this now. (Make the path relative,
1278 * explicitly, since otherwise openat() ignores the first argument.) */
1280 fd
= openat(j
->toplevel_fd
, skip_slash(path
), O_RDONLY
|O_CLOEXEC
);
1282 r
= log_debug_errno(errno
, "Failed to open journal file %s: %m", path
);
1289 r
= journal_file_open(fd
, path
, O_RDONLY
, 0, false, false, NULL
, j
->mmap
, NULL
, NULL
, &f
);
1293 log_debug_errno(r
, "Failed to open journal file %s: %m", path
);
1297 /* journal_file_dump(f); */
1299 r
= ordered_hashmap_put(j
->files
, f
->path
, f
);
1301 f
->close_fd
= close_fd
;
1302 (void) journal_file_close(f
);
1306 if (!j
->has_runtime_files
&& path_has_prefix(j
, f
->path
, "/run"))
1307 j
->has_runtime_files
= true;
1308 else if (!j
->has_persistent_files
&& path_has_prefix(j
, f
->path
, "/var"))
1309 j
->has_persistent_files
= true;
1311 log_debug("File %s added.", f
->path
);
1313 check_network(j
, f
->fd
);
1315 j
->current_invalidate_counter
++;
1320 k
= journal_put_error(j
, r
, path
);
1327 static int add_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1334 if (j
->no_new_files
)
1337 if (!file_type_wanted(j
->flags
, filename
))
1340 path
= strjoina(prefix
, "/", filename
);
1341 return add_any_file(j
, -1, path
);
1344 static void remove_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1352 path
= strjoina(prefix
, "/", filename
);
1353 f
= ordered_hashmap_get(j
->files
, path
);
1357 remove_file_real(j
, f
);
1360 static void remove_file_real(sd_journal
*j
, JournalFile
*f
) {
1364 ordered_hashmap_remove(j
->files
, f
->path
);
1366 log_debug("File %s removed.", f
->path
);
1368 if (j
->current_file
== f
) {
1369 j
->current_file
= NULL
;
1370 j
->current_field
= 0;
1373 if (j
->unique_file
== f
) {
1374 /* Jump to the next unique_file or NULL if that one was last */
1375 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
1376 j
->unique_offset
= 0;
1377 if (!j
->unique_file
)
1378 j
->unique_file_lost
= true;
1381 if (j
->fields_file
== f
) {
1382 j
->fields_file
= ordered_hashmap_next(j
->files
, j
->fields_file
->path
);
1383 j
->fields_offset
= 0;
1384 if (!j
->fields_file
)
1385 j
->fields_file_lost
= true;
1388 (void) journal_file_close(f
);
1390 j
->current_invalidate_counter
++;
1393 static int dirname_is_machine_id(const char *fn
) {
1394 sd_id128_t id
, machine
;
1397 r
= sd_id128_get_machine(&machine
);
1401 r
= sd_id128_from_string(fn
, &id
);
1405 return sd_id128_equal(id
, machine
);
1408 static int add_directory(sd_journal
*j
, const char *prefix
, const char *dirname
) {
1409 _cleanup_free_
char *path
= NULL
;
1410 _cleanup_closedir_
DIR *d
= NULL
;
1411 struct dirent
*de
= NULL
;
1418 /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
1419 * and reenumerates directory contents */
1422 path
= strjoin(prefix
, "/", dirname
);
1424 path
= strdup(prefix
);
1430 log_debug("Considering directory %s.", path
);
1432 /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
1433 if ((j
->flags
& SD_JOURNAL_LOCAL_ONLY
) &&
1434 !((dirname
&& dirname_is_machine_id(dirname
) > 0) || path_has_prefix(j
, path
, "/run")))
1438 if (j
->toplevel_fd
< 0)
1441 /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
1442 * relative, by dropping the initial slash */
1443 d
= xopendirat(j
->toplevel_fd
, skip_slash(path
), 0);
1445 r
= log_debug_errno(errno
, "Failed to open directory %s: %m", path
);
1449 m
= hashmap_get(j
->directories_by_path
, path
);
1451 m
= new0(Directory
, 1);
1460 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1466 path
= NULL
; /* avoid freeing in cleanup */
1467 j
->current_invalidate_counter
++;
1469 log_debug("Directory %s added.", m
->path
);
1471 } else if (m
->is_root
)
1474 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1475 /* Watch this directory, if it not being watched yet. */
1477 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1478 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1479 IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
|IN_MOVED_FROM
|
1482 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1483 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1486 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
1488 if (dirent_is_file_with_suffix(de
, ".journal") ||
1489 dirent_is_file_with_suffix(de
, ".journal~"))
1490 (void) add_file(j
, m
->path
, de
->d_name
);
1493 check_network(j
, dirfd(d
));
1498 k
= journal_put_error(j
, r
, path
?: prefix
);
1505 static int add_root_directory(sd_journal
*j
, const char *p
, bool missing_ok
) {
1507 _cleanup_closedir_
DIR *d
= NULL
;
1514 /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
1515 * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
1516 * populate the set, as well as to update it later. */
1519 /* If there's a path specified, use it. */
1521 if ((j
->flags
& SD_JOURNAL_RUNTIME_ONLY
) &&
1522 !path_has_prefix(j
, p
, "/run"))
1526 p
= strjoina(j
->prefix
, p
);
1528 if (j
->toplevel_fd
< 0)
1531 d
= xopendirat(j
->toplevel_fd
, skip_slash(p
), 0);
1534 if (errno
== ENOENT
&& missing_ok
)
1537 r
= log_debug_errno(errno
, "Failed to open root directory %s: %m", p
);
1543 /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
1544 * opendir() will take possession of the fd, and close it, which we don't want. */
1546 p
= "."; /* store this as "." in the directories hashmap */
1548 dfd
= fcntl(j
->toplevel_fd
, F_DUPFD_CLOEXEC
, 3);
1564 m
= hashmap_get(j
->directories_by_path
, p
);
1566 m
= new0(Directory
, 1);
1574 m
->path
= strdup(p
);
1581 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1588 j
->current_invalidate_counter
++;
1590 log_debug("Root directory %s added.", m
->path
);
1592 } else if (!m
->is_root
)
1595 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1597 m
->wd
= inotify_add_watch_fd(j
->inotify_fd
, dirfd(d
),
1598 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1601 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1602 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1605 if (j
->no_new_files
)
1608 FOREACH_DIRENT_ALL(de
, d
, r
= log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
); goto fail
) {
1611 if (dirent_is_file_with_suffix(de
, ".journal") ||
1612 dirent_is_file_with_suffix(de
, ".journal~"))
1613 (void) add_file(j
, m
->path
, de
->d_name
);
1614 else if (IN_SET(de
->d_type
, DT_DIR
, DT_LNK
, DT_UNKNOWN
) &&
1615 sd_id128_from_string(de
->d_name
, &id
) >= 0)
1616 (void) add_directory(j
, m
->path
, de
->d_name
);
1619 check_network(j
, dirfd(d
));
1624 k
= journal_put_error(j
, r
, p
);
1631 static void remove_directory(sd_journal
*j
, Directory
*d
) {
1635 hashmap_remove(j
->directories_by_wd
, INT_TO_PTR(d
->wd
));
1637 if (j
->inotify_fd
>= 0)
1638 inotify_rm_watch(j
->inotify_fd
, d
->wd
);
1641 hashmap_remove(j
->directories_by_path
, d
->path
);
1644 log_debug("Root directory %s removed.", d
->path
);
1646 log_debug("Directory %s removed.", d
->path
);
1652 static int add_search_paths(sd_journal
*j
) {
1654 static const char search_paths
[] =
1655 "/run/log/journal\0"
1656 "/var/log/journal\0";
1661 /* We ignore most errors here, since the idea is to only open
1662 * what's actually accessible, and ignore the rest. */
1664 NULSTR_FOREACH(p
, search_paths
)
1665 (void) add_root_directory(j
, p
, true);
1667 if (!(j
->flags
& SD_JOURNAL_LOCAL_ONLY
))
1668 (void) add_root_directory(j
, "/var/log/journal/remote", true);
1673 static int add_current_paths(sd_journal
*j
) {
1678 assert(j
->no_new_files
);
1680 /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
1681 * treat them as fatal. */
1683 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1684 _cleanup_free_
char *dir
;
1687 dir
= dirname_malloc(f
->path
);
1691 r
= add_directory(j
, dir
, NULL
);
1699 static int allocate_inotify(sd_journal
*j
) {
1702 if (j
->inotify_fd
< 0) {
1703 j
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1704 if (j
->inotify_fd
< 0)
1708 return hashmap_ensure_allocated(&j
->directories_by_wd
, NULL
);
1711 static sd_journal
*journal_new(int flags
, const char *path
) {
1714 j
= new0(sd_journal
, 1);
1718 j
->original_pid
= getpid_cached();
1719 j
->toplevel_fd
= -1;
1722 j
->data_threshold
= DEFAULT_DATA_THRESHOLD
;
1731 if (flags
& SD_JOURNAL_OS_ROOT
)
1737 j
->files
= ordered_hashmap_new(&string_hash_ops
);
1738 j
->directories_by_path
= hashmap_new(&string_hash_ops
);
1739 j
->mmap
= mmap_cache_new();
1740 if (!j
->files
|| !j
->directories_by_path
|| !j
->mmap
)
1746 sd_journal_close(j
);
1750 #define OPEN_ALLOWED_FLAGS \
1751 (SD_JOURNAL_LOCAL_ONLY | \
1752 SD_JOURNAL_RUNTIME_ONLY | \
1753 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)
1755 _public_
int sd_journal_open(sd_journal
**ret
, int flags
) {
1759 assert_return(ret
, -EINVAL
);
1760 assert_return((flags
& ~OPEN_ALLOWED_FLAGS
) == 0, -EINVAL
);
1762 j
= journal_new(flags
, NULL
);
1766 r
= add_search_paths(j
);
1774 sd_journal_close(j
);
1779 #define OPEN_CONTAINER_ALLOWED_FLAGS \
1780 (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
1782 _public_
int sd_journal_open_container(sd_journal
**ret
, const char *machine
, int flags
) {
1783 _cleanup_free_
char *root
= NULL
, *class = NULL
;
1788 /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
1789 * combination with sd_journal_open_directory_fd(). */
1791 assert_return(machine
, -EINVAL
);
1792 assert_return(ret
, -EINVAL
);
1793 assert_return((flags
& ~OPEN_CONTAINER_ALLOWED_FLAGS
) == 0, -EINVAL
);
1794 assert_return(machine_name_is_valid(machine
), -EINVAL
);
1796 p
= strjoina("/run/systemd/machines/", machine
);
1797 r
= parse_env_file(p
, NEWLINE
, "ROOT", &root
, "CLASS", &class, NULL
);
1805 if (!streq_ptr(class, "container"))
1808 j
= journal_new(flags
, root
);
1812 r
= add_search_paths(j
);
1820 sd_journal_close(j
);
1824 #define OPEN_DIRECTORY_ALLOWED_FLAGS \
1825 (SD_JOURNAL_OS_ROOT | \
1826 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1828 _public_
int sd_journal_open_directory(sd_journal
**ret
, const char *path
, int flags
) {
1832 assert_return(ret
, -EINVAL
);
1833 assert_return(path
, -EINVAL
);
1834 assert_return((flags
& ~OPEN_DIRECTORY_ALLOWED_FLAGS
) == 0, -EINVAL
);
1836 j
= journal_new(flags
, path
);
1840 if (flags
& SD_JOURNAL_OS_ROOT
)
1841 r
= add_search_paths(j
);
1843 r
= add_root_directory(j
, path
, false);
1851 sd_journal_close(j
);
1855 _public_
int sd_journal_open_files(sd_journal
**ret
, const char **paths
, int flags
) {
1860 assert_return(ret
, -EINVAL
);
1861 assert_return(flags
== 0, -EINVAL
);
1863 j
= journal_new(flags
, NULL
);
1867 STRV_FOREACH(path
, paths
) {
1868 r
= add_any_file(j
, -1, *path
);
1873 j
->no_new_files
= true;
1879 sd_journal_close(j
);
1883 #define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
1884 (SD_JOURNAL_OS_ROOT | \
1885 SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
1887 _public_
int sd_journal_open_directory_fd(sd_journal
**ret
, int fd
, int flags
) {
1892 assert_return(ret
, -EINVAL
);
1893 assert_return(fd
>= 0, -EBADF
);
1894 assert_return((flags
& ~OPEN_DIRECTORY_FD_ALLOWED_FLAGS
) == 0, -EINVAL
);
1896 if (fstat(fd
, &st
) < 0)
1899 if (!S_ISDIR(st
.st_mode
))
1902 j
= journal_new(flags
, NULL
);
1906 j
->toplevel_fd
= fd
;
1908 if (flags
& SD_JOURNAL_OS_ROOT
)
1909 r
= add_search_paths(j
);
1911 r
= add_root_directory(j
, NULL
, false);
1919 sd_journal_close(j
);
1923 _public_
int sd_journal_open_files_fd(sd_journal
**ret
, int fds
[], unsigned n_fds
, int flags
) {
1930 assert_return(ret
, -EINVAL
);
1931 assert_return(n_fds
> 0, -EBADF
);
1932 assert_return(flags
== 0, -EINVAL
);
1934 j
= journal_new(flags
, NULL
);
1938 for (i
= 0; i
< n_fds
; i
++) {
1946 if (fstat(fds
[i
], &st
) < 0) {
1951 if (!S_ISREG(st
.st_mode
)) {
1956 r
= add_any_file(j
, fds
[i
], NULL
);
1961 j
->no_new_files
= true;
1962 j
->no_inotify
= true;
1968 /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
1970 ORDERED_HASHMAP_FOREACH(f
, j
->files
, iterator
)
1971 f
->close_fd
= false;
1973 sd_journal_close(j
);
1977 _public_
void sd_journal_close(sd_journal
*j
) {
1985 sd_journal_flush_matches(j
);
1987 while ((f
= ordered_hashmap_steal_first(j
->files
)))
1988 (void) journal_file_close(f
);
1990 ordered_hashmap_free(j
->files
);
1992 while ((d
= hashmap_first(j
->directories_by_path
)))
1993 remove_directory(j
, d
);
1995 while ((d
= hashmap_first(j
->directories_by_wd
)))
1996 remove_directory(j
, d
);
1998 hashmap_free(j
->directories_by_path
);
1999 hashmap_free(j
->directories_by_wd
);
2001 safe_close(j
->inotify_fd
);
2004 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j
->mmap
), mmap_cache_get_missed(j
->mmap
));
2005 mmap_cache_unref(j
->mmap
);
2008 while ((p
= hashmap_steal_first(j
->errors
)))
2010 hashmap_free(j
->errors
);
2014 free(j
->unique_field
);
2015 free(j
->fields_buffer
);
2019 _public_
int sd_journal_get_realtime_usec(sd_journal
*j
, uint64_t *ret
) {
2024 assert_return(j
, -EINVAL
);
2025 assert_return(!journal_pid_changed(j
), -ECHILD
);
2026 assert_return(ret
, -EINVAL
);
2028 f
= j
->current_file
;
2030 return -EADDRNOTAVAIL
;
2032 if (f
->current_offset
<= 0)
2033 return -EADDRNOTAVAIL
;
2035 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2039 *ret
= le64toh(o
->entry
.realtime
);
2043 _public_
int sd_journal_get_monotonic_usec(sd_journal
*j
, uint64_t *ret
, sd_id128_t
*ret_boot_id
) {
2049 assert_return(j
, -EINVAL
);
2050 assert_return(!journal_pid_changed(j
), -ECHILD
);
2052 f
= j
->current_file
;
2054 return -EADDRNOTAVAIL
;
2056 if (f
->current_offset
<= 0)
2057 return -EADDRNOTAVAIL
;
2059 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2064 *ret_boot_id
= o
->entry
.boot_id
;
2066 r
= sd_id128_get_boot(&id
);
2070 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
2075 *ret
= le64toh(o
->entry
.monotonic
);
2080 static bool field_is_valid(const char *field
) {
2088 if (startswith(field
, "__"))
2091 for (p
= field
; *p
; p
++) {
2096 if (*p
>= 'A' && *p
<= 'Z')
2099 if (*p
>= '0' && *p
<= '9')
2108 _public_
int sd_journal_get_data(sd_journal
*j
, const char *field
, const void **data
, size_t *size
) {
2111 size_t field_length
;
2115 assert_return(j
, -EINVAL
);
2116 assert_return(!journal_pid_changed(j
), -ECHILD
);
2117 assert_return(field
, -EINVAL
);
2118 assert_return(data
, -EINVAL
);
2119 assert_return(size
, -EINVAL
);
2120 assert_return(field_is_valid(field
), -EINVAL
);
2122 f
= j
->current_file
;
2124 return -EADDRNOTAVAIL
;
2126 if (f
->current_offset
<= 0)
2127 return -EADDRNOTAVAIL
;
2129 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2133 field_length
= strlen(field
);
2135 n
= journal_file_entry_n_items(o
);
2136 for (i
= 0; i
< n
; i
++) {
2142 p
= le64toh(o
->entry
.items
[i
].object_offset
);
2143 le_hash
= o
->entry
.items
[i
].hash
;
2144 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2148 if (le_hash
!= o
->data
.hash
)
2151 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2153 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2155 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
2156 r
= decompress_startswith(compression
,
2158 &f
->compress_buffer
, &f
->compress_buffer_size
,
2159 field
, field_length
, '=');
2161 log_debug_errno(r
, "Cannot decompress %s object of length %"PRIu64
" at offset "OFSfmt
": %m",
2162 object_compressed_to_string(compression
), l
, p
);
2167 r
= decompress_blob(compression
,
2169 &f
->compress_buffer
, &f
->compress_buffer_size
, &rsize
,
2174 *data
= f
->compress_buffer
;
2175 *size
= (size_t) rsize
;
2180 return -EPROTONOSUPPORT
;
2182 } else if (l
>= field_length
+1 &&
2183 memcmp(o
->data
.payload
, field
, field_length
) == 0 &&
2184 o
->data
.payload
[field_length
] == '=') {
2188 if ((uint64_t) t
!= l
)
2191 *data
= o
->data
.payload
;
2197 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2205 static int return_data(sd_journal
*j
, JournalFile
*f
, Object
*o
, const void **data
, size_t *size
) {
2210 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2213 /* We can't read objects larger than 4G on a 32bit machine */
2214 if ((uint64_t) t
!= l
)
2217 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2219 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
2223 r
= decompress_blob(compression
,
2224 o
->data
.payload
, l
, &f
->compress_buffer
,
2225 &f
->compress_buffer_size
, &rsize
, j
->data_threshold
);
2229 *data
= f
->compress_buffer
;
2230 *size
= (size_t) rsize
;
2232 return -EPROTONOSUPPORT
;
2235 *data
= o
->data
.payload
;
2242 _public_
int sd_journal_enumerate_data(sd_journal
*j
, const void **data
, size_t *size
) {
2249 assert_return(j
, -EINVAL
);
2250 assert_return(!journal_pid_changed(j
), -ECHILD
);
2251 assert_return(data
, -EINVAL
);
2252 assert_return(size
, -EINVAL
);
2254 f
= j
->current_file
;
2256 return -EADDRNOTAVAIL
;
2258 if (f
->current_offset
<= 0)
2259 return -EADDRNOTAVAIL
;
2261 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2265 n
= journal_file_entry_n_items(o
);
2266 if (j
->current_field
>= n
)
2269 p
= le64toh(o
->entry
.items
[j
->current_field
].object_offset
);
2270 le_hash
= o
->entry
.items
[j
->current_field
].hash
;
2271 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2275 if (le_hash
!= o
->data
.hash
)
2278 r
= return_data(j
, f
, o
, data
, size
);
2287 _public_
void sd_journal_restart_data(sd_journal
*j
) {
2291 j
->current_field
= 0;
2294 _public_
int sd_journal_get_fd(sd_journal
*j
) {
2297 assert_return(j
, -EINVAL
);
2298 assert_return(!journal_pid_changed(j
), -ECHILD
);
2301 return -EMEDIUMTYPE
;
2303 if (j
->inotify_fd
>= 0)
2304 return j
->inotify_fd
;
2306 r
= allocate_inotify(j
);
2310 log_debug("Reiterating files to get inotify watches established");
2312 /* Iterate through all dirs again, to add them to the
2314 if (j
->no_new_files
)
2315 r
= add_current_paths(j
);
2316 else if (j
->flags
& SD_JOURNAL_OS_ROOT
)
2317 r
= add_search_paths(j
);
2318 else if (j
->toplevel_fd
>= 0)
2319 r
= add_root_directory(j
, NULL
, false);
2321 r
= add_root_directory(j
, j
->path
, true);
2323 r
= add_search_paths(j
);
2327 return j
->inotify_fd
;
2330 _public_
int sd_journal_get_events(sd_journal
*j
) {
2333 assert_return(j
, -EINVAL
);
2334 assert_return(!journal_pid_changed(j
), -ECHILD
);
2336 fd
= sd_journal_get_fd(j
);
2343 _public_
int sd_journal_get_timeout(sd_journal
*j
, uint64_t *timeout_usec
) {
2346 assert_return(j
, -EINVAL
);
2347 assert_return(!journal_pid_changed(j
), -ECHILD
);
2348 assert_return(timeout_usec
, -EINVAL
);
2350 fd
= sd_journal_get_fd(j
);
2354 if (!j
->on_network
) {
2355 *timeout_usec
= (uint64_t) -1;
2359 /* If we are on the network we need to regularly check for
2360 * changes manually */
2362 *timeout_usec
= j
->last_process_usec
+ JOURNAL_FILES_RECHECK_USEC
;
2366 static void process_inotify_event(sd_journal
*j
, struct inotify_event
*e
) {
2372 /* Is this a subdirectory we watch? */
2373 d
= hashmap_get(j
->directories_by_wd
, INT_TO_PTR(e
->wd
));
2377 if (!(e
->mask
& IN_ISDIR
) && e
->len
> 0 &&
2378 (endswith(e
->name
, ".journal") ||
2379 endswith(e
->name
, ".journal~"))) {
2381 /* Event for a journal file */
2383 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2384 (void) add_file(j
, d
->path
, e
->name
);
2385 else if (e
->mask
& (IN_DELETE
|IN_MOVED_FROM
|IN_UNMOUNT
))
2386 remove_file(j
, d
->path
, e
->name
);
2388 } else if (!d
->is_root
&& e
->len
== 0) {
2390 /* Event for a subdirectory */
2392 if (e
->mask
& (IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
))
2393 remove_directory(j
, d
);
2395 } else if (d
->is_root
&& (e
->mask
& IN_ISDIR
) && e
->len
> 0 && sd_id128_from_string(e
->name
, &id
) >= 0) {
2397 /* Event for root directory */
2399 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2400 (void) add_directory(j
, d
->path
, e
->name
);
2406 if (e
->mask
& IN_IGNORED
)
2409 log_debug("Unknown inotify event.");
2412 static int determine_change(sd_journal
*j
) {
2417 b
= j
->current_invalidate_counter
!= j
->last_invalidate_counter
;
2418 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2420 return b
? SD_JOURNAL_INVALIDATE
: SD_JOURNAL_APPEND
;
2423 _public_
int sd_journal_process(sd_journal
*j
) {
2424 bool got_something
= false;
2426 assert_return(j
, -EINVAL
);
2427 assert_return(!journal_pid_changed(j
), -ECHILD
);
2429 j
->last_process_usec
= now(CLOCK_MONOTONIC
);
2430 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2433 union inotify_event_buffer buffer
;
2434 struct inotify_event
*e
;
2437 l
= read(j
->inotify_fd
, &buffer
, sizeof(buffer
));
2439 if (IN_SET(errno
, EAGAIN
, EINTR
))
2440 return got_something
? determine_change(j
) : SD_JOURNAL_NOP
;
2445 got_something
= true;
2447 FOREACH_INOTIFY_EVENT(e
, buffer
, l
)
2448 process_inotify_event(j
, e
);
2452 _public_
int sd_journal_wait(sd_journal
*j
, uint64_t timeout_usec
) {
2456 assert_return(j
, -EINVAL
);
2457 assert_return(!journal_pid_changed(j
), -ECHILD
);
2459 if (j
->inotify_fd
< 0) {
2461 /* This is the first invocation, hence create the
2463 r
= sd_journal_get_fd(j
);
2467 /* The journal might have changed since the context
2468 * object was created and we weren't watching before,
2469 * hence don't wait for anything, and return
2471 return determine_change(j
);
2474 r
= sd_journal_get_timeout(j
, &t
);
2478 if (t
!= (uint64_t) -1) {
2481 n
= now(CLOCK_MONOTONIC
);
2482 t
= t
> n
? t
- n
: 0;
2484 if (timeout_usec
== (uint64_t) -1 || timeout_usec
> t
)
2489 r
= fd_wait_for_event(j
->inotify_fd
, POLLIN
, timeout_usec
);
2490 } while (r
== -EINTR
);
2495 return sd_journal_process(j
);
2498 _public_
int sd_journal_get_cutoff_realtime_usec(sd_journal
*j
, uint64_t *from
, uint64_t *to
) {
2502 uint64_t fmin
= 0, tmax
= 0;
2505 assert_return(j
, -EINVAL
);
2506 assert_return(!journal_pid_changed(j
), -ECHILD
);
2507 assert_return(from
|| to
, -EINVAL
);
2508 assert_return(from
!= to
, -EINVAL
);
2510 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2513 r
= journal_file_get_cutoff_realtime_usec(f
, &fr
, &t
);
2526 fmin
= MIN(fr
, fmin
);
2527 tmax
= MAX(t
, tmax
);
2536 return first
? 0 : 1;
2539 _public_
int sd_journal_get_cutoff_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t *from
, uint64_t *to
) {
2545 assert_return(j
, -EINVAL
);
2546 assert_return(!journal_pid_changed(j
), -ECHILD
);
2547 assert_return(from
|| to
, -EINVAL
);
2548 assert_return(from
!= to
, -EINVAL
);
2550 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2553 r
= journal_file_get_cutoff_monotonic_usec(f
, boot_id
, &fr
, &t
);
2563 *from
= MIN(fr
, *from
);
2578 void journal_print_header(sd_journal
*j
) {
2581 bool newline
= false;
2585 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2591 journal_file_print_header(f
);
2595 _public_
int sd_journal_get_usage(sd_journal
*j
, uint64_t *bytes
) {
2600 assert_return(j
, -EINVAL
);
2601 assert_return(!journal_pid_changed(j
), -ECHILD
);
2602 assert_return(bytes
, -EINVAL
);
2604 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2607 if (fstat(f
->fd
, &st
) < 0)
2610 sum
+= (uint64_t) st
.st_blocks
* 512ULL;
2617 _public_
int sd_journal_query_unique(sd_journal
*j
, const char *field
) {
2620 assert_return(j
, -EINVAL
);
2621 assert_return(!journal_pid_changed(j
), -ECHILD
);
2622 assert_return(!isempty(field
), -EINVAL
);
2623 assert_return(field_is_valid(field
), -EINVAL
);
2629 free(j
->unique_field
);
2630 j
->unique_field
= f
;
2631 j
->unique_file
= NULL
;
2632 j
->unique_offset
= 0;
2633 j
->unique_file_lost
= false;
2638 _public_
int sd_journal_enumerate_unique(sd_journal
*j
, const void **data
, size_t *l
) {
2641 assert_return(j
, -EINVAL
);
2642 assert_return(!journal_pid_changed(j
), -ECHILD
);
2643 assert_return(data
, -EINVAL
);
2644 assert_return(l
, -EINVAL
);
2645 assert_return(j
->unique_field
, -EINVAL
);
2647 k
= strlen(j
->unique_field
);
2649 if (!j
->unique_file
) {
2650 if (j
->unique_file_lost
)
2653 j
->unique_file
= ordered_hashmap_first(j
->files
);
2654 if (!j
->unique_file
)
2657 j
->unique_offset
= 0;
2669 /* Proceed to next data object in the field's linked list */
2670 if (j
->unique_offset
== 0) {
2671 r
= journal_file_find_field_object(j
->unique_file
, j
->unique_field
, k
, &o
, NULL
);
2675 j
->unique_offset
= r
> 0 ? le64toh(o
->field
.head_data_offset
) : 0;
2677 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_DATA
, j
->unique_offset
, &o
);
2681 j
->unique_offset
= le64toh(o
->data
.next_field_offset
);
2684 /* We reached the end of the list? Then start again, with the next file */
2685 if (j
->unique_offset
== 0) {
2686 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
2687 if (!j
->unique_file
)
2693 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2694 * instead, so that we can look at this data object at the same
2695 * time as one on another file */
2696 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_UNUSED
, j
->unique_offset
, &o
);
2700 /* Let's do the type check by hand, since we used 0 context above. */
2701 if (o
->object
.type
!= OBJECT_DATA
) {
2702 log_debug("%s:offset " OFSfmt
": object has type %d, expected %d",
2703 j
->unique_file
->path
, j
->unique_offset
,
2704 o
->object
.type
, OBJECT_DATA
);
2708 r
= return_data(j
, j
->unique_file
, o
, &odata
, &ol
);
2712 /* Check if we have at least the field name and "=". */
2714 log_debug("%s:offset " OFSfmt
": object has size %zu, expected at least %zu",
2715 j
->unique_file
->path
, j
->unique_offset
,
2720 if (memcmp(odata
, j
->unique_field
, k
) || ((const char*) odata
)[k
] != '=') {
2721 log_debug("%s:offset " OFSfmt
": object does not start with \"%s=\"",
2722 j
->unique_file
->path
, j
->unique_offset
,
2727 /* OK, now let's see if we already returned this data
2728 * object by checking if it exists in the earlier
2729 * traversed files. */
2731 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2732 if (of
== j
->unique_file
)
2735 /* Skip this file it didn't have any fields indexed */
2736 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2739 r
= journal_file_find_data_object_with_hash(of
, odata
, ol
, le64toh(o
->data
.hash
), NULL
, NULL
);
2751 r
= return_data(j
, j
->unique_file
, o
, data
, l
);
2759 _public_
void sd_journal_restart_unique(sd_journal
*j
) {
2763 j
->unique_file
= NULL
;
2764 j
->unique_offset
= 0;
2765 j
->unique_file_lost
= false;
2768 _public_
int sd_journal_enumerate_fields(sd_journal
*j
, const char **field
) {
2771 assert_return(j
, -EINVAL
);
2772 assert_return(!journal_pid_changed(j
), -ECHILD
);
2773 assert_return(field
, -EINVAL
);
2775 if (!j
->fields_file
) {
2776 if (j
->fields_file_lost
)
2779 j
->fields_file
= ordered_hashmap_first(j
->files
);
2780 if (!j
->fields_file
)
2783 j
->fields_hash_table_index
= 0;
2784 j
->fields_offset
= 0;
2788 JournalFile
*f
, *of
;
2797 if (j
->fields_offset
== 0) {
2800 /* We are not yet positioned at any field. Let's pick the first one */
2801 r
= journal_file_map_field_hash_table(f
);
2805 m
= le64toh(f
->header
->field_hash_table_size
) / sizeof(HashItem
);
2807 if (j
->fields_hash_table_index
>= m
) {
2808 /* Reached the end of the hash table, go to the next file. */
2813 j
->fields_offset
= le64toh(f
->field_hash_table
[j
->fields_hash_table_index
].head_hash_offset
);
2815 if (j
->fields_offset
!= 0)
2818 /* Empty hash table bucket, go to next one */
2819 j
->fields_hash_table_index
++;
2823 /* Proceed with next file */
2824 j
->fields_file
= ordered_hashmap_next(j
->files
, f
->path
);
2825 if (!j
->fields_file
) {
2830 j
->fields_offset
= 0;
2831 j
->fields_hash_table_index
= 0;
2836 /* We are already positioned at a field. If so, let's figure out the next field from it */
2838 r
= journal_file_move_to_object(f
, OBJECT_FIELD
, j
->fields_offset
, &o
);
2842 j
->fields_offset
= le64toh(o
->field
.next_hash_offset
);
2843 if (j
->fields_offset
== 0) {
2844 /* Reached the end of the hash table chain */
2845 j
->fields_hash_table_index
++;
2850 /* We use OBJECT_UNUSED here, so that the iterator below doesn't remove our mmap window */
2851 r
= journal_file_move_to_object(f
, OBJECT_UNUSED
, j
->fields_offset
, &o
);
2855 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
2856 if (o
->object
.type
!= OBJECT_FIELD
) {
2857 log_debug("%s:offset " OFSfmt
": object has type %i, expected %i", f
->path
, j
->fields_offset
, o
->object
.type
, OBJECT_FIELD
);
2861 sz
= le64toh(o
->object
.size
) - offsetof(Object
, field
.payload
);
2863 /* Let's see if we already returned this field name before. */
2865 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2869 /* Skip this file it didn't have any fields indexed */
2870 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2873 r
= journal_file_find_field_object_with_hash(of
, o
->field
.payload
, sz
, le64toh(o
->field
.hash
), NULL
, NULL
);
2885 /* Check if this is really a valid string containing no NUL byte */
2886 if (memchr(o
->field
.payload
, 0, sz
))
2889 if (sz
> j
->data_threshold
)
2890 sz
= j
->data_threshold
;
2892 if (!GREEDY_REALLOC(j
->fields_buffer
, j
->fields_buffer_allocated
, sz
+ 1))
2895 memcpy(j
->fields_buffer
, o
->field
.payload
, sz
);
2896 j
->fields_buffer
[sz
] = 0;
2898 if (!field_is_valid(j
->fields_buffer
))
2901 *field
= j
->fields_buffer
;
2906 _public_
void sd_journal_restart_fields(sd_journal
*j
) {
2910 j
->fields_file
= NULL
;
2911 j
->fields_hash_table_index
= 0;
2912 j
->fields_offset
= 0;
2913 j
->fields_file_lost
= false;
2916 _public_
int sd_journal_reliable_fd(sd_journal
*j
) {
2917 assert_return(j
, -EINVAL
);
2918 assert_return(!journal_pid_changed(j
), -ECHILD
);
2920 return !j
->on_network
;
2923 static char *lookup_field(const char *field
, void *userdata
) {
2924 sd_journal
*j
= userdata
;
2932 r
= sd_journal_get_data(j
, field
, &data
, &size
);
2934 size
> REPLACE_VAR_MAX
)
2935 return strdup(field
);
2937 d
= strlen(field
) + 1;
2939 return strndup((const char*) data
+ d
, size
- d
);
2942 _public_
int sd_journal_get_catalog(sd_journal
*j
, char **ret
) {
2946 _cleanup_free_
char *text
= NULL
, *cid
= NULL
;
2950 assert_return(j
, -EINVAL
);
2951 assert_return(!journal_pid_changed(j
), -ECHILD
);
2952 assert_return(ret
, -EINVAL
);
2954 r
= sd_journal_get_data(j
, "MESSAGE_ID", &data
, &size
);
2958 cid
= strndup((const char*) data
+ 11, size
- 11);
2962 r
= sd_id128_from_string(cid
, &id
);
2966 r
= catalog_get(CATALOG_DATABASE
, id
, &text
);
2970 t
= replace_var(text
, lookup_field
, j
);
2978 _public_
int sd_journal_get_catalog_for_message_id(sd_id128_t id
, char **ret
) {
2979 assert_return(ret
, -EINVAL
);
2981 return catalog_get(CATALOG_DATABASE
, id
, ret
);
2984 _public_
int sd_journal_set_data_threshold(sd_journal
*j
, size_t sz
) {
2985 assert_return(j
, -EINVAL
);
2986 assert_return(!journal_pid_changed(j
), -ECHILD
);
2988 j
->data_threshold
= sz
;
2992 _public_
int sd_journal_get_data_threshold(sd_journal
*j
, size_t *sz
) {
2993 assert_return(j
, -EINVAL
);
2994 assert_return(!journal_pid_changed(j
), -ECHILD
);
2995 assert_return(sz
, -EINVAL
);
2997 *sz
= j
->data_threshold
;
3001 _public_
int sd_journal_has_runtime_files(sd_journal
*j
) {
3002 assert_return(j
, -EINVAL
);
3004 return j
->has_runtime_files
;
3007 _public_
int sd_journal_has_persistent_files(sd_journal
*j
) {
3008 assert_return(j
, -EINVAL
);
3010 return j
->has_persistent_files
;