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"
35 #include "dirent-util.h"
38 #include "formats-util.h"
40 #include "hostname-util.h"
42 #include "journal-def.h"
43 #include "journal-file.h"
44 #include "journal-internal.h"
48 #include "path-util.h"
49 #include "replace-var.h"
50 #include "string-util.h"
53 #define JOURNAL_FILES_MAX 7168
55 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
57 #define REPLACE_VAR_MAX 256
59 #define DEFAULT_DATA_THRESHOLD (64*1024)
61 static void remove_file_real(sd_journal
*j
, JournalFile
*f
);
63 static bool journal_pid_changed(sd_journal
*j
) {
66 /* We don't support people creating a journal object and
67 * keeping it around over a fork(). Let's complain. */
69 return j
->original_pid
!= getpid();
72 /* We return an error here only if we didn't manage to
73 memorize the real error. */
74 static int set_put_error(sd_journal
*j
, int r
) {
80 k
= set_ensure_allocated(&j
->errors
, NULL
);
84 return set_put(j
->errors
, INT_TO_PTR(r
));
87 static void detach_location(sd_journal
*j
) {
93 j
->current_file
= NULL
;
96 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
)
97 journal_file_reset_location(f
);
100 static void reset_location(sd_journal
*j
) {
104 zero(j
->current_location
);
107 static void init_location(Location
*l
, LocationType type
, JournalFile
*f
, Object
*o
) {
109 assert(type
== LOCATION_DISCRETE
|| type
== LOCATION_SEEK
);
111 assert(o
->object
.type
== OBJECT_ENTRY
);
114 l
->seqnum
= le64toh(o
->entry
.seqnum
);
115 l
->seqnum_id
= f
->header
->seqnum_id
;
116 l
->realtime
= le64toh(o
->entry
.realtime
);
117 l
->monotonic
= le64toh(o
->entry
.monotonic
);
118 l
->boot_id
= o
->entry
.boot_id
;
119 l
->xor_hash
= le64toh(o
->entry
.xor_hash
);
121 l
->seqnum_set
= l
->realtime_set
= l
->monotonic_set
= l
->xor_hash_set
= true;
124 static void set_location(sd_journal
*j
, JournalFile
*f
, Object
*o
) {
129 init_location(&j
->current_location
, LOCATION_DISCRETE
, f
, o
);
132 j
->current_field
= 0;
134 /* Let f know its candidate entry was picked. */
135 assert(f
->location_type
== LOCATION_SEEK
);
136 f
->location_type
= LOCATION_DISCRETE
;
139 static int match_is_valid(const void *data
, size_t size
) {
147 if (startswith(data
, "__"))
151 for (p
= b
; p
< b
+ size
; p
++) {
159 if (*p
>= 'A' && *p
<= 'Z')
162 if (*p
>= '0' && *p
<= '9')
171 static bool same_field(const void *_a
, size_t s
, const void *_b
, size_t t
) {
172 const uint8_t *a
= _a
, *b
= _b
;
175 for (j
= 0; j
< s
&& j
< t
; j
++) {
184 assert_not_reached("\"=\" not found");
187 static Match
*match_new(Match
*p
, MatchType t
) {
198 LIST_PREPEND(matches
, p
->matches
, m
);
204 static void match_free(Match
*m
) {
208 match_free(m
->matches
);
211 LIST_REMOVE(matches
, m
->parent
->matches
, m
);
217 static void match_free_if_empty(Match
*m
) {
218 if (!m
|| m
->matches
)
224 _public_
int sd_journal_add_match(sd_journal
*j
, const void *data
, size_t size
) {
225 Match
*l3
, *l4
, *add_here
= NULL
, *m
;
228 assert_return(j
, -EINVAL
);
229 assert_return(!journal_pid_changed(j
), -ECHILD
);
230 assert_return(data
, -EINVAL
);
235 assert_return(match_is_valid(data
, size
), -EINVAL
);
241 * level 4: concrete matches */
244 j
->level0
= match_new(NULL
, MATCH_AND_TERM
);
250 j
->level1
= match_new(j
->level0
, MATCH_OR_TERM
);
256 j
->level2
= match_new(j
->level1
, MATCH_AND_TERM
);
261 assert(j
->level0
->type
== MATCH_AND_TERM
);
262 assert(j
->level1
->type
== MATCH_OR_TERM
);
263 assert(j
->level2
->type
== MATCH_AND_TERM
);
265 le_hash
= htole64(hash64(data
, size
));
267 LIST_FOREACH(matches
, l3
, j
->level2
->matches
) {
268 assert(l3
->type
== MATCH_OR_TERM
);
270 LIST_FOREACH(matches
, l4
, l3
->matches
) {
271 assert(l4
->type
== MATCH_DISCRETE
);
273 /* Exactly the same match already? Then ignore
275 if (l4
->le_hash
== le_hash
&&
277 memcmp(l4
->data
, data
, size
) == 0)
280 /* Same field? Then let's add this to this OR term */
281 if (same_field(data
, size
, l4
->data
, l4
->size
)) {
292 add_here
= match_new(j
->level2
, MATCH_OR_TERM
);
297 m
= match_new(add_here
, MATCH_DISCRETE
);
301 m
->le_hash
= le_hash
;
303 m
->data
= memdup(data
, size
);
312 match_free_if_empty(add_here
);
313 match_free_if_empty(j
->level2
);
314 match_free_if_empty(j
->level1
);
315 match_free_if_empty(j
->level0
);
320 _public_
int sd_journal_add_conjunction(sd_journal
*j
) {
321 assert_return(j
, -EINVAL
);
322 assert_return(!journal_pid_changed(j
), -ECHILD
);
330 if (!j
->level1
->matches
)
339 _public_
int sd_journal_add_disjunction(sd_journal
*j
) {
340 assert_return(j
, -EINVAL
);
341 assert_return(!journal_pid_changed(j
), -ECHILD
);
352 if (!j
->level2
->matches
)
359 static char *match_make_string(Match
*m
) {
362 bool enclose
= false;
365 return strdup("none");
367 if (m
->type
== MATCH_DISCRETE
)
368 return strndup(m
->data
, m
->size
);
371 LIST_FOREACH(matches
, i
, m
->matches
) {
374 t
= match_make_string(i
);
381 k
= strjoin(p
, m
->type
== MATCH_OR_TERM
? " OR " : " AND ", t
, NULL
);
396 r
= strjoin("(", p
, ")", NULL
);
404 char *journal_make_match_string(sd_journal
*j
) {
407 return match_make_string(j
->level0
);
410 _public_
void sd_journal_flush_matches(sd_journal
*j
) {
415 match_free(j
->level0
);
417 j
->level0
= j
->level1
= j
->level2
= NULL
;
422 _pure_
static int compare_with_location(JournalFile
*f
, Location
*l
) {
425 assert(f
->location_type
== LOCATION_SEEK
);
426 assert(l
->type
== LOCATION_DISCRETE
|| l
->type
== LOCATION_SEEK
);
428 if (l
->monotonic_set
&&
429 sd_id128_equal(f
->current_boot_id
, l
->boot_id
) &&
431 f
->current_realtime
== l
->realtime
&&
433 f
->current_xor_hash
== l
->xor_hash
)
437 sd_id128_equal(f
->header
->seqnum_id
, l
->seqnum_id
)) {
439 if (f
->current_seqnum
< l
->seqnum
)
441 if (f
->current_seqnum
> l
->seqnum
)
445 if (l
->monotonic_set
&&
446 sd_id128_equal(f
->current_boot_id
, l
->boot_id
)) {
448 if (f
->current_monotonic
< l
->monotonic
)
450 if (f
->current_monotonic
> l
->monotonic
)
454 if (l
->realtime_set
) {
456 if (f
->current_realtime
< l
->realtime
)
458 if (f
->current_realtime
> l
->realtime
)
462 if (l
->xor_hash_set
) {
464 if (f
->current_xor_hash
< l
->xor_hash
)
466 if (f
->current_xor_hash
> l
->xor_hash
)
473 static int next_for_match(
477 uint64_t after_offset
,
478 direction_t direction
,
490 if (m
->type
== MATCH_DISCRETE
) {
493 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
497 return journal_file_move_to_entry_by_offset_for_data(f
, dp
, after_offset
, direction
, ret
, offset
);
499 } else if (m
->type
== MATCH_OR_TERM
) {
502 /* Find the earliest match beyond after_offset */
504 LIST_FOREACH(matches
, i
, m
->matches
) {
507 r
= next_for_match(j
, i
, f
, after_offset
, direction
, NULL
, &cp
);
511 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
< np
: cp
> np
))
519 } else if (m
->type
== MATCH_AND_TERM
) {
520 Match
*i
, *last_moved
;
522 /* Always jump to the next matching entry and repeat
523 * this until we find an offset that matches for all
529 r
= next_for_match(j
, m
->matches
, f
, after_offset
, direction
, NULL
, &np
);
533 assert(direction
== DIRECTION_DOWN
? np
>= after_offset
: np
<= after_offset
);
534 last_moved
= m
->matches
;
536 LIST_LOOP_BUT_ONE(matches
, i
, m
->matches
, last_moved
) {
539 r
= next_for_match(j
, i
, f
, np
, direction
, NULL
, &cp
);
543 assert(direction
== DIRECTION_DOWN
? cp
>= np
: cp
<= np
);
544 if (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
) {
553 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
565 static int find_location_for_match(
569 direction_t direction
,
579 if (m
->type
== MATCH_DISCRETE
) {
582 r
= journal_file_find_data_object_with_hash(f
, m
->data
, m
->size
, le64toh(m
->le_hash
), NULL
, &dp
);
586 /* FIXME: missing: find by monotonic */
588 if (j
->current_location
.type
== LOCATION_HEAD
)
589 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_DOWN
, ret
, offset
);
590 if (j
->current_location
.type
== LOCATION_TAIL
)
591 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, DIRECTION_UP
, ret
, offset
);
592 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
593 return journal_file_move_to_entry_by_seqnum_for_data(f
, dp
, j
->current_location
.seqnum
, direction
, ret
, offset
);
594 if (j
->current_location
.monotonic_set
) {
595 r
= journal_file_move_to_entry_by_monotonic_for_data(f
, dp
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
599 if (j
->current_location
.realtime_set
)
600 return journal_file_move_to_entry_by_realtime_for_data(f
, dp
, j
->current_location
.realtime
, direction
, ret
, offset
);
602 return journal_file_next_entry_for_data(f
, NULL
, 0, dp
, direction
, ret
, offset
);
604 } else if (m
->type
== MATCH_OR_TERM
) {
609 /* Find the earliest match */
611 LIST_FOREACH(matches
, i
, m
->matches
) {
614 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
618 if (np
== 0 || (direction
== DIRECTION_DOWN
? np
> cp
: np
< cp
))
626 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, np
, &n
);
641 assert(m
->type
== MATCH_AND_TERM
);
643 /* First jump to the last match, and then find the
644 * next one where all matches match */
649 LIST_FOREACH(matches
, i
, m
->matches
) {
652 r
= find_location_for_match(j
, i
, f
, direction
, NULL
, &cp
);
656 if (np
== 0 || (direction
== DIRECTION_DOWN
? cp
> np
: cp
< np
))
660 return next_for_match(j
, m
, f
, np
, direction
, ret
, offset
);
664 static int find_location_with_matches(
667 direction_t direction
,
679 /* No matches is simple */
681 if (j
->current_location
.type
== LOCATION_HEAD
)
682 return journal_file_next_entry(f
, 0, DIRECTION_DOWN
, ret
, offset
);
683 if (j
->current_location
.type
== LOCATION_TAIL
)
684 return journal_file_next_entry(f
, 0, DIRECTION_UP
, ret
, offset
);
685 if (j
->current_location
.seqnum_set
&& sd_id128_equal(j
->current_location
.seqnum_id
, f
->header
->seqnum_id
))
686 return journal_file_move_to_entry_by_seqnum(f
, j
->current_location
.seqnum
, direction
, ret
, offset
);
687 if (j
->current_location
.monotonic_set
) {
688 r
= journal_file_move_to_entry_by_monotonic(f
, j
->current_location
.boot_id
, j
->current_location
.monotonic
, direction
, ret
, offset
);
692 if (j
->current_location
.realtime_set
)
693 return journal_file_move_to_entry_by_realtime(f
, j
->current_location
.realtime
, direction
, ret
, offset
);
695 return journal_file_next_entry(f
, 0, direction
, ret
, offset
);
697 return find_location_for_match(j
, j
->level0
, f
, direction
, ret
, offset
);
700 static int next_with_matches(
703 direction_t direction
,
712 /* No matches is easy. We simple advance the file
715 return journal_file_next_entry(f
, f
->current_offset
, direction
, ret
, offset
);
717 /* If we have a match then we look for the next matching entry
718 * with an offset at least one step larger */
719 return next_for_match(j
, j
->level0
, f
,
720 direction
== DIRECTION_DOWN
? f
->current_offset
+ 1
721 : f
->current_offset
- 1,
722 direction
, ret
, offset
);
725 static int next_beyond_location(sd_journal
*j
, JournalFile
*f
, direction_t direction
) {
727 uint64_t cp
, n_entries
;
733 n_entries
= le64toh(f
->header
->n_entries
);
735 /* If we hit EOF before, we don't need to look into this file again
736 * unless direction changed or new entries appeared. */
737 if (f
->last_direction
== direction
&& f
->location_type
== LOCATION_TAIL
&&
738 n_entries
== f
->last_n_entries
)
741 f
->last_n_entries
= n_entries
;
743 if (f
->last_direction
== direction
&& f
->current_offset
> 0) {
744 /* LOCATION_SEEK here means we did the work in a previous
745 * iteration and the current location already points to a
746 * candidate entry. */
747 if (f
->location_type
!= LOCATION_SEEK
) {
748 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
752 journal_file_save_location(f
, c
, cp
);
755 f
->last_direction
= direction
;
757 r
= find_location_with_matches(j
, f
, direction
, &c
, &cp
);
761 journal_file_save_location(f
, c
, cp
);
764 /* OK, we found the spot, now let's advance until an entry
765 * that is actually different from what we were previously
766 * looking at. This is necessary to handle entries which exist
767 * in two (or more) journal files, and which shall all be
768 * suppressed but one. */
773 if (j
->current_location
.type
== LOCATION_DISCRETE
) {
776 k
= compare_with_location(f
, &j
->current_location
);
778 found
= direction
== DIRECTION_DOWN
? k
> 0 : k
< 0;
785 r
= next_with_matches(j
, f
, direction
, &c
, &cp
);
789 journal_file_save_location(f
, c
, cp
);
793 static int real_journal_next(sd_journal
*j
, direction_t direction
) {
794 JournalFile
*f
, *new_file
= NULL
;
799 assert_return(j
, -EINVAL
);
800 assert_return(!journal_pid_changed(j
), -ECHILD
);
802 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
805 r
= next_beyond_location(j
, f
, direction
);
807 log_debug_errno(r
, "Can't iterate through %s, ignoring: %m", f
->path
);
808 remove_file_real(j
, f
);
811 f
->location_type
= LOCATION_TAIL
;
820 k
= journal_file_compare_locations(f
, new_file
);
822 found
= direction
== DIRECTION_DOWN
? k
< 0 : k
> 0;
832 r
= journal_file_move_to_object(new_file
, OBJECT_ENTRY
, new_file
->current_offset
, &o
);
836 set_location(j
, new_file
, o
);
841 _public_
int sd_journal_next(sd_journal
*j
) {
842 return real_journal_next(j
, DIRECTION_DOWN
);
845 _public_
int sd_journal_previous(sd_journal
*j
) {
846 return real_journal_next(j
, DIRECTION_UP
);
849 static int real_journal_next_skip(sd_journal
*j
, direction_t direction
, uint64_t skip
) {
852 assert_return(j
, -EINVAL
);
853 assert_return(!journal_pid_changed(j
), -ECHILD
);
856 /* If this is not a discrete skip, then at least
857 * resolve the current location */
858 if (j
->current_location
.type
!= LOCATION_DISCRETE
)
859 return real_journal_next(j
, direction
);
865 r
= real_journal_next(j
, direction
);
879 _public_
int sd_journal_next_skip(sd_journal
*j
, uint64_t skip
) {
880 return real_journal_next_skip(j
, DIRECTION_DOWN
, skip
);
883 _public_
int sd_journal_previous_skip(sd_journal
*j
, uint64_t skip
) {
884 return real_journal_next_skip(j
, DIRECTION_UP
, skip
);
887 _public_
int sd_journal_get_cursor(sd_journal
*j
, char **cursor
) {
890 char bid
[33], sid
[33];
892 assert_return(j
, -EINVAL
);
893 assert_return(!journal_pid_changed(j
), -ECHILD
);
894 assert_return(cursor
, -EINVAL
);
896 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
897 return -EADDRNOTAVAIL
;
899 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
903 sd_id128_to_string(j
->current_file
->header
->seqnum_id
, sid
);
904 sd_id128_to_string(o
->entry
.boot_id
, bid
);
907 "s=%s;i=%"PRIx64
";b=%s;m=%"PRIx64
";t=%"PRIx64
";x=%"PRIx64
,
908 sid
, le64toh(o
->entry
.seqnum
),
909 bid
, le64toh(o
->entry
.monotonic
),
910 le64toh(o
->entry
.realtime
),
911 le64toh(o
->entry
.xor_hash
)) < 0)
917 _public_
int sd_journal_seek_cursor(sd_journal
*j
, const char *cursor
) {
918 const char *word
, *state
;
920 unsigned long long seqnum
, monotonic
, realtime
, xor_hash
;
922 seqnum_id_set
= false,
925 monotonic_set
= false,
926 realtime_set
= false,
927 xor_hash_set
= false;
928 sd_id128_t seqnum_id
, boot_id
;
930 assert_return(j
, -EINVAL
);
931 assert_return(!journal_pid_changed(j
), -ECHILD
);
932 assert_return(!isempty(cursor
), -EINVAL
);
934 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
938 if (l
< 2 || word
[1] != '=')
941 item
= strndup(word
, l
);
948 seqnum_id_set
= true;
949 k
= sd_id128_from_string(item
+2, &seqnum_id
);
954 if (sscanf(item
+2, "%llx", &seqnum
) != 1)
960 k
= sd_id128_from_string(item
+2, &boot_id
);
964 monotonic_set
= true;
965 if (sscanf(item
+2, "%llx", &monotonic
) != 1)
971 if (sscanf(item
+2, "%llx", &realtime
) != 1)
977 if (sscanf(item
+2, "%llx", &xor_hash
) != 1)
988 if ((!seqnum_set
|| !seqnum_id_set
) &&
989 (!monotonic_set
|| !boot_id_set
) &&
995 j
->current_location
.type
= LOCATION_SEEK
;
998 j
->current_location
.realtime
= (uint64_t) realtime
;
999 j
->current_location
.realtime_set
= true;
1002 if (seqnum_set
&& seqnum_id_set
) {
1003 j
->current_location
.seqnum
= (uint64_t) seqnum
;
1004 j
->current_location
.seqnum_id
= seqnum_id
;
1005 j
->current_location
.seqnum_set
= true;
1008 if (monotonic_set
&& boot_id_set
) {
1009 j
->current_location
.monotonic
= (uint64_t) monotonic
;
1010 j
->current_location
.boot_id
= boot_id
;
1011 j
->current_location
.monotonic_set
= true;
1015 j
->current_location
.xor_hash
= (uint64_t) xor_hash
;
1016 j
->current_location
.xor_hash_set
= true;
1022 _public_
int sd_journal_test_cursor(sd_journal
*j
, const char *cursor
) {
1024 const char *word
, *state
;
1028 assert_return(j
, -EINVAL
);
1029 assert_return(!journal_pid_changed(j
), -ECHILD
);
1030 assert_return(!isempty(cursor
), -EINVAL
);
1032 if (!j
->current_file
|| j
->current_file
->current_offset
<= 0)
1033 return -EADDRNOTAVAIL
;
1035 r
= journal_file_move_to_object(j
->current_file
, OBJECT_ENTRY
, j
->current_file
->current_offset
, &o
);
1039 FOREACH_WORD_SEPARATOR(word
, l
, cursor
, ";", state
) {
1040 _cleanup_free_
char *item
= NULL
;
1042 unsigned long long ll
;
1045 if (l
< 2 || word
[1] != '=')
1048 item
= strndup(word
, l
);
1055 k
= sd_id128_from_string(item
+2, &id
);
1058 if (!sd_id128_equal(id
, j
->current_file
->header
->seqnum_id
))
1063 if (sscanf(item
+2, "%llx", &ll
) != 1)
1065 if (ll
!= le64toh(o
->entry
.seqnum
))
1070 k
= sd_id128_from_string(item
+2, &id
);
1073 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1078 if (sscanf(item
+2, "%llx", &ll
) != 1)
1080 if (ll
!= le64toh(o
->entry
.monotonic
))
1085 if (sscanf(item
+2, "%llx", &ll
) != 1)
1087 if (ll
!= le64toh(o
->entry
.realtime
))
1092 if (sscanf(item
+2, "%llx", &ll
) != 1)
1094 if (ll
!= le64toh(o
->entry
.xor_hash
))
1104 _public_
int sd_journal_seek_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t usec
) {
1105 assert_return(j
, -EINVAL
);
1106 assert_return(!journal_pid_changed(j
), -ECHILD
);
1109 j
->current_location
.type
= LOCATION_SEEK
;
1110 j
->current_location
.boot_id
= boot_id
;
1111 j
->current_location
.monotonic
= usec
;
1112 j
->current_location
.monotonic_set
= true;
1117 _public_
int sd_journal_seek_realtime_usec(sd_journal
*j
, uint64_t usec
) {
1118 assert_return(j
, -EINVAL
);
1119 assert_return(!journal_pid_changed(j
), -ECHILD
);
1122 j
->current_location
.type
= LOCATION_SEEK
;
1123 j
->current_location
.realtime
= usec
;
1124 j
->current_location
.realtime_set
= true;
1129 _public_
int sd_journal_seek_head(sd_journal
*j
) {
1130 assert_return(j
, -EINVAL
);
1131 assert_return(!journal_pid_changed(j
), -ECHILD
);
1134 j
->current_location
.type
= LOCATION_HEAD
;
1139 _public_
int sd_journal_seek_tail(sd_journal
*j
) {
1140 assert_return(j
, -EINVAL
);
1141 assert_return(!journal_pid_changed(j
), -ECHILD
);
1144 j
->current_location
.type
= LOCATION_TAIL
;
1149 static void check_network(sd_journal
*j
, int fd
) {
1157 if (fstatfs(fd
, &sfs
) < 0)
1161 F_TYPE_EQUAL(sfs
.f_type
, CIFS_MAGIC_NUMBER
) ||
1162 F_TYPE_EQUAL(sfs
.f_type
, CODA_SUPER_MAGIC
) ||
1163 F_TYPE_EQUAL(sfs
.f_type
, NCP_SUPER_MAGIC
) ||
1164 F_TYPE_EQUAL(sfs
.f_type
, NFS_SUPER_MAGIC
) ||
1165 F_TYPE_EQUAL(sfs
.f_type
, SMB_SUPER_MAGIC
);
1168 static bool file_has_type_prefix(const char *prefix
, const char *filename
) {
1169 const char *full
, *tilded
, *atted
;
1171 full
= strjoina(prefix
, ".journal");
1172 tilded
= strjoina(full
, "~");
1173 atted
= strjoina(prefix
, "@");
1175 return streq(filename
, full
) ||
1176 streq(filename
, tilded
) ||
1177 startswith(filename
, atted
);
1180 static bool file_type_wanted(int flags
, const char *filename
) {
1181 if (!endswith(filename
, ".journal") && !endswith(filename
, ".journal~"))
1184 /* no flags set → every type is OK */
1185 if (!(flags
& (SD_JOURNAL_SYSTEM
| SD_JOURNAL_CURRENT_USER
)))
1188 if (flags
& SD_JOURNAL_SYSTEM
&& file_has_type_prefix("system", filename
))
1191 if (flags
& SD_JOURNAL_CURRENT_USER
) {
1192 char prefix
[5 + DECIMAL_STR_MAX(uid_t
) + 1];
1194 xsprintf(prefix
, "user-"UID_FMT
, getuid());
1196 if (file_has_type_prefix(prefix
, filename
))
1203 static int add_any_file(sd_journal
*j
, const char *path
) {
1204 JournalFile
*f
= NULL
;
1210 if (ordered_hashmap_get(j
->files
, path
))
1213 if (ordered_hashmap_size(j
->files
) >= JOURNAL_FILES_MAX
) {
1214 log_warning("Too many open journal files, not adding %s.", path
);
1215 return set_put_error(j
, -ETOOMANYREFS
);
1218 r
= journal_file_open(path
, O_RDONLY
, 0, false, false, NULL
, j
->mmap
, NULL
, &f
);
1222 /* journal_file_dump(f); */
1224 r
= ordered_hashmap_put(j
->files
, f
->path
, f
);
1226 journal_file_close(f
);
1230 log_debug("File %s added.", f
->path
);
1232 check_network(j
, f
->fd
);
1234 j
->current_invalidate_counter
++;
1239 static int add_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1240 _cleanup_free_
char *path
= NULL
;
1247 if (j
->no_new_files
||
1248 !file_type_wanted(j
->flags
, filename
))
1251 path
= strjoin(prefix
, "/", filename
, NULL
);
1255 r
= add_any_file(j
, path
);
1261 static int remove_file(sd_journal
*j
, const char *prefix
, const char *filename
) {
1262 _cleanup_free_
char *path
;
1269 path
= strjoin(prefix
, "/", filename
, NULL
);
1273 f
= ordered_hashmap_get(j
->files
, path
);
1277 remove_file_real(j
, f
);
1281 static void remove_file_real(sd_journal
*j
, JournalFile
*f
) {
1285 ordered_hashmap_remove(j
->files
, f
->path
);
1287 log_debug("File %s removed.", f
->path
);
1289 if (j
->current_file
== f
) {
1290 j
->current_file
= NULL
;
1291 j
->current_field
= 0;
1294 if (j
->unique_file
== f
) {
1295 /* Jump to the next unique_file or NULL if that one was last */
1296 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
1297 j
->unique_offset
= 0;
1298 if (!j
->unique_file
)
1299 j
->unique_file_lost
= true;
1302 journal_file_close(f
);
1304 j
->current_invalidate_counter
++;
1307 static int add_directory(sd_journal
*j
, const char *prefix
, const char *dirname
) {
1308 _cleanup_free_
char *path
= NULL
;
1310 _cleanup_closedir_
DIR *d
= NULL
;
1318 log_debug("Considering %s/%s.", prefix
, dirname
);
1320 if ((j
->flags
& SD_JOURNAL_LOCAL_ONLY
) &&
1321 (sd_id128_from_string(dirname
, &id
) < 0 ||
1322 sd_id128_get_machine(&mid
) < 0 ||
1323 !(sd_id128_equal(id
, mid
) || path_startswith(prefix
, "/run"))))
1326 path
= strjoin(prefix
, "/", dirname
, NULL
);
1332 log_debug_errno(errno
, "Failed to open %s: %m", path
);
1333 if (errno
== ENOENT
)
1338 m
= hashmap_get(j
->directories_by_path
, path
);
1340 m
= new0(Directory
, 1);
1347 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1352 path
= NULL
; /* avoid freeing in cleanup */
1353 j
->current_invalidate_counter
++;
1355 log_debug("Directory %s added.", m
->path
);
1357 } else if (m
->is_root
)
1360 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1362 m
->wd
= inotify_add_watch(j
->inotify_fd
, m
->path
,
1363 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1364 IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
|IN_MOVED_FROM
|
1367 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1368 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1376 if (!de
&& errno
!= 0) {
1378 log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
);
1384 if (dirent_is_file_with_suffix(de
, ".journal") ||
1385 dirent_is_file_with_suffix(de
, ".journal~")) {
1386 r
= add_file(j
, m
->path
, de
->d_name
);
1388 log_debug_errno(r
, "Failed to add file %s/%s: %m",
1389 m
->path
, de
->d_name
);
1390 r
= set_put_error(j
, r
);
1397 check_network(j
, dirfd(d
));
1402 static int add_root_directory(sd_journal
*j
, const char *p
) {
1403 _cleanup_closedir_
DIR *d
= NULL
;
1410 if ((j
->flags
& SD_JOURNAL_RUNTIME_ONLY
) &&
1411 !path_startswith(p
, "/run"))
1415 p
= strjoina(j
->prefix
, p
);
1421 m
= hashmap_get(j
->directories_by_path
, p
);
1423 m
= new0(Directory
, 1);
1428 m
->path
= strdup(p
);
1434 if (hashmap_put(j
->directories_by_path
, m
->path
, m
) < 0) {
1440 j
->current_invalidate_counter
++;
1442 log_debug("Root directory %s added.", m
->path
);
1444 } else if (!m
->is_root
)
1447 if (m
->wd
<= 0 && j
->inotify_fd
>= 0) {
1449 m
->wd
= inotify_add_watch(j
->inotify_fd
, m
->path
,
1450 IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
|IN_DELETE
|
1453 if (m
->wd
> 0 && hashmap_put(j
->directories_by_wd
, INT_TO_PTR(m
->wd
), m
) < 0)
1454 inotify_rm_watch(j
->inotify_fd
, m
->wd
);
1457 if (j
->no_new_files
)
1466 if (!de
&& errno
!= 0) {
1468 log_debug_errno(errno
, "Failed to read directory %s: %m", m
->path
);
1474 if (dirent_is_file_with_suffix(de
, ".journal") ||
1475 dirent_is_file_with_suffix(de
, ".journal~")) {
1476 r
= add_file(j
, m
->path
, de
->d_name
);
1478 log_debug_errno(r
, "Failed to add file %s/%s: %m",
1479 m
->path
, de
->d_name
);
1480 r
= set_put_error(j
, r
);
1484 } else if ((de
->d_type
== DT_DIR
|| de
->d_type
== DT_LNK
|| de
->d_type
== DT_UNKNOWN
) &&
1485 sd_id128_from_string(de
->d_name
, &id
) >= 0) {
1487 r
= add_directory(j
, m
->path
, de
->d_name
);
1489 log_debug_errno(r
, "Failed to add directory %s/%s: %m", m
->path
, de
->d_name
);
1493 check_network(j
, dirfd(d
));
1498 static void remove_directory(sd_journal
*j
, Directory
*d
) {
1502 hashmap_remove(j
->directories_by_wd
, INT_TO_PTR(d
->wd
));
1504 if (j
->inotify_fd
>= 0)
1505 inotify_rm_watch(j
->inotify_fd
, d
->wd
);
1508 hashmap_remove(j
->directories_by_path
, d
->path
);
1511 log_debug("Root directory %s removed.", d
->path
);
1513 log_debug("Directory %s removed.", d
->path
);
1519 static int add_search_paths(sd_journal
*j
) {
1521 const char search_paths
[] =
1522 "/run/log/journal\0"
1523 "/var/log/journal\0";
1528 /* We ignore most errors here, since the idea is to only open
1529 * what's actually accessible, and ignore the rest. */
1531 NULSTR_FOREACH(p
, search_paths
) {
1532 r
= add_root_directory(j
, p
);
1533 if (r
< 0 && r
!= -ENOENT
) {
1534 r
= set_put_error(j
, r
);
1543 static int add_current_paths(sd_journal
*j
) {
1548 assert(j
->no_new_files
);
1550 /* Simply adds all directories for files we have open as
1551 * "root" directories. We don't expect errors here, so we
1552 * treat them as fatal. */
1554 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
1555 _cleanup_free_
char *dir
;
1558 dir
= dirname_malloc(f
->path
);
1562 r
= add_root_directory(j
, dir
);
1564 set_put_error(j
, r
);
1573 static int allocate_inotify(sd_journal
*j
) {
1576 if (j
->inotify_fd
< 0) {
1577 j
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
1578 if (j
->inotify_fd
< 0)
1582 if (!j
->directories_by_wd
) {
1583 j
->directories_by_wd
= hashmap_new(NULL
);
1584 if (!j
->directories_by_wd
)
1591 static sd_journal
*journal_new(int flags
, const char *path
) {
1594 j
= new0(sd_journal
, 1);
1598 j
->original_pid
= getpid();
1601 j
->data_threshold
= DEFAULT_DATA_THRESHOLD
;
1604 j
->path
= strdup(path
);
1609 j
->files
= ordered_hashmap_new(&string_hash_ops
);
1610 j
->directories_by_path
= hashmap_new(&string_hash_ops
);
1611 j
->mmap
= mmap_cache_new();
1612 if (!j
->files
|| !j
->directories_by_path
|| !j
->mmap
)
1618 sd_journal_close(j
);
1622 _public_
int sd_journal_open(sd_journal
**ret
, int flags
) {
1626 assert_return(ret
, -EINVAL
);
1627 assert_return((flags
& ~(SD_JOURNAL_LOCAL_ONLY
|SD_JOURNAL_RUNTIME_ONLY
|SD_JOURNAL_SYSTEM
|SD_JOURNAL_CURRENT_USER
)) == 0, -EINVAL
);
1629 j
= journal_new(flags
, NULL
);
1633 r
= add_search_paths(j
);
1641 sd_journal_close(j
);
1646 _public_
int sd_journal_open_container(sd_journal
**ret
, const char *machine
, int flags
) {
1647 _cleanup_free_
char *root
= NULL
, *class = NULL
;
1652 assert_return(machine
, -EINVAL
);
1653 assert_return(ret
, -EINVAL
);
1654 assert_return((flags
& ~(SD_JOURNAL_LOCAL_ONLY
|SD_JOURNAL_SYSTEM
)) == 0, -EINVAL
);
1655 assert_return(machine_name_is_valid(machine
), -EINVAL
);
1657 p
= strjoina("/run/systemd/machines/", machine
);
1658 r
= parse_env_file(p
, NEWLINE
, "ROOT", &root
, "CLASS", &class, NULL
);
1666 if (!streq_ptr(class, "container"))
1669 j
= journal_new(flags
, NULL
);
1676 r
= add_search_paths(j
);
1684 sd_journal_close(j
);
1688 _public_
int sd_journal_open_directory(sd_journal
**ret
, const char *path
, int flags
) {
1692 assert_return(ret
, -EINVAL
);
1693 assert_return(path
, -EINVAL
);
1694 assert_return(flags
== 0, -EINVAL
);
1696 j
= journal_new(flags
, path
);
1700 r
= add_root_directory(j
, path
);
1702 set_put_error(j
, r
);
1710 sd_journal_close(j
);
1715 _public_
int sd_journal_open_files(sd_journal
**ret
, const char **paths
, int flags
) {
1720 assert_return(ret
, -EINVAL
);
1721 assert_return(flags
== 0, -EINVAL
);
1723 j
= journal_new(flags
, NULL
);
1727 STRV_FOREACH(path
, paths
) {
1728 r
= add_any_file(j
, *path
);
1730 log_error_errno(r
, "Failed to open %s: %m", *path
);
1735 j
->no_new_files
= true;
1741 sd_journal_close(j
);
1746 _public_
void sd_journal_close(sd_journal
*j
) {
1753 sd_journal_flush_matches(j
);
1755 while ((f
= ordered_hashmap_steal_first(j
->files
)))
1756 journal_file_close(f
);
1758 ordered_hashmap_free(j
->files
);
1760 while ((d
= hashmap_first(j
->directories_by_path
)))
1761 remove_directory(j
, d
);
1763 while ((d
= hashmap_first(j
->directories_by_wd
)))
1764 remove_directory(j
, d
);
1766 hashmap_free(j
->directories_by_path
);
1767 hashmap_free(j
->directories_by_wd
);
1769 safe_close(j
->inotify_fd
);
1772 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j
->mmap
), mmap_cache_get_missed(j
->mmap
));
1773 mmap_cache_unref(j
->mmap
);
1778 free(j
->unique_field
);
1779 set_free(j
->errors
);
1783 _public_
int sd_journal_get_realtime_usec(sd_journal
*j
, uint64_t *ret
) {
1788 assert_return(j
, -EINVAL
);
1789 assert_return(!journal_pid_changed(j
), -ECHILD
);
1790 assert_return(ret
, -EINVAL
);
1792 f
= j
->current_file
;
1794 return -EADDRNOTAVAIL
;
1796 if (f
->current_offset
<= 0)
1797 return -EADDRNOTAVAIL
;
1799 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
1803 *ret
= le64toh(o
->entry
.realtime
);
1807 _public_
int sd_journal_get_monotonic_usec(sd_journal
*j
, uint64_t *ret
, sd_id128_t
*ret_boot_id
) {
1813 assert_return(j
, -EINVAL
);
1814 assert_return(!journal_pid_changed(j
), -ECHILD
);
1816 f
= j
->current_file
;
1818 return -EADDRNOTAVAIL
;
1820 if (f
->current_offset
<= 0)
1821 return -EADDRNOTAVAIL
;
1823 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
1828 *ret_boot_id
= o
->entry
.boot_id
;
1830 r
= sd_id128_get_boot(&id
);
1834 if (!sd_id128_equal(id
, o
->entry
.boot_id
))
1839 *ret
= le64toh(o
->entry
.monotonic
);
1844 static bool field_is_valid(const char *field
) {
1852 if (startswith(field
, "__"))
1855 for (p
= field
; *p
; p
++) {
1860 if (*p
>= 'A' && *p
<= 'Z')
1863 if (*p
>= '0' && *p
<= '9')
1872 _public_
int sd_journal_get_data(sd_journal
*j
, const char *field
, const void **data
, size_t *size
) {
1875 size_t field_length
;
1879 assert_return(j
, -EINVAL
);
1880 assert_return(!journal_pid_changed(j
), -ECHILD
);
1881 assert_return(field
, -EINVAL
);
1882 assert_return(data
, -EINVAL
);
1883 assert_return(size
, -EINVAL
);
1884 assert_return(field_is_valid(field
), -EINVAL
);
1886 f
= j
->current_file
;
1888 return -EADDRNOTAVAIL
;
1890 if (f
->current_offset
<= 0)
1891 return -EADDRNOTAVAIL
;
1893 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
1897 field_length
= strlen(field
);
1899 n
= journal_file_entry_n_items(o
);
1900 for (i
= 0; i
< n
; i
++) {
1906 p
= le64toh(o
->entry
.items
[i
].object_offset
);
1907 le_hash
= o
->entry
.items
[i
].hash
;
1908 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
1912 if (le_hash
!= o
->data
.hash
)
1915 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
1917 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
1919 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
1920 if (decompress_startswith(compression
,
1922 &f
->compress_buffer
, &f
->compress_buffer_size
,
1923 field
, field_length
, '=')) {
1927 r
= decompress_blob(compression
,
1929 &f
->compress_buffer
, &f
->compress_buffer_size
, &rsize
,
1934 *data
= f
->compress_buffer
;
1935 *size
= (size_t) rsize
;
1940 return -EPROTONOSUPPORT
;
1942 } else if (l
>= field_length
+1 &&
1943 memcmp(o
->data
.payload
, field
, field_length
) == 0 &&
1944 o
->data
.payload
[field_length
] == '=') {
1948 if ((uint64_t) t
!= l
)
1951 *data
= o
->data
.payload
;
1957 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
1965 static int return_data(sd_journal
*j
, JournalFile
*f
, Object
*o
, const void **data
, size_t *size
) {
1970 l
= le64toh(o
->object
.size
) - offsetof(Object
, data
.payload
);
1973 /* We can't read objects larger than 4G on a 32bit machine */
1974 if ((uint64_t) t
!= l
)
1977 compression
= o
->object
.flags
& OBJECT_COMPRESSION_MASK
;
1979 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
1983 r
= decompress_blob(compression
,
1984 o
->data
.payload
, l
, &f
->compress_buffer
,
1985 &f
->compress_buffer_size
, &rsize
, j
->data_threshold
);
1989 *data
= f
->compress_buffer
;
1990 *size
= (size_t) rsize
;
1992 return -EPROTONOSUPPORT
;
1995 *data
= o
->data
.payload
;
2002 _public_
int sd_journal_enumerate_data(sd_journal
*j
, const void **data
, size_t *size
) {
2009 assert_return(j
, -EINVAL
);
2010 assert_return(!journal_pid_changed(j
), -ECHILD
);
2011 assert_return(data
, -EINVAL
);
2012 assert_return(size
, -EINVAL
);
2014 f
= j
->current_file
;
2016 return -EADDRNOTAVAIL
;
2018 if (f
->current_offset
<= 0)
2019 return -EADDRNOTAVAIL
;
2021 r
= journal_file_move_to_object(f
, OBJECT_ENTRY
, f
->current_offset
, &o
);
2025 n
= journal_file_entry_n_items(o
);
2026 if (j
->current_field
>= n
)
2029 p
= le64toh(o
->entry
.items
[j
->current_field
].object_offset
);
2030 le_hash
= o
->entry
.items
[j
->current_field
].hash
;
2031 r
= journal_file_move_to_object(f
, OBJECT_DATA
, p
, &o
);
2035 if (le_hash
!= o
->data
.hash
)
2038 r
= return_data(j
, f
, o
, data
, size
);
2042 j
->current_field
++;
2047 _public_
void sd_journal_restart_data(sd_journal
*j
) {
2051 j
->current_field
= 0;
2054 _public_
int sd_journal_get_fd(sd_journal
*j
) {
2057 assert_return(j
, -EINVAL
);
2058 assert_return(!journal_pid_changed(j
), -ECHILD
);
2060 if (j
->inotify_fd
>= 0)
2061 return j
->inotify_fd
;
2063 r
= allocate_inotify(j
);
2067 /* Iterate through all dirs again, to add them to the
2069 if (j
->no_new_files
)
2070 r
= add_current_paths(j
);
2072 r
= add_root_directory(j
, j
->path
);
2074 r
= add_search_paths(j
);
2078 return j
->inotify_fd
;
2081 _public_
int sd_journal_get_events(sd_journal
*j
) {
2084 assert_return(j
, -EINVAL
);
2085 assert_return(!journal_pid_changed(j
), -ECHILD
);
2087 fd
= sd_journal_get_fd(j
);
2094 _public_
int sd_journal_get_timeout(sd_journal
*j
, uint64_t *timeout_usec
) {
2097 assert_return(j
, -EINVAL
);
2098 assert_return(!journal_pid_changed(j
), -ECHILD
);
2099 assert_return(timeout_usec
, -EINVAL
);
2101 fd
= sd_journal_get_fd(j
);
2105 if (!j
->on_network
) {
2106 *timeout_usec
= (uint64_t) -1;
2110 /* If we are on the network we need to regularly check for
2111 * changes manually */
2113 *timeout_usec
= j
->last_process_usec
+ JOURNAL_FILES_RECHECK_USEC
;
2117 static void process_inotify_event(sd_journal
*j
, struct inotify_event
*e
) {
2124 /* Is this a subdirectory we watch? */
2125 d
= hashmap_get(j
->directories_by_wd
, INT_TO_PTR(e
->wd
));
2129 if (!(e
->mask
& IN_ISDIR
) && e
->len
> 0 &&
2130 (endswith(e
->name
, ".journal") ||
2131 endswith(e
->name
, ".journal~"))) {
2133 /* Event for a journal file */
2135 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
)) {
2136 r
= add_file(j
, d
->path
, e
->name
);
2138 log_debug_errno(r
, "Failed to add file %s/%s: %m",
2140 set_put_error(j
, r
);
2143 } else if (e
->mask
& (IN_DELETE
|IN_MOVED_FROM
|IN_UNMOUNT
)) {
2145 r
= remove_file(j
, d
->path
, e
->name
);
2147 log_debug_errno(r
, "Failed to remove file %s/%s: %m", d
->path
, e
->name
);
2150 } else if (!d
->is_root
&& e
->len
== 0) {
2152 /* Event for a subdirectory */
2154 if (e
->mask
& (IN_DELETE_SELF
|IN_MOVE_SELF
|IN_UNMOUNT
))
2155 remove_directory(j
, d
);
2157 } else if (d
->is_root
&& (e
->mask
& IN_ISDIR
) && e
->len
> 0 && sd_id128_from_string(e
->name
, &id
) >= 0) {
2159 /* Event for root directory */
2161 if (e
->mask
& (IN_CREATE
|IN_MOVED_TO
|IN_MODIFY
|IN_ATTRIB
)) {
2162 r
= add_directory(j
, d
->path
, e
->name
);
2164 log_debug_errno(r
, "Failed to add directory %s/%s: %m", d
->path
, e
->name
);
2171 if (e
->mask
& IN_IGNORED
)
2174 log_warning("Unknown inotify event.");
2177 static int determine_change(sd_journal
*j
) {
2182 b
= j
->current_invalidate_counter
!= j
->last_invalidate_counter
;
2183 j
->last_invalidate_counter
= j
->current_invalidate_counter
;
2185 return b
? SD_JOURNAL_INVALIDATE
: SD_JOURNAL_APPEND
;
2188 _public_
int sd_journal_process(sd_journal
*j
) {
2189 bool got_something
= false;
2191 assert_return(j
, -EINVAL
);
2192 assert_return(!journal_pid_changed(j
), -ECHILD
);
2194 j
->last_process_usec
= now(CLOCK_MONOTONIC
);
2197 union inotify_event_buffer buffer
;
2198 struct inotify_event
*e
;
2201 l
= read(j
->inotify_fd
, &buffer
, sizeof(buffer
));
2203 if (errno
== EAGAIN
|| errno
== EINTR
)
2204 return got_something
? determine_change(j
) : SD_JOURNAL_NOP
;
2209 got_something
= true;
2211 FOREACH_INOTIFY_EVENT(e
, buffer
, l
)
2212 process_inotify_event(j
, e
);
2216 _public_
int sd_journal_wait(sd_journal
*j
, uint64_t timeout_usec
) {
2220 assert_return(j
, -EINVAL
);
2221 assert_return(!journal_pid_changed(j
), -ECHILD
);
2223 if (j
->inotify_fd
< 0) {
2225 /* This is the first invocation, hence create the
2227 r
= sd_journal_get_fd(j
);
2231 /* The journal might have changed since the context
2232 * object was created and we weren't watching before,
2233 * hence don't wait for anything, and return
2235 return determine_change(j
);
2238 r
= sd_journal_get_timeout(j
, &t
);
2242 if (t
!= (uint64_t) -1) {
2245 n
= now(CLOCK_MONOTONIC
);
2246 t
= t
> n
? t
- n
: 0;
2248 if (timeout_usec
== (uint64_t) -1 || timeout_usec
> t
)
2253 r
= fd_wait_for_event(j
->inotify_fd
, POLLIN
, timeout_usec
);
2254 } while (r
== -EINTR
);
2259 return sd_journal_process(j
);
2262 _public_
int sd_journal_get_cutoff_realtime_usec(sd_journal
*j
, uint64_t *from
, uint64_t *to
) {
2266 uint64_t fmin
= 0, tmax
= 0;
2269 assert_return(j
, -EINVAL
);
2270 assert_return(!journal_pid_changed(j
), -ECHILD
);
2271 assert_return(from
|| to
, -EINVAL
);
2272 assert_return(from
!= to
, -EINVAL
);
2274 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2277 r
= journal_file_get_cutoff_realtime_usec(f
, &fr
, &t
);
2290 fmin
= MIN(fr
, fmin
);
2291 tmax
= MAX(t
, tmax
);
2300 return first
? 0 : 1;
2303 _public_
int sd_journal_get_cutoff_monotonic_usec(sd_journal
*j
, sd_id128_t boot_id
, uint64_t *from
, uint64_t *to
) {
2309 assert_return(j
, -EINVAL
);
2310 assert_return(!journal_pid_changed(j
), -ECHILD
);
2311 assert_return(from
|| to
, -EINVAL
);
2312 assert_return(from
!= to
, -EINVAL
);
2314 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2317 r
= journal_file_get_cutoff_monotonic_usec(f
, boot_id
, &fr
, &t
);
2327 *from
= MIN(fr
, *from
);
2342 void journal_print_header(sd_journal
*j
) {
2345 bool newline
= false;
2349 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2355 journal_file_print_header(f
);
2359 _public_
int sd_journal_get_usage(sd_journal
*j
, uint64_t *bytes
) {
2364 assert_return(j
, -EINVAL
);
2365 assert_return(!journal_pid_changed(j
), -ECHILD
);
2366 assert_return(bytes
, -EINVAL
);
2368 ORDERED_HASHMAP_FOREACH(f
, j
->files
, i
) {
2371 if (fstat(f
->fd
, &st
) < 0)
2374 sum
+= (uint64_t) st
.st_blocks
* 512ULL;
2381 _public_
int sd_journal_query_unique(sd_journal
*j
, const char *field
) {
2384 assert_return(j
, -EINVAL
);
2385 assert_return(!journal_pid_changed(j
), -ECHILD
);
2386 assert_return(!isempty(field
), -EINVAL
);
2387 assert_return(field_is_valid(field
), -EINVAL
);
2393 free(j
->unique_field
);
2394 j
->unique_field
= f
;
2395 j
->unique_file
= NULL
;
2396 j
->unique_offset
= 0;
2397 j
->unique_file_lost
= false;
2402 _public_
int sd_journal_enumerate_unique(sd_journal
*j
, const void **data
, size_t *l
) {
2405 assert_return(j
, -EINVAL
);
2406 assert_return(!journal_pid_changed(j
), -ECHILD
);
2407 assert_return(data
, -EINVAL
);
2408 assert_return(l
, -EINVAL
);
2409 assert_return(j
->unique_field
, -EINVAL
);
2411 k
= strlen(j
->unique_field
);
2413 if (!j
->unique_file
) {
2414 if (j
->unique_file_lost
)
2417 j
->unique_file
= ordered_hashmap_first(j
->files
);
2418 if (!j
->unique_file
)
2421 j
->unique_offset
= 0;
2433 /* Proceed to next data object in the field's linked list */
2434 if (j
->unique_offset
== 0) {
2435 r
= journal_file_find_field_object(j
->unique_file
, j
->unique_field
, k
, &o
, NULL
);
2439 j
->unique_offset
= r
> 0 ? le64toh(o
->field
.head_data_offset
) : 0;
2441 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_DATA
, j
->unique_offset
, &o
);
2445 j
->unique_offset
= le64toh(o
->data
.next_field_offset
);
2448 /* We reached the end of the list? Then start again, with the next file */
2449 if (j
->unique_offset
== 0) {
2450 j
->unique_file
= ordered_hashmap_next(j
->files
, j
->unique_file
->path
);
2451 if (!j
->unique_file
)
2457 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2458 * instead, so that we can look at this data object at the same
2459 * time as one on another file */
2460 r
= journal_file_move_to_object(j
->unique_file
, OBJECT_UNUSED
, j
->unique_offset
, &o
);
2464 /* Let's do the type check by hand, since we used 0 context above. */
2465 if (o
->object
.type
!= OBJECT_DATA
) {
2466 log_debug("%s:offset " OFSfmt
": object has type %d, expected %d",
2467 j
->unique_file
->path
, j
->unique_offset
,
2468 o
->object
.type
, OBJECT_DATA
);
2472 r
= return_data(j
, j
->unique_file
, o
, &odata
, &ol
);
2476 /* Check if we have at least the field name and "=". */
2478 log_debug("%s:offset " OFSfmt
": object has size %zu, expected at least %zu",
2479 j
->unique_file
->path
, j
->unique_offset
,
2484 if (memcmp(odata
, j
->unique_field
, k
) || ((const char*) odata
)[k
] != '=') {
2485 log_debug("%s:offset " OFSfmt
": object does not start with \"%s=\"",
2486 j
->unique_file
->path
, j
->unique_offset
,
2491 /* OK, now let's see if we already returned this data
2492 * object by checking if it exists in the earlier
2493 * traversed files. */
2495 ORDERED_HASHMAP_FOREACH(of
, j
->files
, i
) {
2499 if (of
== j
->unique_file
)
2502 /* Skip this file it didn't have any fields
2504 if (JOURNAL_HEADER_CONTAINS(of
->header
, n_fields
) &&
2505 le64toh(of
->header
->n_fields
) <= 0)
2508 r
= journal_file_find_data_object_with_hash(of
, odata
, ol
, le64toh(o
->data
.hash
), &oo
, &op
);
2519 r
= return_data(j
, j
->unique_file
, o
, data
, l
);
2527 _public_
void sd_journal_restart_unique(sd_journal
*j
) {
2531 j
->unique_file
= NULL
;
2532 j
->unique_offset
= 0;
2533 j
->unique_file_lost
= false;
2536 _public_
int sd_journal_reliable_fd(sd_journal
*j
) {
2537 assert_return(j
, -EINVAL
);
2538 assert_return(!journal_pid_changed(j
), -ECHILD
);
2540 return !j
->on_network
;
2543 static char *lookup_field(const char *field
, void *userdata
) {
2544 sd_journal
*j
= userdata
;
2552 r
= sd_journal_get_data(j
, field
, &data
, &size
);
2554 size
> REPLACE_VAR_MAX
)
2555 return strdup(field
);
2557 d
= strlen(field
) + 1;
2559 return strndup((const char*) data
+ d
, size
- d
);
2562 _public_
int sd_journal_get_catalog(sd_journal
*j
, char **ret
) {
2566 _cleanup_free_
char *text
= NULL
, *cid
= NULL
;
2570 assert_return(j
, -EINVAL
);
2571 assert_return(!journal_pid_changed(j
), -ECHILD
);
2572 assert_return(ret
, -EINVAL
);
2574 r
= sd_journal_get_data(j
, "MESSAGE_ID", &data
, &size
);
2578 cid
= strndup((const char*) data
+ 11, size
- 11);
2582 r
= sd_id128_from_string(cid
, &id
);
2586 r
= catalog_get(CATALOG_DATABASE
, id
, &text
);
2590 t
= replace_var(text
, lookup_field
, j
);
2598 _public_
int sd_journal_get_catalog_for_message_id(sd_id128_t id
, char **ret
) {
2599 assert_return(ret
, -EINVAL
);
2601 return catalog_get(CATALOG_DATABASE
, id
, ret
);
2604 _public_
int sd_journal_set_data_threshold(sd_journal
*j
, size_t sz
) {
2605 assert_return(j
, -EINVAL
);
2606 assert_return(!journal_pid_changed(j
), -ECHILD
);
2608 j
->data_threshold
= sz
;
2612 _public_
int sd_journal_get_data_threshold(sd_journal
*j
, size_t *sz
) {
2613 assert_return(j
, -EINVAL
);
2614 assert_return(!journal_pid_changed(j
), -ECHILD
);
2615 assert_return(sz
, -EINVAL
);
2617 *sz
= j
->data_threshold
;