Commit Graph
38 Commits
Author SHA1 Message Date
Chris Down 422abe6be6 test-journal: Cover reader position invalidation 2026-09-22 15:00:55 +08:00
Michael Renner 101b8633c2 journal: recover iteration over vacuumed files (#43649)
Vacuuming unlinks and deallocates archived journal files. A reader
may have already selected an entry from such a file, so final
validation can fail after candidate selection succeeded.

If the selected file is now unlinked, remove it and retry candidate
selection. Preserve errors from linked files, including the EIO
reported after SIGBUS recovery from a truncated mapping.
2026-09-05 11:17:59 +09:00
Frantisek Sumsal ae940730c6 sd-journal: prefer machine ID from the tail entry
compare_boot_ids() (from 262299dccb) skips
the tail entry realtime timestamp ordering when the compared locations
are from two different machines (and hence have two different machine
IDs) - in that case we fall through to a realtime comparison between the
two locations. This works fine except for journals that were imported
via systemd-journal-remote - the machine ID in the journal header is set
to the receiving machine's ID instead of the original one; but the
original machine ID is kept in the _MACHINE_ID= field.

This, however, defeats the check in compare_boot_ids() so we treat the
remote journals as local ones and try to compare the boots based on
their tail entry realtime timestamps, which results in grouping the
entries by their boot ID instead of interleaving them by their realtime
timestamp.

Given that we (transitively) call journal_file_read_tail_timestamp()
from compare_boot_ids(), where we both (re)set the newest_machine_id
field to the machine ID from the journal header and have the tail entry
at hand, let's try to get the _MACHINE_ID= field from the tail entry and
set newest_machine_id to that if it's present and valid. This way
compare_boot_ids() will correctly determine that the entries are from
two different machines and compare_locations() eventually falls through
to the entry realtime check, so we end up with properly interleaved
entries instead of entries grouped by boot ID.

The performance impact should be pretty negligible in vast majority of
cases, as we'd do this only when:
  - opening a new file
  - comparing entries across different boots
  - advancing to a next location

The first case is a one-time thing only per journal. The second and
third case might call this a bit more frequently, but we fall through to
the _MACHINE_ID= parsing only if the journal file got a new entry since
the last check. The most significant impact would be on journals that
are being actively written into, but even then iterating through the
handful of typical fields is negligible compared to what the rest of the
function does. Also, since 8f8ab4bf98 the
journal_file_read_tail_timestamp() calls are ratelimited when walking
through the journal, lessening the impact even further.

Resolves: #34169
2026-08-08 04:05:25 +09:00
Frantisek Sumsal 8e762e6b9f test: verify cursor-seeking in the opposite direction as well 2026-08-05 21:06:43 +02:00
Frantisek Sumsal 868d07d1d4 sd-journal: prefer exact cursor match after seek
Since 262299dccb compare_locations() falls
through to a realtime-based comparison in compare_boot_ids() if the
compared entries have different boot IDs (and seqnum IDs). This can,
however, cause us to pick up the wrong entry/file on systems with
unreliable/missing RTC, where early-boot entries of a boot might have
earlier realtime timestamp compared to the previous boot.

For example, here's a minimal reproducer consisting of two journal files
containing three entries from two separate boot IDs:

$ journalctl --file one.journal -o export
__CURSOR=s=ba37c62fcacf406aad088166c4963cd1;i=1;b=c220efc91dd440deb89d82c98ddb11a5;m=186a0;t=1e8480;x=39d4323a8e5a248d
__REALTIME_TIMESTAMP=2000000
__MONOTONIC_TIMESTAMP=100000
__SEQNUM=1
__SEQNUM_ID=ba37c62fcacf406aad088166c4963cd1
_BOOT_ID=c220efc91dd440deb89d82c98ddb11a5
NUMBER=1

$ journalctl --file two.journal -o export
__CURSOR=s=9d15197efcc54d8ca5d6e7cce28373e2;i=1;b=686dc35e78f64b6ba126018ab6e8bae9;m=186a0;t=f4240;x=57db1c7bd38b37ed
__REALTIME_TIMESTAMP=1000000
__MONOTONIC_TIMESTAMP=100000
__SEQNUM=1
__SEQNUM_ID=9d15197efcc54d8ca5d6e7cce28373e2
_BOOT_ID=686dc35e78f64b6ba126018ab6e8bae9
NUMBER=2

__CURSOR=s=9d15197efcc54d8ca5d6e7cce28373e2;i=2;b=686dc35e78f64b6ba126018ab6e8bae9;m=30d40;t=2dc6c0;x=3513732159948113
__REALTIME_TIMESTAMP=3000000
__MONOTONIC_TIMESTAMP=200000
__SEQNUM=2
__SEQNUM_ID=9d15197efcc54d8ca5d6e7cce28373e2
_BOOT_ID=686dc35e78f64b6ba126018ab6e8bae9
NUMBER=3

The first file (one.journal) contains a single entry from the first boot
(c220efc91dd440deb89d82c98ddb11a5) and a realtime timestamp of 2s. The
second file (two.journal) contains two entries from the second boot
(686dc35e78f64b6ba126018ab6e8bae9) - the first entry has a realtime
timestamp of 1s (i.e. _earlier_ than the tail timestamp of the first
boot), and the second entry has a realtime timestamp of 3s (i.e.  after
a time correction).

This works fine for forward iteration, but seeking directly to the
second entry is when things go south:

First entry:
$ python3 <<EOF
c = "s=ba37c62fcacf406aad088166c4963cd1;i=1;b=c220efc91dd440deb89d82c98ddb11a5;m=186a0;t=1e8480;x=39d4323a8e5a248d"
from systemd import journal; j = journal.Reader(path="."); j.seek_cursor(c); j.get_next(); print(j.test_cursor(c))
EOF
True

Second entry:
$ python3 <<EOF
c = "s=9d15197efcc54d8ca5d6e7cce28373e2;i=1;b=686dc35e78f64b6ba126018ab6e8bae9;m=186a0;t=f4240;x=57db1c7bd38b37ed"
from systemd import journal; j = journal.Reader(path="."); j.seek_cursor(c); j.get_next(); print(j.test_cursor(c))
EOF
False

That's because:
  - we call sd_journal_seek_cursor(...) and parse it (seqnum, seqnum_id,
    boot_id, realtime, ...)
  - we call sd_journal_next() -> real_journal_next() which iterates over
    all open journal files to find all candidate entries and pick the
    best one
  - for each journal file we call next_beyond_location()
  - for next_beyond_location(one.journal) we get:
    - last_direction is _DIRECTION_INVALID, so we call find_location_with_matches()
    - we fall all the way through to journal_file_move_to_entry_by_realtime()
    - here we try to find the first entry with realtime >= 1s; this file
      has only one entry with realtime = 2s which matches
  - we got a match and new_file is unset, so we set it to one.journal
  - for next_beyond_location(two.journal) we get:
    - we fall through to find_location_with_matches()
    - here we have a matching seqnum, so we call journal_file_move_to_entry_by_seqnum()
  - we got another match but new_file is set, so we call compare_locations(two.journal, one.journal):
    - we fall through to compare_boot_ids()
    - we get the tail timestamps of both journal files and return
      CMP(second boot, first boot) -> CMP(3s, 2s) = 1
  - this bubbles up back to real_journal_next() where found = false, so
    new_file remains one.journal (the wrong journal file)
  - this is followed by set_location(one.journal), which makes the
    following sd_journal_test_cursor() call fail, as the
    boot_id/seqnum_id/... of the current position don't match with the
    cursor

To fix this, let's track the journal file that holds the exact cursor
match, and override the chosen candidate if needed once we process all
open journals.

Resolves: #31516
2026-08-05 21:06:43 +02:00
Yu Watanabe c33a9eb858 sd-journal: update comments 2026-05-15 15:04:02 +09:00
Michael Vogt bd141bd818 many: fix remaining check-pointer-deref issues
The updated parsing_hacks.h file uncovered a bunch of extra
things that the check-pointer-deref coccinelle script flags.

This commit fixes them to make the tree check-pointer-deref clean.
2026-04-12 15:27:15 +02:00
Michael Vogt b50d7345a2 libsystemd: make check-pointer-deref clean
Add the needed assert changes to make the code clean
for the new check-pointer-deref script.
2026-03-31 18:30:40 +02:00
Yu Watanabe 93378148d4 tree-wide: normalize comment style 2025-12-15 08:50:13 +09:00
Daan De Meyer 5cdf13c70c libsystemd: Clean up includes
For libsystemd's headers, the changes made depend on whether the
header is installed or not. For installed headers, the only change
made is that commonly included headers were moved to _sd-common.h.
For these headers, there should be no noticeable change in behavior
when including them. For non-installed headers, includes were replaced
with forward declarations where possible as usual.

Split out of #37344.
2025-05-25 03:40:24 +09:00
Daan De Meyer 69a283c5f2 shared: Clean up includes
Split out of #37344.
2025-05-24 14:00:44 +02:00
Daan De Meyer 1e35e81b2c tree-wide: Clean up includes
Preparation for cleaning up includes in src/shared.
2025-05-22 21:10:15 +02:00
Daan De Meyer 1cf40697e3 tree-wide: Sort includes
This was done by running a locally built clang-format with
https://github.com/llvm/llvm-project/pull/137617 and
https://github.com/llvm/llvm-project/pull/137840 applied on all .c
and .h files.
2025-04-30 09:30:51 +02:00
Yu Watanabe d9000d708c test: drop redundant parentheses in ASSERT_OK() and friends
This reverts 278e3adf50, and drop more
redundant parentheses, as they unfortunately does not suppress the
false-positive warnings by coverity.
2025-03-15 09:08:06 +09:00
Yu Watanabe 278e3adf50 test: wrap assignments in ASSERT_OK() and friends with parentheses
Hopefully fixes many CID reports.
2025-03-13 05:15:28 +09:00
Yu Watanabe a997f3387f chattr-util: drop mostly unused 'previous' argument from chattr_path() and friends 2025-03-04 00:47:12 +09:00
Nick Rosbrook 5dc89b327f tree-wide: remove some spurious newlines
Specifically, remove double newlines, and newlines before '}'.
2025-01-29 16:17:46 +00:00
Yu Watanabe ab61b8865b test: use ASSERT_EQ_ID128() and ASSERT_NE_ID128() 2024-08-23 10:18:08 +09:00
Yu Watanabe 12dcb12df3 test: add test cases for sd_journal_seek_realtime_usec() and sd_journal_seek_monotonic_usec() 2024-08-15 04:43:32 +09:00
Yu Watanabe a2e4b8d866 test: modernize test-journal-interleaving 2024-08-15 04:43:32 +09:00
Yu Watanabe 6ecee6cf2b logs-show: rename BootId -> LogId
The struct itself is generic, and can be used for other ID.
Let's rename it to more generic one.
No functional change, just refactoring and preparation for later
commits.
2024-08-01 07:31:44 +09:00
Yu Watanabe d0936a7266 journalctl: make --list-boots support -n/--lines= option
Also mention that -r/--reverse is supported by the command.
2024-05-10 11:43:57 +09:00
Yu Watanabe a467515519 journalctl: fix support of --boot=ID±offset format
Fixes a regression introduced by e44f06065b.

After the offending commit, if a boot ID suffixed with an offset is
specified to --boot=, the boot ID was ignored.
This fixes the issue.

To fix the issue, this merges journal_find_boot_by_id() and
journal_find_boot_by_offset().
2024-05-10 11:43:57 +09:00
Yu Watanabe f0297ea097 test: add test case for sd_journal_{get,seek,test}_cursor()
For issue #31516.
2024-04-20 13:26:57 +02:00
Yu Watanabe 36c6b26c37 sd-journal: use -EBADF for journal_file_open() 2024-02-15 09:50:18 +09:00
Lennart Poettering c9cdbaed17 Merge pull request #30380 from keszybz/tmpfiles-dry-run
Make tmpfiles/sysusers nicer with local files and implement tmpfiles --dry-run
2024-02-13 09:45:50 +01:00
Yu WatanabeandCosta Tsaousis f7f062bf9f tree-wide: set SD_JOURNAL_ASSUME_IMMUTABLE where appropriate
Co-authored-by: Costa Tsaousis <costa@netdata.cloud>
2024-02-12 02:42:36 +09:00
Zbigniew Jędrzejewski-Szmek f7862b2a00 tree-wide: use normal spelling of "reopen"
It's a commonly used verb meaning "to open again".
2024-02-09 17:57:41 +01:00
Yu Watanabe 07ae001f81 test: add tests for journal_file_next_entry() 2024-02-10 00:30:04 +09:00
Yu Watanabe f3714bd5a2 test: add tests for generic_array_bisect() 2023-12-01 10:08:49 +09:00
Yu Watanabe 1f21bc5811 test: make append_number() optionally return offset of the entry object
Preparation for later commits.
2023-12-01 10:08:49 +09:00
Yu Watanabe 76b7a346ed test: split out finalization task 2023-12-01 10:08:46 +09:00
Zbigniew Jędrzejewski-Szmek fa5a025167 Rename {dual,triple}_timestamp_get to {dual,triple}_timestamp_now
Those functions take a pointer to a timestamp and return a timestamp pointer,
so the reader would be justified to think that those are just getters. Rename
them to avoid confusion.
2023-11-13 13:27:07 +01:00
Lennart Poettering bd1ae17833 io-util: split out "struct iovec" related calls into their own .c/.h files
This is preparation for #28891, which adds a bunch more helpers around
"struct iovec", at which point this really deserves its own .c/.h file.

The idea is that we sooner or later can consider "struct iovec" as an
entirely generic mechanism to reference some binary blob, and is the
go-to type for this purpose whenever we need one.
2023-10-20 10:34:33 +02:00
Yu Watanabe 1d3ef11dfe journal: move several tests to libsystemd/sd-journal
This also renames test-journal-xyz for journald (rather than sd-journal)
to test-journald-xyz.
2023-10-02 10:52:45 +09:00
Daan De Meyer 035b0f8fe8 journal: Introduce journald-file.c for journal file write related logic
Currently, all the logic related to writing journal files lives in
journal-file.c which is part of libsystemd (sd-journal). Because it's
part of libsystemd, we can't depend on any code from src/shared.

To allow using code from src/shared when writing journal files, let's
gradually move the write related logic from journal-file.c to
journald-file.c in src/journal. This directory is not part of libsystemd
and as such can use code from src/shared.

We can safely remove any journal write related logic from libsystemd as
it's not used by any public APIs in libsystemd.

This commit introduces the new file along with the JournaldFile struct
which wraps an instance of JournalFile. The goal is to gradually move
more functions from journal-file.c and fields from JournalFile to
journald-file.c and JournaldFile respectively.

This commit also modifies all call sites that write journal files to
use JournaldFile instead of JournalFile. All sd-journal tests that
write journal files are moved to src/journal so they can make use of
journald-file.c.

Because the deferred closes logic is only used by journald, we move it
out of journal-file.c as well. In journal_file_open(), we would wait for
any remaining deferred closes for the file we're about to open to complete
before continuing if the file was not newly created. In journald_file_open(),
we call this logic unconditionally since it stands that if a file is newly
created, it can't have any outstanding deferred closes.

No changes in behavior are introduced aside from the earlier execution
of waiting for any deferred closes to complete when opening a new journal
file.
2021-12-06 22:17:38 +01:00
Yu Watanabe f5fbe71d95 tree-wide: use UINT64_MAX or friends 2021-03-05 07:10:13 +09:00
Yu Watanabe 99b9f8fddd sd-journal: move source files for sd-journal to src/libsystemd/sd-journal 2021-01-19 07:04:18 +09:00