1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Marius Vollmer
7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "sd-journal.h"
28 #include "journal-file.h"
29 #include "journal-vacuum.h"
31 #include "parse-util.h"
35 /* This program tests skipping around in a multi-file journal.
38 static bool arg_keep
= false;
40 noreturn
static void log_assert_errno(const char *text
, int eno
, const char *file
, int line
, const char *func
) {
41 log_internal(LOG_CRIT
, 0, file
, line
, func
,
42 "'%s' failed at %s:%u (%s): %s.",
43 text
, file
, line
, func
, strerror(eno
));
47 #define assert_ret(expr) \
50 if (_unlikely_(_r_ < 0)) \
51 log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
54 static JournalFile
*test_open(const char *name
) {
56 assert_ret(journal_file_open(name
, O_RDWR
|O_CREAT
, 0644, true, false, NULL
, NULL
, NULL
, &f
));
60 static void test_close(JournalFile
*f
) {
61 journal_file_close (f
);
64 static void append_number(JournalFile
*f
, int n
, uint64_t *seqnum
) {
67 static dual_timestamp previous_ts
= {};
68 struct iovec iovec
[1];
70 dual_timestamp_get(&ts
);
72 if (ts
.monotonic
<= previous_ts
.monotonic
)
73 ts
.monotonic
= previous_ts
.monotonic
+ 1;
75 if (ts
.realtime
<= previous_ts
.realtime
)
76 ts
.realtime
= previous_ts
.realtime
+ 1;
80 assert_se(asprintf(&p
, "NUMBER=%d", n
) >= 0);
81 iovec
[0].iov_base
= p
;
82 iovec
[0].iov_len
= strlen(p
);
83 assert_ret(journal_file_append_entry(f
, &ts
, iovec
, 1, seqnum
, NULL
, NULL
));
87 static void test_check_number (sd_journal
*j
, int n
) {
89 _cleanup_free_
char *k
;
93 assert_ret(sd_journal_get_data(j
, "NUMBER", &d
, &l
));
94 assert_se(k
= strndup(d
, l
));
97 assert_se(safe_atoi(k
+ 7, &x
) >= 0);
101 static void test_check_numbers_down (sd_journal
*j
, int count
) {
104 for (i
= 1; i
<= count
; i
++) {
106 test_check_number(j
, i
);
107 assert_ret(r
= sd_journal_next(j
));
116 static void test_check_numbers_up (sd_journal
*j
, int count
) {
117 for (int i
= count
; i
>= 1; i
--) {
119 test_check_number(j
, i
);
120 assert_ret(r
= sd_journal_previous(j
));
129 static void setup_sequential(void) {
130 JournalFile
*one
, *two
;
131 one
= test_open("one.journal");
132 two
= test_open("two.journal");
133 append_number(one
, 1, NULL
);
134 append_number(one
, 2, NULL
);
135 append_number(two
, 3, NULL
);
136 append_number(two
, 4, NULL
);
141 static void setup_interleaved(void) {
142 JournalFile
*one
, *two
;
143 one
= test_open("one.journal");
144 two
= test_open("two.journal");
145 append_number(one
, 1, NULL
);
146 append_number(two
, 2, NULL
);
147 append_number(one
, 3, NULL
);
148 append_number(two
, 4, NULL
);
153 static void test_skip(void (*setup
)(void)) {
154 char t
[] = "/tmp/journal-skip-XXXXXX";
158 assert_se(mkdtemp(t
));
159 assert_se(chdir(t
) >= 0);
163 /* Seek to head, iterate down.
165 assert_ret(sd_journal_open_directory(&j
, t
, 0));
166 assert_ret(sd_journal_seek_head(j
));
167 assert_ret(sd_journal_next(j
));
168 test_check_numbers_down(j
, 4);
171 /* Seek to tail, iterate up.
173 assert_ret(sd_journal_open_directory(&j
, t
, 0));
174 assert_ret(sd_journal_seek_tail(j
));
175 assert_ret(sd_journal_previous(j
));
176 test_check_numbers_up(j
, 4);
179 /* Seek to tail, skip to head, iterate down.
181 assert_ret(sd_journal_open_directory(&j
, t
, 0));
182 assert_ret(sd_journal_seek_tail(j
));
183 assert_ret(r
= sd_journal_previous_skip(j
, 4));
185 test_check_numbers_down(j
, 4);
188 /* Seek to head, skip to tail, iterate up.
190 assert_ret(sd_journal_open_directory(&j
, t
, 0));
191 assert_ret(sd_journal_seek_head(j
));
192 assert_ret(r
= sd_journal_next_skip(j
, 4));
194 test_check_numbers_up(j
, 4);
200 log_info("Not removing %s", t
);
202 journal_directory_vacuum(".", 3000000, 0, 0, NULL
, true);
204 assert_se(rm_rf(t
, REMOVE_ROOT
|REMOVE_PHYSICAL
) >= 0);
207 puts("------------------------------------------------------------");
210 static void test_sequence_numbers(void) {
212 char t
[] = "/tmp/journal-seq-XXXXXX";
213 JournalFile
*one
, *two
;
215 sd_id128_t seqnum_id
;
217 assert_se(mkdtemp(t
));
218 assert_se(chdir(t
) >= 0);
220 assert_se(journal_file_open("one.journal", O_RDWR
|O_CREAT
, 0644,
221 true, false, NULL
, NULL
, NULL
, &one
) == 0);
223 append_number(one
, 1, &seqnum
);
224 printf("seqnum=%"PRIu64
"\n", seqnum
);
225 assert_se(seqnum
== 1);
226 append_number(one
, 2, &seqnum
);
227 printf("seqnum=%"PRIu64
"\n", seqnum
);
228 assert_se(seqnum
== 2);
230 assert_se(one
->header
->state
== STATE_ONLINE
);
231 assert_se(!sd_id128_equal(one
->header
->file_id
, one
->header
->machine_id
));
232 assert_se(!sd_id128_equal(one
->header
->file_id
, one
->header
->boot_id
));
233 assert_se(sd_id128_equal(one
->header
->file_id
, one
->header
->seqnum_id
));
235 memcpy(&seqnum_id
, &one
->header
->seqnum_id
, sizeof(sd_id128_t
));
237 assert_se(journal_file_open("two.journal", O_RDWR
|O_CREAT
, 0644,
238 true, false, NULL
, NULL
, one
, &two
) == 0);
240 assert_se(two
->header
->state
== STATE_ONLINE
);
241 assert_se(!sd_id128_equal(two
->header
->file_id
, one
->header
->file_id
));
242 assert_se(sd_id128_equal(one
->header
->machine_id
, one
->header
->machine_id
));
243 assert_se(sd_id128_equal(one
->header
->boot_id
, one
->header
->boot_id
));
244 assert_se(sd_id128_equal(one
->header
->seqnum_id
, one
->header
->seqnum_id
));
246 append_number(two
, 3, &seqnum
);
247 printf("seqnum=%"PRIu64
"\n", seqnum
);
248 assert_se(seqnum
== 3);
249 append_number(two
, 4, &seqnum
);
250 printf("seqnum=%"PRIu64
"\n", seqnum
);
251 assert_se(seqnum
== 4);
255 append_number(one
, 5, &seqnum
);
256 printf("seqnum=%"PRIu64
"\n", seqnum
);
257 assert_se(seqnum
== 5);
259 append_number(one
, 6, &seqnum
);
260 printf("seqnum=%"PRIu64
"\n", seqnum
);
261 assert_se(seqnum
== 6);
268 assert_se(journal_file_open("two.journal", O_RDWR
, 0,
269 true, false, NULL
, NULL
, NULL
, &two
) == 0);
271 assert_se(sd_id128_equal(two
->header
->seqnum_id
, seqnum_id
));
273 append_number(two
, 7, &seqnum
);
274 printf("seqnum=%"PRIu64
"\n", seqnum
);
275 assert_se(seqnum
== 5);
277 /* So..., here we have the same seqnum in two files with the
285 log_info("Not removing %s", t
);
287 journal_directory_vacuum(".", 3000000, 0, 0, NULL
, true);
289 assert_se(rm_rf(t
, REMOVE_ROOT
|REMOVE_PHYSICAL
) >= 0);
293 int main(int argc
, char *argv
[]) {
294 log_set_max_level(LOG_DEBUG
);
296 /* journal_file_open requires a valid machine id */
297 if (access("/etc/machine-id", F_OK
) != 0)
298 return EXIT_TEST_SKIP
;
302 test_skip(setup_sequential
);
303 test_skip(setup_interleaved
);
305 test_sequence_numbers();