1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 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 "formats-util.h"
42 #include "hostname-util.h"
44 #include "journal-def.h"
45 #include "journal-file.h"
46 #include "journal-internal.h"
50 #include "path-util.h"
51 #include "replace-var.h"
52 #include "stat-util.h"
53 #include "stdio-util.h"
54 #include "string-util.h"
57 #define JOURNAL_FILES_MAX 7168
59 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
61 #define REPLACE_VAR_MAX 256
63 #define DEFAULT_DATA_THRESHOLD (64*1024)
65 static void remove_file_real(sd_journal
*j
, JournalFile
*f
);
67 static bool journal_pid_changed(sd_journal
*j
) {
70 /* We don't support people creating a journal object and
71 * keeping it around over a fork(). Let's complain. */
73 return j
->original_pid
!= getpid();
76 static int journal_put_error(sd_journal
*j
, int r
, const char *path
) {
80 /* Memorize an error we encountered, and store which
81 * file/directory it was generated from. Note that we store
82 * only *one* path per error code, as the error code is the
83 * key into the hashmap, and the path is the value. This means
84 * we keep track only of all error kinds, but not of all error
85 * locations. This has the benefit that the hashmap cannot
88 * We return an error here only if we didn't manage to
89 * memorize the real error. */
94 k
= hashmap_ensure_allocated(&j
->errors
, NULL
);
105 k
= hashmap_put(j
->errors
, INT_TO_PTR(r
), copy
);
118 static void detach_location(sd_journal
*j
) {
124 j
->current_file
= NULL
;
125 j
->current_field
= 0;
127 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
)
128 journal_file_reset_location(f
);
131 static void reset_location(sd_journal
*j
) {
135 zero(j
->current_location
);
138 static void init_location(Location
*l
, LocationType type
, JournalFile
*f
, Object
*o
) {
140 assert(type
== LOCATION_DISCRETE
|| type
== LOCATION_SEEK
);
142 assert(o
->object
.type
== OBJECT_ENTRY
);
145 l
->seqnum
= le64toh(o
->entry
.seqnum
);
146 l
->seqnum_id
= f
->header
->seqnum_id
;
147 l
->realtime
= le64toh(o
->entry
.realtime
);
148 l
->monotonic
= le64toh(o
->entry
.monotonic
);
149 l
->boot_id
= o
->entry
.boot_id
;
150 l
->xor_hash
= le64toh(o
->entry
.xor_hash
);
152 l
->seqnum_set
= l
->realtime_set
= l
->monotonic_set
= l
->xor_hash_set
= true;
155 static void set_location(sd_journal
*j
, JournalFile
*f
, Object
*o
) {
160 init_location(&j
->current_location
, LOCATION_DISCRETE
, f
, o
);
163 j
->current_field
= 0;
165 /* Let f know its candidate entry was picked. */
166 assert(f
->location_type
== LOCATION_SEEK
);
167 f
->location_type
= LOCATION_DISCRETE
;
170 static int match_is_valid(const void *data
, size_t size
) {
178 if (startswith(data
, "__"))
182 for (p
= b
; p
< b
+ size
; p
++) {
190 if (*p
>= 'A' && *p
<= 'Z')
193 if (*p
>= '0' && *p
<= '9')
202 static bool same_field(const void *_a
, size_t s
, const void *_b
, size_t t
) {
203 const uint8_t *a
= _a
, *b
= _b
;
206 for (j
= 0; j
< s
&& j
< t
; j
++) {
215 assert_not_reached("\"=\" not found");
218 static Match
*match_new(Match
*p
, MatchType t
) {
229 LIST_PREPEND(matches
, p
->matches
, m
);
235 static void match_free(Match
*m
) {
239 match_free(m
->matches
);
242 LIST_REMOVE(matches
, m
->parent
->matches
, m
);
248 static void match_free_if_empty(Match
*m
) {
249 if (!m
|| m
->matches
)
255 _public_
int sd_journal_add_match(sd_journal
*j
, const void *data
, size_t size
) {
256 Match
*l3
, *l4
, *add_here
= NULL
, *m
;
259 assert_return(j
, -EINVAL
);
260 assert_return(!journal_pid_changed(j
), -ECHILD
);
261 assert_return(data
, -EINVAL
);
266 assert_return(match_is_valid(data
, size
), -EINVAL
);
272 * level 4: concrete matches */
275 j
->level0
= match_new(NULL
, MATCH_AND_TERM
);
281 j
->level1
= match_new(j
->level0
, MATCH_OR_TERM
);
287 j
->level2
= match_new(j
->level1
, MATCH_AND_TERM
);
292 assert(j
->level0
->type
== MATCH_AND_TERM
);
293 assert(j
->level1
->type
== MATCH_OR_TERM
);
294 assert(j
->level2
->type
== MATCH_AND_TERM
);
296 le_hash
= htole64(hash64(data
, size
));
298 LIST_FOREACH(matches
, l3
, j
->level2
->matches
) {
299 assert(l3
->type
== MATCH_OR_TERM
);
301 LIST_FOREACH(matches
, l4
, l3
->matches
) {
302 assert(l4
->type
== MATCH_DISCRETE
);
304 /* Exactly the same match already? Then ignore
306 if (l4
->le_hash
== le_hash
&&
308 memcmp(l4
->data
, data
, size
) == 0)
311 /* Same field? Then let's add this to this OR term */
312 if (same_field(data
, size
, l4
->data
, l4
->size
)) {
323 add_here
= match_new(j
->level2
, MATCH_OR_TERM
);
328 m
= match_new(add_here
, MATCH_DISCRETE
);
332 m
->le_hash
= le_hash
;
334 m
->data
= memdup(data
, size
);
343 match_free_if_empty(add_here
);
344 match_free_if_empty(j
->level2
);
345 match_free_if_empty(j
->level1
);
346 match_free_if_empty(j
->level0
);
351 _public_
int sd_journal_add_conjunction(sd_journal
*j
) {
352 assert_return(j
, -EINVAL
);
353 assert_return(!journal_pid_changed(j
), -ECHILD
);
361 if (!j
->level1
->matches
)
370 _public_
int sd_journal_add_disjunction(sd_journal
*j
) {
371 assert_return(j
, -EINVAL
);
372 assert_return(!journal_pid_changed(j
), -ECHILD
);
383 if (!j
->level2
->matches
)
390 static char *match_make_string(Match
*m
) {
393 bool enclose
= false;
396 return strdup("none");
398 if (m
->type
== MATCH_DISCRETE
)
399 return strndup(m
->data
, m
->size
);
402 LIST_FOREACH(matches
, i
, m
->matches
) {
405 t
= match_make_string(i
);
412 k
= strjoin(p
, m
->type
== MATCH_OR_TERM
? " OR " : " AND ", t
, NULL
);
427 r
= strjoin("(", p
, ")", NULL
);
435 char *journal_make_match_string(sd_journal
*j
) {
438 return match_make_string(j
->level0
);
441 _public_
void sd_journal_flush_matches(sd_journal
*j
) {
446 match_free(j
->level0
);
448 j
->level0
= j
->level1
= j
->level2
= NULL
;
453 _pure_
static int compare_with_location(JournalFile
*f
, Location
*l
) {
456 assert(f
->location_type
== LOCATION_SEEK
);
457 assert(l
->type
== LOCATION_DISCRETE
|| l
->type
== LOCATION_SEEK
);
459 if (l
->monotonic_set
&&
460 sd_id128_equal(f
->current_boot_id
, l
->boot_id
) &&
462 f
->current_realtime
== l
->realtime
&&
464 f
->current_xor_hash
== l
->xor_hash
)
468 sd_id128_equal(f
->header
->seqnum_id
, l
->seqnum_id
)) {
470 if (f
->current_seqnum
< l
->seqnum
)
472 if (f
->current_seqnum
> l
->seqnum
)
476 if (l
->monotonic_set
&&
477 sd_id128_equal(f
->current_boot_id
, l
->boot_id
)) {
479 if (f
->current_monotonic
< l
->monotonic
)
481 if (f
->current_monotonic
> l
->monotonic
)
485 if (l
->realtime_set
) {
487 if (f
->current_realtime
< l
->realtime
)
489 if (f
->current_realtime
> l
->realtime
)
493 if (l
->xor_hash_set
) {
495 if (f
->current_xor_hash
< l
->xor_hash
)
497 if (f
->current_xor_hash
> l
->xor_hash
)
504 static int next_for_match(
508 uint64_t after_offset
,
509 direction_t direction
,
521 if (m
->type
== MATCH_DISCRETE
) {
524 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
528 return journal_file_move_to_entry_by_offset_for_data(f
, dp
, after_offset
, direction
, ret
, offset
);
530 } else if (m
->type
== MATCH_OR_TERM
) {
533 /* Find the earliest match beyond after_offset */
535 LIST_FOREACH(matches
, i
, m
->matches
) {
538 r
= next_for_match(j
, i
, f
, after_offset
, direction
, NULL
, &cp
);
542 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
< np
: cp
> np
))
550 } else if (m
->type
== MATCH_AND_TERM
) {
551 Match
*i
, *last_moved
;
553 /* Always jump to the next matching entry and repeat
554 * this until we find an offset that matches for all
560 r
= next_for_match(j
, m
->matches
, f
, after_offset
, direction
, NULL
, &np
);
564 assert(direction
== DIRECTION_DOWN
? np
>= after_offset
: np
<= after_offset
);
565 last_moved
= m
->matches
;
567 LIST_LOOP_BUT_ONE(matches
, i
, m
->matches
, last_moved
) {
570 r
= next_for_match(j
, i
, f
, np
, direction
, NULL
, &cp
);
574 assert(direction
== DIRECTION_DOWN
? cp
>= np
: cp
<= np
);
575 if (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
) {
584 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
596 static int find_location_for_match(
600 direction_t direction
,
610 if (m
->type
== MATCH_DISCRETE
) {
613 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
617 /* FIXME: missing: find by monotonic */
619 if (j
->current_location
.type
== LOCATION_HEAD
)
620 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_DOWN
, ret
, offset
);
621 if (j
->current_location
.type
== LOCATION_TAIL
)
622 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_UP
, ret
, offset
);
623 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
624 return journal_file_move_to_entry_by_seqnum_for_data(f
, dp
, j
->current_location
.seqnum
, direction
, ret
, offset
);
625 if (j
->current_location
.monotonic_set
) {
626 r
= journal_file_move_to_entry_by_monotonic_for_data(f
, dp
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
630 if (j
->current_location
.realtime_set
)
631 return journal_file_move_to_entry_by_realtime_for_data(f
, dp
, j
->current_location
.realtime
, direction
, ret
, offset
);
633 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, direction
, ret
, offset
);
635 } else if (m
->type
== MATCH_OR_TERM
) {
640 /* Find the earliest match */
642 LIST_FOREACH(matches
, i
, m
->matches
) {
645 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
649 if (np
== 0 || (direction
== DIRECTION_DOWN
? np
> cp
: np
< cp
))
657 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
672 assert(m
->type
== MATCH_AND_TERM
);
674 /* First jump to the last match, and then find the
675 * next one where all matches match */
680 LIST_FOREACH(matches
, i
, m
->matches
) {
683 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
687 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
))
691 return next_for_match(j
, m
, f
, np
, direction
, ret
, offset
);
695 static int find_location_with_matches(
698 direction_t direction
,
710 /* No matches is simple */
712 if (j
->current_location
.type
== LOCATION_HEAD
)
713 return journal_file_next_entry(f
, 0, DIRECTION_DOWN
, ret
, offset
);
714 if (j
->current_location
.type
== LOCATION_TAIL
)
715 return journal_file_next_entry(f
, 0, DIRECTION_UP
, ret
, offset
);
716 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
717 return journal_file_move_to_entry_by_seqnum(f
, j
->current_location
.seqnum
, direction
, ret
, offset
);
718 if (j
->current_location
.monotonic_set
) {
719 r
= journal_file_move_to_entry_by_monotonic(f
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
723 if (j
->current_location
.realtime_set
)
724 return journal_file_move_to_entry_by_realtime(f
, j
->current_location
.realtime
, direction
, ret
, offset
);
726 return journal_file_next_entry(f
, 0, direction
, ret
, offset
);
728 return find_location_for_match(j
, j
->level0
, f
, direction
, ret
, offset
);
731 static int next_with_matches(
734 direction_t direction
,
743 /* No matches is easy. We simple advance the file
746 return journal_file_next_entry(f
, f
->current_offset
, direction
, ret
, offset
);
748 /* If we have a match then we look for the next matching entry
749 * with an offset at least one step larger */
750 return next_for_match(j
, j
->level0
, f
,
751 direction
== DIRECTION_DOWN
? f
->current_offset
+ 1
752 : f
->current_offset
- 1,
753 direction
, ret
, offset
);
756 static int next_beyond_location(sd_journal
*j
, JournalFile
*f
, direction_t direction
) {
758 uint64_t cp
, n_entries
;
764 n_entries
= le64toh(f
->header
->n_entries
);
766 /* If we hit EOF before, we don't need to look into this file again
767 * unless direction changed or new entries appeared. */
768 if (f
->last_direction
== direction
&& f
->location_type
== LOCATION_TAIL
&&
769 n_entries
== f
->last_n_entries
)
772 f
->last_n_entries
= n_entries
;
774 if (f
->last_direction
== direction
&& f
->current_offset
> 0) {
775 /* LOCATION_SEEK here means we did the work in a previous
776 * iteration and the current location already points to a
777 * candidate entry. */
778 if (f
->location_type
!= LOCATION_SEEK
) {
779 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
783 journal_file_save_location(f
, c
, cp
);
786 f
->last_direction
= direction
;
788 r
= find_location_with_matches(j
, f
, direction
, &c
, &cp
);
792 journal_file_save_location(f
, c
, cp
);
795 /* OK, we found the spot, now let's advance until an entry
796 * that is actually different from what we were previously
797 * looking at. This is necessary to handle entries which exist
798 * in two (or more) journal files, and which shall all be
799 * suppressed but one. */
804 if (j
->current_location
.type
== LOCATION_DISCRETE
) {
807 k
= compare_with_location(f
, &j
->current_location
);
809 found
= direction
== DIRECTION_DOWN
? k
> 0 : k
< 0;
816 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
820 journal_file_save_location(f
, c
, cp
);
824 static int real_journal_next(sd_journal
*j
, direction_t direction
) {
825 JournalFile
*f
, *new_file
= NULL
;
830 assert_return(j
, -EINVAL
);
831 assert_return(!journal_pid_changed(j
), -ECHILD
);
833 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
836 r
= next_beyond_location(j
, f
, direction
);
838 log_debug_errno(r
, "Can't iterate through %s, ignoring: %m", f
->path
);
839 remove_file_real(j
, f
);
842 f
->location_type
= LOCATION_TAIL
;
851 k
= journal_file_compare_locations(f
, new_file
);
853 found
= direction
== DIRECTION_DOWN
? k
< 0 : k
> 0;
863 r
= journal_file_move_to_object(new_file
, OBJECT_ENTRY
, new_file
->current_offset
, &o
);
867 set_location(j
, new_file
, o
);
872 _public_
int sd_journal_next(sd_journal
*j
) {
873 return real_journal_next(j
, DIRECTION_DOWN
);
876 _public_
int sd_journal_previous(sd_journal
*j
) {
877 return real_journal_next(j
, DIRECTION_UP
);
880 static int real_journal_next_skip(sd_journal
*j
, direction_t direction
, uint64_t skip
) {
883 assert_return(j
, -EINVAL
);
884 assert_return(!journal_pid_changed(j
), -ECHILD
);
887 /* If this is not a discrete skip, then at least
888 * resolve the current location */
889 if (j
->current_location
.type
!= LOCATION_DISCRETE
)
890 return real_journal_next(j
, direction
);
896 r
= real_journal_next(j
, direction
);
910 _public_
int sd_journal_next_skip(sd_journal
*j
, uint64_t skip
) {
911 return real_journal_next_skip(j
, DIRECTION_DOWN
, skip
);
914 _public_
int sd_journal_previous_skip(sd_journal
*j
, uint64_t skip
) {
915 return real_journal_next_skip(j
, DIRECTION_UP
, skip
);
918 _public_
int sd_journal_get_cursor(sd_journal
*j
, char **cursor
) {
921 char bid
[33], sid
[33];
923 assert_return(j
, -EINVAL
);
924 assert_return(!journal_pid_changed(j
), -ECHILD
);
925 assert_return(cursor
, -EINVAL
);
927 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
928 return -EADDRNOTAVAIL
;
930 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
934 sd_id128_to_string(j
->current_file
->header
->seqnum_id
, sid
);
935 sd_id128_to_string(o
->entry
.boot_id
, bid
);
938 "s=%s;i=%"PRIx64
";b=%s;m=%"PRIx64
";t=%"PRIx64
";x=%"PRIx64
,
939 sid
, le64toh(o
->entry
.seqnum
),
940 bid
, le64toh(o
->entry
.monotonic
),
941 le64toh(o
->entry
.realtime
),
942 le64toh(o
->entry
.xor_hash
)) < 0)
948 _public_
int sd_journal_seek_cursor(sd_journal
*j
, const char *cursor
) {
949 const char *word
, *state
;
951 unsigned long long seqnum
, monotonic
, realtime
, xor_hash
;
953 seqnum_id_set
= false,
956 monotonic_set
= false,
957 realtime_set
= false,
958 xor_hash_set
= false;
959 sd_id128_t seqnum_id
, boot_id
;
961 assert_return(j
, -EINVAL
);
962 assert_return(!journal_pid_changed(j
), -ECHILD
);
963 assert_return(!isempty(cursor
), -EINVAL
);
965 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
969 if (l
< 2 || word
[1] != '=')
972 item
= strndup(word
, l
);
979 seqnum_id_set
= true;
980 k
= sd_id128_from_string(item
+2, &seqnum_id
);
985 if (sscanf(item
+2, "%llx", &seqnum
) != 1)
991 k
= sd_id128_from_string(item
+2, &boot_id
);
995 monotonic_set
= true;
996 if (sscanf(item
+2, "%llx", &monotonic
) != 1)
1001 realtime_set
= true;
1002 if (sscanf(item
+2, "%llx", &realtime
) != 1)
1007 xor_hash_set
= true;
1008 if (sscanf(item
+2, "%llx", &xor_hash
) != 1)
1019 if ((!seqnum_set
|| !seqnum_id_set
) &&
1020 (!monotonic_set
|| !boot_id_set
) &&
1026 j
->current_location
.type
= LOCATION_SEEK
;
1029 j
->current_location
.realtime
= (uint64_t) realtime
;
1030 j
->current_location
.realtime_set
= true;
1033 if (seqnum_set
&& seqnum_id_set
) {
1034 j
->current_location
.seqnum
= (uint64_t) seqnum
;
1035 j
->current_location
.seqnum_id
= seqnum_id
;
1036 j
->current_location
.seqnum_set
= true;
1039 if (monotonic_set
&& boot_id_set
) {
1040 j
->current_location
.monotonic
= (uint64_t) monotonic
;
1041 j
->current_location
.boot_id
= boot_id
;
1042 j
->current_location
.monotonic_set
= true;
1046 j
->current_location
.xor_hash
= (uint64_t) xor_hash
;
1047 j
->current_location
.xor_hash_set
= true;
1053 _public_
int sd_journal_test_cursor(sd_journal
*j
, const char *cursor
) {
1057 assert_return(j
, -EINVAL
);
1058 assert_return(!journal_pid_changed(j
), -ECHILD
);
1059 assert_return(!isempty(cursor
), -EINVAL
);
1061 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
1062 return -EADDRNOTAVAIL
;
1064 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
1069 _cleanup_free_
char *item
= NULL
;
1070 unsigned long long ll
;
1074 r
= extract_first_word(&cursor
, &item
, ";", EXTRACT_DONT_COALESCE_SEPARATORS
);
1081 if (strlen(item
) < 2 || item
[1] != '=')
1087 k
= sd_id128_from_string(item
+2, &id
);
1090 if (!sd_id128_equal(id
, j
->current_file
->header
->seqnum_id
))
1095 if (sscanf(item
+2, "%llx", &ll
) != 1)
1097 if (ll
!= le64toh(o
->entry
.seqnum
))
1102 k
= sd_id128_from_string(item
+2, &id
);
1105 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1110 if (sscanf(item
+2, "%llx", &ll
) != 1)
1112 if (ll
!= le64toh(o
->entry
.monotonic
))
1117 if (sscanf(item
+2, "%llx", &ll
) != 1)
1119 if (ll
!= le64toh(o
->entry
.realtime
))
1124 if (sscanf(item
+2, "%llx", &ll
) != 1)
1126 if (ll
!= le64toh(o
->entry
.xor_hash
))
1136 _public_
int sd_journal_seek_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t usec
) {
1137 assert_return(j
, -EINVAL
);
1138 assert_return(!journal_pid_changed(j
), -ECHILD
);
1141 j
->current_location
.type
= LOCATION_SEEK
;
1142 j
->current_location
.boot_id
= boot_id
;
1143 j
->current_location
.monotonic
= usec
;
1144 j
->current_location
.monotonic_set
= true;
1149 _public_
int sd_journal_seek_realtime_usec(sd_journal
*j
, uint64_t usec
) {
1150 assert_return(j
, -EINVAL
);
1151 assert_return(!journal_pid_changed(j
), -ECHILD
);
1154 j
->current_location
.type
= LOCATION_SEEK
;
1155 j
->current_location
.realtime
= usec
;
1156 j
->current_location
.realtime_set
= true;
1161 _public_
int sd_journal_seek_head(sd_journal
*j
) {
1162 assert_return(j
, -EINVAL
);
1163 assert_return(!journal_pid_changed(j
), -ECHILD
);
1166 j
->current_location
.type
= LOCATION_HEAD
;
1171 _public_
int sd_journal_seek_tail(sd_journal
*j
) {
1172 assert_return(j
, -EINVAL
);
1173 assert_return(!journal_pid_changed(j
), -ECHILD
);
1176 j
->current_location
.type
= LOCATION_TAIL
;
1181 static void check_network(sd_journal
*j
, int fd
) {
1189 if (fstatfs(fd
, &sfs
) < 0)
1193 F_TYPE_EQUAL(sfs
.f_type
, CIFS_MAGIC_NUMBER
) ||
1194 F_TYPE_EQUAL(sfs
.f_type
, CODA_SUPER_MAGIC
) ||
1195 F_TYPE_EQUAL(sfs
.f_type
, NCP_SUPER_MAGIC
) ||
1196 F_TYPE_EQUAL(sfs
.f_type
, NFS_SUPER_MAGIC
) ||
1197 F_TYPE_EQUAL(sfs
.f_type
, SMB_SUPER_MAGIC
);
1200 static bool file_has_type_prefix(const char *prefix
, const char *filename
) {
1201 const char *full
, *tilded
, *atted
;
1203 full
= strjoina(prefix
, ".journal");
1204 tilded
= strjoina(full
, "~");
1205 atted
= strjoina(prefix
, "@");
1207 return streq(filename
, full
) ||
1208 streq(filename
, tilded
) ||
1209 startswith(filename
, atted
);
1212 static bool file_type_wanted(int flags
, const char *filename
) {
1215 if (!endswith(filename
, ".journal") && !endswith(filename
, ".journal~"))
1218 /* no flags set → every type is OK */
1219 if (!(flags
& (SD_JOURNAL_SYSTEM
| SD_JOURNAL_CURRENT_USER
)))
1222 if (flags
& SD_JOURNAL_SYSTEM
&& file_has_type_prefix("system", filename
))
1225 if (flags
& SD_JOURNAL_CURRENT_USER
) {
1226 char prefix
[5 + DECIMAL_STR_MAX(uid_t
) + 1];
1228 xsprintf(prefix
, "user-"UID_FMT
, getuid());
1230 if (file_has_type_prefix(prefix
, filename
))
1237 static int add_any_file(sd_journal
*j
, const char *path
) {
1238 JournalFile
*f
= NULL
;
1244 if (ordered_hashmap_get(j
->files
, path
))
1247 if (ordered_hashmap_size(j
->files
) >= JOURNAL_FILES_MAX
) {
1248 log_debug("Too many open journal files, not adding %s.", path
);
1253 r
= journal_file_open(path
, O_RDONLY
, 0, false, false, NULL
, j
->mmap
, NULL
, &f
);
1255 log_debug_errno(r
, "Failed to open journal file %s: %m", path
);
1259 /* journal_file_dump(f); */
1261 r
= ordered_hashmap_put(j
->files
, f
->path
, f
);
1263 journal_file_close(f
);
1267 log_debug("File %s added.", f
->path
);
1269 check_network(j
, f
->fd
);
1271 j
->current_invalidate_counter
++;
1276 k
= journal_put_error(j
, r
, path
);
1283 static int add_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1290 if (j
->no_new_files
||
1291 !file_type_wanted(j
->flags
, filename
))
1294 path
= strjoina(prefix
, "/", filename
);
1296 if (!j
->has_runtime_files
&& path_startswith(path
, "/run/log/journal"))
1297 j
->has_runtime_files
= true;
1298 else if (!j
->has_persistent_files
&& path_startswith(path
, "/var/log/journal"))
1299 j
->has_persistent_files
= true;
1301 return add_any_file(j
, path
);
1304 static void remove_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1312 path
= strjoina(prefix
, "/", filename
);
1313 f
= ordered_hashmap_get(j
->files
, path
);
1317 remove_file_real(j
, f
);
1320 static void remove_file_real(sd_journal
*j
, JournalFile
*f
) {
1324 ordered_hashmap_remove(j
->files
, f
->path
);
1326 log_debug("File %s removed.", f
->path
);
1328 if (j
->current_file
== f
) {
1329 j
->current_file
= NULL
;
1330 j
->current_field
= 0;
1333 if (j
->unique_file
== f
) {
1334 /* Jump to the next unique_file or NULL if that one was last */
1335 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
1336 j
->unique_offset
= 0;
1337 if (!j
->unique_file
)
1338 j
->unique_file_lost
= true;
1341 if (j
->fields_file
== f
) {
1342 j
->fields_file
= ordered_hashmap_next(j
->files
, j
->fields_file
->path
);
1343 j
->fields_offset
= 0;
1344 if (!j
->fields_file
)
1345 j
->fields_file_lost
= true;
1348 journal_file_close(f
);
1350 j
->current_invalidate_counter
++;
1353 static int dirname_is_machine_id(const char *fn
) {
1354 sd_id128_t id
, machine
;
1357 r
= sd_id128_get_machine(&machine
);
1361 r
= sd_id128_from_string(fn
, &id
);
1365 return sd_id128_equal(id
, machine
);
1368 static int add_directory(sd_journal
*j
, const char *prefix
, const char *dirname
) {
1369 _cleanup_free_
char *path
= NULL
;
1370 _cleanup_closedir_
DIR *d
= NULL
;
1371 struct dirent
*de
= NULL
;
1379 log_debug("Considering %s/%s.", prefix
, dirname
);
1381 if ((j
->flags
& SD_JOURNAL_LOCAL_ONLY
) &&
1382 !(dirname_is_machine_id(dirname
) > 0 || path_startswith(prefix
, "/run")))
1385 path
= strjoin(prefix
, "/", dirname
, NULL
);
1393 r
= log_debug_errno(errno
, "Failed to open directory %s: %m", path
);
1397 m
= hashmap_get(j
->directories_by_path
, path
);
1399 m
= new0(Directory
, 1);
1408 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1414 path
= NULL
; /* avoid freeing in cleanup */
1415 j
->current_invalidate_counter
++;
1417 log_debug("Directory %s added.", m
->path
);
1419 } else if (m
->is_root
)
1422 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1424 m
->wd
= inotify_add_watch(j
->inotify_fd
, m
->path
,
1425 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1426 IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
|IN_MOVED_FROM
|
1429 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1430 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1433 FOREACH_DIRENT_ALL(de
, d
, return log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
)) {
1435 if (dirent_is_file_with_suffix(de
, ".journal") ||
1436 dirent_is_file_with_suffix(de
, ".journal~"))
1437 (void) add_file(j
, m
->path
, de
->d_name
);
1440 check_network(j
, dirfd(d
));
1445 k
= journal_put_error(j
, r
, path
?: dirname
);
1452 static int add_root_directory(sd_journal
*j
, const char *p
, bool missing_ok
) {
1453 _cleanup_closedir_
DIR *d
= NULL
;
1461 if ((j
->flags
& SD_JOURNAL_RUNTIME_ONLY
) &&
1462 !path_startswith(p
, "/run"))
1466 p
= strjoina(j
->prefix
, p
);
1470 if (errno
== ENOENT
&& missing_ok
)
1473 r
= log_debug_errno(errno
, "Failed to open root directory %s: %m", p
);
1477 m
= hashmap_get(j
->directories_by_path
, p
);
1479 m
= new0(Directory
, 1);
1486 m
->path
= strdup(p
);
1493 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1500 j
->current_invalidate_counter
++;
1502 log_debug("Root directory %s added.", m
->path
);
1504 } else if (!m
->is_root
)
1507 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1509 m
->wd
= inotify_add_watch(j
->inotify_fd
, m
->path
,
1510 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1513 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1514 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1517 if (j
->no_new_files
)
1520 FOREACH_DIRENT_ALL(de
, d
, return log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
)) {
1523 if (dirent_is_file_with_suffix(de
, ".journal") ||
1524 dirent_is_file_with_suffix(de
, ".journal~"))
1525 (void) add_file(j
, m
->path
, de
->d_name
);
1526 else if (IN_SET(de
->d_type
, DT_DIR
, DT_LNK
, DT_UNKNOWN
) &&
1527 sd_id128_from_string(de
->d_name
, &id
) >= 0)
1528 (void) add_directory(j
, m
->path
, de
->d_name
);
1531 check_network(j
, dirfd(d
));
1536 k
= journal_put_error(j
, r
, p
);
1543 static void remove_directory(sd_journal
*j
, Directory
*d
) {
1547 hashmap_remove(j
->directories_by_wd
, INT_TO_PTR(d
->wd
));
1549 if (j
->inotify_fd
>= 0)
1550 inotify_rm_watch(j
->inotify_fd
, d
->wd
);
1553 hashmap_remove(j
->directories_by_path
, d
->path
);
1556 log_debug("Root directory %s removed.", d
->path
);
1558 log_debug("Directory %s removed.", d
->path
);
1564 static int add_search_paths(sd_journal
*j
) {
1566 static const char search_paths
[] =
1567 "/run/log/journal\0"
1568 "/var/log/journal\0";
1573 /* We ignore most errors here, since the idea is to only open
1574 * what's actually accessible, and ignore the rest. */
1576 NULSTR_FOREACH(p
, search_paths
)
1577 (void) add_root_directory(j
, p
, true);
1582 static int add_current_paths(sd_journal
*j
) {
1587 assert(j
->no_new_files
);
1589 /* Simply adds all directories for files we have open as
1590 * "root" directories. We don't expect errors here, so we
1591 * treat them as fatal. */
1593 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1594 _cleanup_free_
char *dir
;
1597 dir
= dirname_malloc(f
->path
);
1601 r
= add_root_directory(j
, dir
, true);
1609 static int allocate_inotify(sd_journal
*j
) {
1612 if (j
->inotify_fd
< 0) {
1613 j
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1614 if (j
->inotify_fd
< 0)
1618 if (!j
->directories_by_wd
) {
1619 j
->directories_by_wd
= hashmap_new(NULL
);
1620 if (!j
->directories_by_wd
)
1627 static sd_journal
*journal_new(int flags
, const char *path
) {
1630 j
= new0(sd_journal
, 1);
1634 j
->original_pid
= getpid();
1637 j
->data_threshold
= DEFAULT_DATA_THRESHOLD
;
1640 j
->path
= strdup(path
);
1645 j
->files
= ordered_hashmap_new(&string_hash_ops
);
1646 j
->directories_by_path
= hashmap_new(&string_hash_ops
);
1647 j
->mmap
= mmap_cache_new();
1648 if (!j
->files
|| !j
->directories_by_path
|| !j
->mmap
)
1654 sd_journal_close(j
);
1658 _public_
int sd_journal_open(sd_journal
**ret
, int flags
) {
1662 assert_return(ret
, -EINVAL
);
1663 assert_return((flags
& ~(SD_JOURNAL_LOCAL_ONLY
|SD_JOURNAL_RUNTIME_ONLY
|SD_JOURNAL_SYSTEM
|SD_JOURNAL_CURRENT_USER
)) == 0, -EINVAL
);
1665 j
= journal_new(flags
, NULL
);
1669 r
= add_search_paths(j
);
1677 sd_journal_close(j
);
1682 _public_
int sd_journal_open_container(sd_journal
**ret
, const char *machine
, int flags
) {
1683 _cleanup_free_
char *root
= NULL
, *class = NULL
;
1688 assert_return(machine
, -EINVAL
);
1689 assert_return(ret
, -EINVAL
);
1690 assert_return((flags
& ~(SD_JOURNAL_LOCAL_ONLY
|SD_JOURNAL_SYSTEM
)) == 0, -EINVAL
);
1691 assert_return(machine_name_is_valid(machine
), -EINVAL
);
1693 p
= strjoina("/run/systemd/machines/", machine
);
1694 r
= parse_env_file(p
, NEWLINE
, "ROOT", &root
, "CLASS", &class, NULL
);
1702 if (!streq_ptr(class, "container"))
1705 j
= journal_new(flags
, NULL
);
1712 r
= add_search_paths(j
);
1720 sd_journal_close(j
);
1724 _public_
int sd_journal_open_directory(sd_journal
**ret
, const char *path
, int flags
) {
1728 assert_return(ret
, -EINVAL
);
1729 assert_return(path
, -EINVAL
);
1730 assert_return(flags
== 0, -EINVAL
);
1732 j
= journal_new(flags
, path
);
1736 r
= add_root_directory(j
, path
, false);
1744 sd_journal_close(j
);
1749 _public_
int sd_journal_open_files(sd_journal
**ret
, const char **paths
, int flags
) {
1754 assert_return(ret
, -EINVAL
);
1755 assert_return(flags
== 0, -EINVAL
);
1757 j
= journal_new(flags
, NULL
);
1761 STRV_FOREACH(path
, paths
) {
1762 r
= add_any_file(j
, *path
);
1767 j
->no_new_files
= true;
1773 sd_journal_close(j
);
1778 _public_
void sd_journal_close(sd_journal
*j
) {
1786 sd_journal_flush_matches(j
);
1788 while ((f
= ordered_hashmap_steal_first(j
->files
)))
1789 journal_file_close(f
);
1791 ordered_hashmap_free(j
->files
);
1793 while ((d
= hashmap_first(j
->directories_by_path
)))
1794 remove_directory(j
, d
);
1796 while ((d
= hashmap_first(j
->directories_by_wd
)))
1797 remove_directory(j
, d
);
1799 hashmap_free(j
->directories_by_path
);
1800 hashmap_free(j
->directories_by_wd
);
1802 safe_close(j
->inotify_fd
);
1805 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j
->mmap
), mmap_cache_get_missed(j
->mmap
));
1806 mmap_cache_unref(j
->mmap
);
1809 while ((p
= hashmap_steal_first(j
->errors
)))
1811 hashmap_free(j
->errors
);
1815 free(j
->unique_field
);
1816 free(j
->fields_buffer
);
1820 _public_
int sd_journal_get_realtime_usec(sd_journal
*j
, uint64_t *ret
) {
1825 assert_return(j
, -EINVAL
);
1826 assert_return(!journal_pid_changed(j
), -ECHILD
);
1827 assert_return(ret
, -EINVAL
);
1829 f
= j
->current_file
;
1831 return -EADDRNOTAVAIL
;
1833 if (f
->current_offset
<= 0)
1834 return -EADDRNOTAVAIL
;
1836 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
1840 *ret
= le64toh(o
->entry
.realtime
);
1844 _public_
int sd_journal_get_monotonic_usec(sd_journal
*j
, uint64_t *ret
, sd_id128_t
*ret_boot_id
) {
1850 assert_return(j
, -EINVAL
);
1851 assert_return(!journal_pid_changed(j
), -ECHILD
);
1853 f
= j
->current_file
;
1855 return -EADDRNOTAVAIL
;
1857 if (f
->current_offset
<= 0)
1858 return -EADDRNOTAVAIL
;
1860 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
1865 *ret_boot_id
= o
->entry
.boot_id
;
1867 r
= sd_id128_get_boot(&id
);
1871 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1876 *ret
= le64toh(o
->entry
.monotonic
);
1881 static bool field_is_valid(const char *field
) {
1889 if (startswith(field
, "__"))
1892 for (p
= field
; *p
; p
++) {
1897 if (*p
>= 'A' && *p
<= 'Z')
1900 if (*p
>= '0' && *p
<= '9')
1909 _public_
int sd_journal_get_data(sd_journal
*j
, const char *field
, const void **data
, size_t *size
) {
1912 size_t field_length
;
1916 assert_return(j
, -EINVAL
);
1917 assert_return(!journal_pid_changed(j
), -ECHILD
);
1918 assert_return(field
, -EINVAL
);
1919 assert_return(data
, -EINVAL
);
1920 assert_return(size
, -EINVAL
);
1921 assert_return(field_is_valid(field
), -EINVAL
);
1923 f
= j
->current_file
;
1925 return -EADDRNOTAVAIL
;
1927 if (f
->current_offset
<= 0)
1928 return -EADDRNOTAVAIL
;
1930 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
1934 field_length
= strlen(field
);
1936 n
= journal_file_entry_n_items(o
);
1937 for (i
= 0; i
< n
; i
++) {
1943 p
= le64toh(o
->entry
.items
[i
].object_offset
);
1944 le_hash
= o
->entry
.items
[i
].hash
;
1945 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
1949 if (le_hash
!= o
->data
.hash
)
1952 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
1954 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
1956 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
1957 r
= decompress_startswith(compression
,
1959 &f
->compress_buffer
, &f
->compress_buffer_size
,
1960 field
, field_length
, '=');
1962 log_debug_errno(r
, "Cannot decompress %s object of length %zu at offset "OFSfmt
": %m",
1963 object_compressed_to_string(compression
), l
, p
);
1968 r
= decompress_blob(compression
,
1970 &f
->compress_buffer
, &f
->compress_buffer_size
, &rsize
,
1975 *data
= f
->compress_buffer
;
1976 *size
= (size_t) rsize
;
1981 return -EPROTONOSUPPORT
;
1983 } else if (l
>= field_length
+1 &&
1984 memcmp(o
->data
.payload
, field
, field_length
) == 0 &&
1985 o
->data
.payload
[field_length
] == '=') {
1989 if ((uint64_t) t
!= l
)
1992 *data
= o
->data
.payload
;
1998 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2006 static int return_data(sd_journal
*j
, JournalFile
*f
, Object
*o
, const void **data
, size_t *size
) {
2011 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
2014 /* We can't read objects larger than 4G on a 32bit machine */
2015 if ((uint64_t) t
!= l
)
2018 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
2020 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
2024 r
= decompress_blob(compression
,
2025 o
->data
.payload
, l
, &f
->compress_buffer
,
2026 &f
->compress_buffer_size
, &rsize
, j
->data_threshold
);
2030 *data
= f
->compress_buffer
;
2031 *size
= (size_t) rsize
;
2033 return -EPROTONOSUPPORT
;
2036 *data
= o
->data
.payload
;
2043 _public_
int sd_journal_enumerate_data(sd_journal
*j
, const void **data
, size_t *size
) {
2050 assert_return(j
, -EINVAL
);
2051 assert_return(!journal_pid_changed(j
), -ECHILD
);
2052 assert_return(data
, -EINVAL
);
2053 assert_return(size
, -EINVAL
);
2055 f
= j
->current_file
;
2057 return -EADDRNOTAVAIL
;
2059 if (f
->current_offset
<= 0)
2060 return -EADDRNOTAVAIL
;
2062 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2066 n
= journal_file_entry_n_items(o
);
2067 if (j
->current_field
>= n
)
2070 p
= le64toh(o
->entry
.items
[j
->current_field
].object_offset
);
2071 le_hash
= o
->entry
.items
[j
->current_field
].hash
;
2072 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2076 if (le_hash
!= o
->data
.hash
)
2079 r
= return_data(j
, f
, o
, data
, size
);
2083 j
->current_field
++;
2088 _public_
void sd_journal_restart_data(sd_journal
*j
) {
2092 j
->current_field
= 0;
2095 _public_
int sd_journal_get_fd(sd_journal
*j
) {
2098 assert_return(j
, -EINVAL
);
2099 assert_return(!journal_pid_changed(j
), -ECHILD
);
2101 if (j
->inotify_fd
>= 0)
2102 return j
->inotify_fd
;
2104 r
= allocate_inotify(j
);
2108 /* Iterate through all dirs again, to add them to the
2110 if (j
->no_new_files
)
2111 r
= add_current_paths(j
);
2113 r
= add_root_directory(j
, j
->path
, true);
2115 r
= add_search_paths(j
);
2119 return j
->inotify_fd
;
2122 _public_
int sd_journal_get_events(sd_journal
*j
) {
2125 assert_return(j
, -EINVAL
);
2126 assert_return(!journal_pid_changed(j
), -ECHILD
);
2128 fd
= sd_journal_get_fd(j
);
2135 _public_
int sd_journal_get_timeout(sd_journal
*j
, uint64_t *timeout_usec
) {
2138 assert_return(j
, -EINVAL
);
2139 assert_return(!journal_pid_changed(j
), -ECHILD
);
2140 assert_return(timeout_usec
, -EINVAL
);
2142 fd
= sd_journal_get_fd(j
);
2146 if (!j
->on_network
) {
2147 *timeout_usec
= (uint64_t) -1;
2151 /* If we are on the network we need to regularly check for
2152 * changes manually */
2154 *timeout_usec
= j
->last_process_usec
+ JOURNAL_FILES_RECHECK_USEC
;
2158 static void process_inotify_event(sd_journal
*j
, struct inotify_event
*e
) {
2164 /* Is this a subdirectory we watch? */
2165 d
= hashmap_get(j
->directories_by_wd
, INT_TO_PTR(e
->wd
));
2169 if (!(e
->mask
& IN_ISDIR
) && e
->len
> 0 &&
2170 (endswith(e
->name
, ".journal") ||
2171 endswith(e
->name
, ".journal~"))) {
2173 /* Event for a journal file */
2175 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2176 (void) add_file(j
, d
->path
, e
->name
);
2177 else if (e
->mask
& (IN_DELETE
|IN_MOVED_FROM
|IN_UNMOUNT
))
2178 remove_file(j
, d
->path
, e
->name
);
2180 } else if (!d
->is_root
&& e
->len
== 0) {
2182 /* Event for a subdirectory */
2184 if (e
->mask
& (IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
))
2185 remove_directory(j
, d
);
2187 } else if (d
->is_root
&& (e
->mask
& IN_ISDIR
) && e
->len
> 0 && sd_id128_from_string(e
->name
, &id
) >= 0) {
2189 /* Event for root directory */
2191 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
))
2192 (void) add_directory(j
, d
->path
, e
->name
);
2198 if (e
->mask
& IN_IGNORED
)
2201 log_debug("Unknown inotify event.");
2204 static int determine_change(sd_journal
*j
) {
2209 b
= j
->current_invalidate_counter
!= j
->last_invalidate_counter
;
2210 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2212 return b
? SD_JOURNAL_INVALIDATE
: SD_JOURNAL_APPEND
;
2215 _public_
int sd_journal_process(sd_journal
*j
) {
2216 bool got_something
= false;
2218 assert_return(j
, -EINVAL
);
2219 assert_return(!journal_pid_changed(j
), -ECHILD
);
2221 j
->last_process_usec
= now(CLOCK_MONOTONIC
);
2224 union inotify_event_buffer buffer
;
2225 struct inotify_event
*e
;
2228 l
= read(j
->inotify_fd
, &buffer
, sizeof(buffer
));
2230 if (errno
== EAGAIN
|| errno
== EINTR
)
2231 return got_something
? determine_change(j
) : SD_JOURNAL_NOP
;
2236 got_something
= true;
2238 FOREACH_INOTIFY_EVENT(e
, buffer
, l
)
2239 process_inotify_event(j
, e
);
2243 _public_
int sd_journal_wait(sd_journal
*j
, uint64_t timeout_usec
) {
2247 assert_return(j
, -EINVAL
);
2248 assert_return(!journal_pid_changed(j
), -ECHILD
);
2250 if (j
->inotify_fd
< 0) {
2252 /* This is the first invocation, hence create the
2254 r
= sd_journal_get_fd(j
);
2258 /* The journal might have changed since the context
2259 * object was created and we weren't watching before,
2260 * hence don't wait for anything, and return
2262 return determine_change(j
);
2265 r
= sd_journal_get_timeout(j
, &t
);
2269 if (t
!= (uint64_t) -1) {
2272 n
= now(CLOCK_MONOTONIC
);
2273 t
= t
> n
? t
- n
: 0;
2275 if (timeout_usec
== (uint64_t) -1 || timeout_usec
> t
)
2280 r
= fd_wait_for_event(j
->inotify_fd
, POLLIN
, timeout_usec
);
2281 } while (r
== -EINTR
);
2286 return sd_journal_process(j
);
2289 _public_
int sd_journal_get_cutoff_realtime_usec(sd_journal
*j
, uint64_t *from
, uint64_t *to
) {
2293 uint64_t fmin
= 0, tmax
= 0;
2296 assert_return(j
, -EINVAL
);
2297 assert_return(!journal_pid_changed(j
), -ECHILD
);
2298 assert_return(from
|| to
, -EINVAL
);
2299 assert_return(from
!= to
, -EINVAL
);
2301 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2304 r
= journal_file_get_cutoff_realtime_usec(f
, &fr
, &t
);
2317 fmin
= MIN(fr
, fmin
);
2318 tmax
= MAX(t
, tmax
);
2327 return first
? 0 : 1;
2330 _public_
int sd_journal_get_cutoff_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t *from
, uint64_t *to
) {
2336 assert_return(j
, -EINVAL
);
2337 assert_return(!journal_pid_changed(j
), -ECHILD
);
2338 assert_return(from
|| to
, -EINVAL
);
2339 assert_return(from
!= to
, -EINVAL
);
2341 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2344 r
= journal_file_get_cutoff_monotonic_usec(f
, boot_id
, &fr
, &t
);
2354 *from
= MIN(fr
, *from
);
2369 void journal_print_header(sd_journal
*j
) {
2372 bool newline
= false;
2376 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2382 journal_file_print_header(f
);
2386 _public_
int sd_journal_get_usage(sd_journal
*j
, uint64_t *bytes
) {
2391 assert_return(j
, -EINVAL
);
2392 assert_return(!journal_pid_changed(j
), -ECHILD
);
2393 assert_return(bytes
, -EINVAL
);
2395 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2398 if (fstat(f
->fd
, &st
) < 0)
2401 sum
+= (uint64_t) st
.st_blocks
* 512ULL;
2408 _public_
int sd_journal_query_unique(sd_journal
*j
, const char *field
) {
2411 assert_return(j
, -EINVAL
);
2412 assert_return(!journal_pid_changed(j
), -ECHILD
);
2413 assert_return(!isempty(field
), -EINVAL
);
2414 assert_return(field_is_valid(field
), -EINVAL
);
2420 free(j
->unique_field
);
2421 j
->unique_field
= f
;
2422 j
->unique_file
= NULL
;
2423 j
->unique_offset
= 0;
2424 j
->unique_file_lost
= false;
2429 _public_
int sd_journal_enumerate_unique(sd_journal
*j
, const void **data
, size_t *l
) {
2432 assert_return(j
, -EINVAL
);
2433 assert_return(!journal_pid_changed(j
), -ECHILD
);
2434 assert_return(data
, -EINVAL
);
2435 assert_return(l
, -EINVAL
);
2436 assert_return(j
->unique_field
, -EINVAL
);
2438 k
= strlen(j
->unique_field
);
2440 if (!j
->unique_file
) {
2441 if (j
->unique_file_lost
)
2444 j
->unique_file
= ordered_hashmap_first(j
->files
);
2445 if (!j
->unique_file
)
2448 j
->unique_offset
= 0;
2460 /* Proceed to next data object in the field's linked list */
2461 if (j
->unique_offset
== 0) {
2462 r
= journal_file_find_field_object(j
->unique_file
, j
->unique_field
, k
, &o
, NULL
);
2466 j
->unique_offset
= r
> 0 ? le64toh(o
->field
.head_data_offset
) : 0;
2468 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_DATA
, j
->unique_offset
, &o
);
2472 j
->unique_offset
= le64toh(o
->data
.next_field_offset
);
2475 /* We reached the end of the list? Then start again, with the next file */
2476 if (j
->unique_offset
== 0) {
2477 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
2478 if (!j
->unique_file
)
2484 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2485 * instead, so that we can look at this data object at the same
2486 * time as one on another file */
2487 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_UNUSED
, j
->unique_offset
, &o
);
2491 /* Let's do the type check by hand, since we used 0 context above. */
2492 if (o
->object
.type
!= OBJECT_DATA
) {
2493 log_debug("%s:offset " OFSfmt
": object has type %d, expected %d",
2494 j
->unique_file
->path
, j
->unique_offset
,
2495 o
->object
.type
, OBJECT_DATA
);
2499 r
= return_data(j
, j
->unique_file
, o
, &odata
, &ol
);
2503 /* Check if we have at least the field name and "=". */
2505 log_debug("%s:offset " OFSfmt
": object has size %zu, expected at least %zu",
2506 j
->unique_file
->path
, j
->unique_offset
,
2511 if (memcmp(odata
, j
->unique_field
, k
) || ((const char*) odata
)[k
] != '=') {
2512 log_debug("%s:offset " OFSfmt
": object does not start with \"%s=\"",
2513 j
->unique_file
->path
, j
->unique_offset
,
2518 /* OK, now let's see if we already returned this data
2519 * object by checking if it exists in the earlier
2520 * traversed files. */
2522 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2526 if (of
== j
->unique_file
)
2529 /* Skip this file it didn't have any fields
2531 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) &&
2532 le64toh(of
->header
->n_fields
) <= 0)
2535 r
= journal_file_find_data_object_with_hash(of
, odata
, ol
, le64toh(o
->data
.hash
), &oo
, &op
);
2546 r
= return_data(j
, j
->unique_file
, o
, data
, l
);
2554 _public_
void sd_journal_restart_unique(sd_journal
*j
) {
2558 j
->unique_file
= NULL
;
2559 j
->unique_offset
= 0;
2560 j
->unique_file_lost
= false;
2563 _public_
int sd_journal_enumerate_fields(sd_journal
*j
, const char **field
) {
2566 assert_return(j
, -EINVAL
);
2567 assert_return(!journal_pid_changed(j
), -ECHILD
);
2568 assert_return(field
, -EINVAL
);
2570 if (!j
->fields_file
) {
2571 if (j
->fields_file_lost
)
2574 j
->fields_file
= ordered_hashmap_first(j
->files
);
2575 if (!j
->fields_file
)
2578 j
->fields_hash_table_index
= 0;
2579 j
->fields_offset
= 0;
2583 JournalFile
*f
, *of
;
2592 if (j
->fields_offset
== 0) {
2595 /* We are not yet positioned at any field. Let's pick the first one */
2596 r
= journal_file_map_field_hash_table(f
);
2600 m
= le64toh(f
->header
->field_hash_table_size
) / sizeof(HashItem
);
2602 if (j
->fields_hash_table_index
>= m
) {
2603 /* Reached the end of the hash table, go to the next file. */
2608 j
->fields_offset
= le64toh(f
->field_hash_table
[j
->fields_hash_table_index
].head_hash_offset
);
2610 if (j
->fields_offset
!= 0)
2613 /* Empty hash table bucket, go to next one */
2614 j
->fields_hash_table_index
++;
2618 /* Proceed with next file */
2619 j
->fields_file
= ordered_hashmap_next(j
->files
, f
->path
);
2620 if (!j
->fields_file
) {
2625 j
->fields_offset
= 0;
2626 j
->fields_hash_table_index
= 0;
2631 /* We are already positioned at a field. If so, let's figure out the next field from it */
2633 r
= journal_file_move_to_object(f
, OBJECT_FIELD
, j
->fields_offset
, &o
);
2637 j
->fields_offset
= le64toh(o
->field
.next_hash_offset
);
2638 if (j
->fields_offset
== 0) {
2639 /* Reached the end of the hash table chain */
2640 j
->fields_hash_table_index
++;
2645 /* We use OBJECT_UNUSED here, so that the iteator below doesn't remove our mmap window */
2646 r
= journal_file_move_to_object(f
, OBJECT_UNUSED
, j
->fields_offset
, &o
);
2650 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
2651 if (o
->object
.type
!= OBJECT_FIELD
) {
2652 log_debug("%s:offset " OFSfmt
": object has type %i, expected %i", f
->path
, j
->fields_offset
, o
->object
.type
, OBJECT_FIELD
);
2656 sz
= le64toh(o
->object
.size
) - offsetof(Object
, field
.payload
);
2658 /* Let's see if we already returned this field name before. */
2660 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2664 /* Skip this file it didn't have any fields indexed */
2665 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) && le64toh(of
->header
->n_fields
) <= 0)
2668 r
= journal_file_find_field_object_with_hash(of
, o
->field
.payload
, sz
, le64toh(o
->field
.hash
), NULL
, NULL
);
2680 /* Check if this is really a valid string containing no NUL byte */
2681 if (memchr(o
->field
.payload
, 0, sz
))
2684 if (sz
> j
->data_threshold
)
2685 sz
= j
->data_threshold
;
2687 if (!GREEDY_REALLOC(j
->fields_buffer
, j
->fields_buffer_allocated
, sz
+ 1))
2690 memcpy(j
->fields_buffer
, o
->field
.payload
, sz
);
2691 j
->fields_buffer
[sz
] = 0;
2693 if (!field_is_valid(j
->fields_buffer
))
2696 *field
= j
->fields_buffer
;
2701 _public_
void sd_journal_restart_fields(sd_journal
*j
) {
2705 j
->fields_file
= NULL
;
2706 j
->fields_hash_table_index
= 0;
2707 j
->fields_offset
= 0;
2708 j
->fields_file_lost
= false;
2711 _public_
int sd_journal_reliable_fd(sd_journal
*j
) {
2712 assert_return(j
, -EINVAL
);
2713 assert_return(!journal_pid_changed(j
), -ECHILD
);
2715 return !j
->on_network
;
2718 static char *lookup_field(const char *field
, void *userdata
) {
2719 sd_journal
*j
= userdata
;
2727 r
= sd_journal_get_data(j
, field
, &data
, &size
);
2729 size
> REPLACE_VAR_MAX
)
2730 return strdup(field
);
2732 d
= strlen(field
) + 1;
2734 return strndup((const char*) data
+ d
, size
- d
);
2737 _public_
int sd_journal_get_catalog(sd_journal
*j
, char **ret
) {
2741 _cleanup_free_
char *text
= NULL
, *cid
= NULL
;
2745 assert_return(j
, -EINVAL
);
2746 assert_return(!journal_pid_changed(j
), -ECHILD
);
2747 assert_return(ret
, -EINVAL
);
2749 r
= sd_journal_get_data(j
, "MESSAGE_ID", &data
, &size
);
2753 cid
= strndup((const char*) data
+ 11, size
- 11);
2757 r
= sd_id128_from_string(cid
, &id
);
2761 r
= catalog_get(CATALOG_DATABASE
, id
, &text
);
2765 t
= replace_var(text
, lookup_field
, j
);
2773 _public_
int sd_journal_get_catalog_for_message_id(sd_id128_t id
, char **ret
) {
2774 assert_return(ret
, -EINVAL
);
2776 return catalog_get(CATALOG_DATABASE
, id
, ret
);
2779 _public_
int sd_journal_set_data_threshold(sd_journal
*j
, size_t sz
) {
2780 assert_return(j
, -EINVAL
);
2781 assert_return(!journal_pid_changed(j
), -ECHILD
);
2783 j
->data_threshold
= sz
;
2787 _public_
int sd_journal_get_data_threshold(sd_journal
*j
, size_t *sz
) {
2788 assert_return(j
, -EINVAL
);
2789 assert_return(!journal_pid_changed(j
), -ECHILD
);
2790 assert_return(sz
, -EINVAL
);
2792 *sz
= j
->data_threshold
;
2796 _public_
int sd_journal_has_runtime_files(sd_journal
*j
) {
2797 assert_return(j
, -EINVAL
);
2799 return j
->has_runtime_files
;
2802 _public_
int sd_journal_has_persistent_files(sd_journal
*j
) {
2803 assert_return(j
, -EINVAL
);
2805 return j
->has_persistent_files
;