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"
27 #include "journal-file.h"
28 #include "journal-vacuum.h"
33 /* This program tests skipping around in a multi-file journal.
36 static bool arg_keep
= false;
38 noreturn
static void log_assert_errno(const char *text
, int eno
, const char *file
, int line
, const char *func
) {
39 log_internal(LOG_CRIT
, 0, file
, line
, func
,
40 "'%s' failed at %s:%u (%s): %s.",
41 text
, file
, line
, func
, strerror(eno
));
45 #define assert_ret(expr) \
48 if (_unlikely_(_r_ < 0)) \
49 log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
52 static JournalFile
*test_open(const char *name
) {
54 assert_ret(journal_file_open(name
, O_RDWR
|O_CREAT
, 0644, true, false, NULL
, NULL
, NULL
, &f
));
58 static void test_close(JournalFile
*f
) {
59 journal_file_close (f
);
62 static void append_number(JournalFile
*f
, int n
, uint64_t *seqnum
) {
65 static dual_timestamp previous_ts
= {};
66 struct iovec iovec
[1];
68 dual_timestamp_get(&ts
);
70 if (ts
.monotonic
<= previous_ts
.monotonic
)
71 ts
.monotonic
= previous_ts
.monotonic
+ 1;
73 if (ts
.realtime
<= previous_ts
.realtime
)
74 ts
.realtime
= previous_ts
.realtime
+ 1;
78 assert_se(asprintf(&p
, "NUMBER=%d", n
) >= 0);
79 iovec
[0].iov_base
= p
;
80 iovec
[0].iov_len
= strlen(p
);
81 assert_ret(journal_file_append_entry(f
, &ts
, iovec
, 1, seqnum
, NULL
, NULL
));
85 static void test_check_number (sd_journal
*j
, int n
) {
87 _cleanup_free_
char *k
;
91 assert_ret(sd_journal_get_data(j
, "NUMBER", &d
, &l
));
92 assert_se(k
= strndup(d
, l
));
95 assert_se(safe_atoi(k
+ 7, &x
) >= 0);
99 static void test_check_numbers_down (sd_journal
*j
, int count
) {
102 for (i
= 1; i
<= count
; i
++) {
104 test_check_number(j
, i
);
105 assert_ret(r
= sd_journal_next(j
));
114 static void test_check_numbers_up (sd_journal
*j
, int count
) {
115 for (int i
= count
; i
>= 1; i
--) {
117 test_check_number(j
, i
);
118 assert_ret(r
= sd_journal_previous(j
));
127 static void setup_sequential(void) {
128 JournalFile
*one
, *two
;
129 one
= test_open("one.journal");
130 two
= test_open("two.journal");
131 append_number(one
, 1, NULL
);
132 append_number(one
, 2, NULL
);
133 append_number(two
, 3, NULL
);
134 append_number(two
, 4, NULL
);
139 static void setup_interleaved(void) {
140 JournalFile
*one
, *two
;
141 one
= test_open("one.journal");
142 two
= test_open("two.journal");
143 append_number(one
, 1, NULL
);
144 append_number(two
, 2, NULL
);
145 append_number(one
, 3, NULL
);
146 append_number(two
, 4, NULL
);
151 static void test_skip(void (*setup
)(void)) {
152 char t
[] = "/tmp/journal-skip-XXXXXX";
156 assert_se(mkdtemp(t
));
157 assert_se(chdir(t
) >= 0);
161 /* Seek to head, iterate down.
163 assert_ret(sd_journal_open_directory(&j
, t
, 0));
164 assert_ret(sd_journal_seek_head(j
));
165 assert_ret(sd_journal_next(j
));
166 test_check_numbers_down(j
, 4);
169 /* Seek to tail, iterate up.
171 assert_ret(sd_journal_open_directory(&j
, t
, 0));
172 assert_ret(sd_journal_seek_tail(j
));
173 assert_ret(sd_journal_previous(j
));
174 test_check_numbers_up(j
, 4);
177 /* Seek to tail, skip to head, iterate down.
179 assert_ret(sd_journal_open_directory(&j
, t
, 0));
180 assert_ret(sd_journal_seek_tail(j
));
181 assert_ret(r
= sd_journal_previous_skip(j
, 4));
183 test_check_numbers_down(j
, 4);
186 /* Seek to head, skip to tail, iterate up.
188 assert_ret(sd_journal_open_directory(&j
, t
, 0));
189 assert_ret(sd_journal_seek_head(j
));
190 assert_ret(r
= sd_journal_next_skip(j
, 4));
192 test_check_numbers_up(j
, 4);
198 log_info("Not removing %s", t
);
200 journal_directory_vacuum(".", 3000000, 0, NULL
, true);
202 assert_se(rm_rf(t
, REMOVE_ROOT
|REMOVE_PHYSICAL
) >= 0);
205 puts("------------------------------------------------------------");
208 static void test_sequence_numbers(void) {
210 char t
[] = "/tmp/journal-seq-XXXXXX";
211 JournalFile
*one
, *two
;
213 sd_id128_t seqnum_id
;
215 assert_se(mkdtemp(t
));
216 assert_se(chdir(t
) >= 0);
218 assert_se(journal_file_open("one.journal", O_RDWR
|O_CREAT
, 0644,
219 true, false, NULL
, NULL
, NULL
, &one
) == 0);
221 append_number(one
, 1, &seqnum
);
222 printf("seqnum=%"PRIu64
"\n", seqnum
);
223 assert_se(seqnum
== 1);
224 append_number(one
, 2, &seqnum
);
225 printf("seqnum=%"PRIu64
"\n", seqnum
);
226 assert_se(seqnum
== 2);
228 assert_se(one
->header
->state
== STATE_ONLINE
);
229 assert_se(!sd_id128_equal(one
->header
->file_id
, one
->header
->machine_id
));
230 assert_se(!sd_id128_equal(one
->header
->file_id
, one
->header
->boot_id
));
231 assert_se(sd_id128_equal(one
->header
->file_id
, one
->header
->seqnum_id
));
233 memcpy(&seqnum_id
, &one
->header
->seqnum_id
, sizeof(sd_id128_t
));
235 assert_se(journal_file_open("two.journal", O_RDWR
|O_CREAT
, 0644,
236 true, false, NULL
, NULL
, one
, &two
) == 0);
238 assert_se(two
->header
->state
== STATE_ONLINE
);
239 assert_se(!sd_id128_equal(two
->header
->file_id
, one
->header
->file_id
));
240 assert_se(sd_id128_equal(one
->header
->machine_id
, one
->header
->machine_id
));
241 assert_se(sd_id128_equal(one
->header
->boot_id
, one
->header
->boot_id
));
242 assert_se(sd_id128_equal(one
->header
->seqnum_id
, one
->header
->seqnum_id
));
244 append_number(two
, 3, &seqnum
);
245 printf("seqnum=%"PRIu64
"\n", seqnum
);
246 assert_se(seqnum
== 3);
247 append_number(two
, 4, &seqnum
);
248 printf("seqnum=%"PRIu64
"\n", seqnum
);
249 assert_se(seqnum
== 4);
253 append_number(one
, 5, &seqnum
);
254 printf("seqnum=%"PRIu64
"\n", seqnum
);
255 assert_se(seqnum
== 5);
257 append_number(one
, 6, &seqnum
);
258 printf("seqnum=%"PRIu64
"\n", seqnum
);
259 assert_se(seqnum
== 6);
266 assert_se(journal_file_open("two.journal", O_RDWR
, 0,
267 true, false, NULL
, NULL
, NULL
, &two
) == 0);
269 assert_se(sd_id128_equal(two
->header
->seqnum_id
, seqnum_id
));
271 append_number(two
, 7, &seqnum
);
272 printf("seqnum=%"PRIu64
"\n", seqnum
);
273 assert_se(seqnum
== 5);
275 /* So..., here we have the same seqnum in two files with the
283 log_info("Not removing %s", t
);
285 journal_directory_vacuum(".", 3000000, 0, NULL
, true);
287 assert_se(rm_rf(t
, REMOVE_ROOT
|REMOVE_PHYSICAL
) >= 0);
291 int main(int argc
, char *argv
[]) {
292 log_set_max_level(LOG_DEBUG
);
294 /* journal_file_open requires a valid machine id */
295 if (access("/etc/machine-id", F_OK
) != 0)
296 return EXIT_TEST_SKIP
;
300 test_skip(setup_sequential
);
301 test_skip(setup_interleaved
);
303 test_sequence_numbers();