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 <systemd/sd-journal.h>
28 #include "journal-file.h"
29 #include "journal-internal.h"
30 #include "journal-vacuum.h"
34 /* This program tests skipping around in a multi-file journal.
37 static bool arg_keep = false;
39 _noreturn_ static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) {
40 log_meta(LOG_CRIT, file, line, func,
41 "'%s' failed at %s:%u (%s): %s.",
42 text, file, line, func, strerror(eno));
46 #define assert_ret(expr) \
49 if (_unlikely_(_r_ < 0)) \
50 log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
53 static JournalFile *test_open(const char *name) {
55 assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
59 static void test_close(JournalFile *f) {
60 journal_file_close (f);
63 static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
66 struct iovec iovec[1];
68 dual_timestamp_get(&ts);
70 assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
71 iovec[0].iov_base = p;
72 iovec[0].iov_len = strlen(p);
73 assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
77 static void test_check_number (sd_journal *j, int n) {
79 _cleanup_free_ char *k;
83 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
84 assert_se(k = strndup(d, l));
87 assert_se(safe_atoi(k + 7, &x) >= 0);
91 static void test_check_numbers_down (sd_journal *j, int count) {
94 for (i = 1; i <= count; i++) {
96 test_check_number(j, i);
97 assert_ret(r = sd_journal_next(j));
106 static void test_check_numbers_up (sd_journal *j, int count) {
107 for (int i = count; i >= 1; i--) {
109 test_check_number(j, i);
110 assert_ret(r = sd_journal_previous(j));
119 static void setup_sequential(void) {
120 JournalFile *one, *two;
121 one = test_open("one.journal");
122 two = test_open("two.journal");
123 append_number(one, 1, NULL);
124 append_number(one, 2, NULL);
125 append_number(two, 3, NULL);
126 append_number(two, 4, NULL);
131 static void setup_interleaved(void) {
132 JournalFile *one, *two;
133 one = test_open("one.journal");
134 two = test_open("two.journal");
135 append_number(one, 1, NULL);
136 append_number(two, 2, NULL);
137 append_number(one, 3, NULL);
138 append_number(two, 4, NULL);
143 static void test_skip(void (*setup)(void)) {
144 char t[] = "/tmp/journal-skip-XXXXXX";
148 assert_se(mkdtemp(t));
149 assert_se(chdir(t) >= 0);
153 /* Seek to head, iterate down.
155 assert_ret(sd_journal_open_directory(&j, t, 0));
156 assert_ret(sd_journal_seek_head(j));
157 assert_ret(sd_journal_next(j));
158 test_check_numbers_down(j, 4);
161 /* Seek to tail, iterate up.
163 assert_ret(sd_journal_open_directory(&j, t, 0));
164 assert_ret(sd_journal_seek_tail(j));
165 assert_ret(sd_journal_previous(j));
166 test_check_numbers_up(j, 4);
169 /* Seek to tail, skip to head, iterate down.
171 assert_ret(sd_journal_open_directory(&j, t, 0));
172 assert_ret(sd_journal_seek_tail(j));
173 assert_ret(r = sd_journal_previous_skip(j, 4));
175 test_check_numbers_down(j, 4);
178 /* Seek to head, skip to tail, iterate up.
180 assert_ret(sd_journal_open_directory(&j, t, 0));
181 assert_ret(sd_journal_seek_head(j));
182 assert_ret(r = sd_journal_next_skip(j, 4));
184 test_check_numbers_up(j, 4);
190 log_info("Not removing %s", t);
192 journal_directory_vacuum(".", 3000000, 0, 0, NULL);
194 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
197 puts("------------------------------------------------------------");
200 static void test_sequence_numbers(void) {
202 char t[] = "/tmp/journal-seq-XXXXXX";
203 JournalFile *one, *two;
205 sd_id128_t seqnum_id;
207 assert_se(mkdtemp(t));
208 assert_se(chdir(t) >= 0);
210 assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
211 true, false, NULL, NULL, NULL, &one) == 0);
213 append_number(one, 1, &seqnum);
214 printf("seqnum=%"PRIu64"\n", seqnum);
216 append_number(one, 2, &seqnum);
217 printf("seqnum=%"PRIu64"\n", seqnum);
220 assert(one->header->state == STATE_ONLINE);
221 assert(!sd_id128_equal(one->header->file_id, one->header->machine_id));
222 assert(!sd_id128_equal(one->header->file_id, one->header->boot_id));
223 assert(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
225 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
227 assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
228 true, false, NULL, NULL, one, &two) == 0);
230 assert(two->header->state == STATE_ONLINE);
231 assert(!sd_id128_equal(two->header->file_id, one->header->file_id));
232 assert(sd_id128_equal(one->header->machine_id, one->header->machine_id));
233 assert(sd_id128_equal(one->header->boot_id, one->header->boot_id));
234 assert(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
236 append_number(two, 3, &seqnum);
237 printf("seqnum=%"PRIu64"\n", seqnum);
239 append_number(two, 4, &seqnum);
240 printf("seqnum=%"PRIu64"\n", seqnum);
245 append_number(one, 5, &seqnum);
246 printf("seqnum=%"PRIu64"\n", seqnum);
249 append_number(one, 6, &seqnum);
250 printf("seqnum=%"PRIu64"\n", seqnum);
258 assert_se(journal_file_open("two.journal", O_RDWR, 0,
259 true, false, NULL, NULL, NULL, &two) == 0);
261 assert(sd_id128_equal(two->header->seqnum_id, seqnum_id));
263 append_number(two, 7, &seqnum);
264 printf("seqnum=%"PRIu64"\n", seqnum);
267 /* So..., here we have the same seqnum in two files with the
275 log_info("Not removing %s", t);
277 journal_directory_vacuum(".", 3000000, 0, 0, NULL);
279 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
283 int main(int argc, char *argv[]) {
284 log_set_max_level(LOG_DEBUG);
286 /* journal_file_open requires a valid machine id */
287 if (access("/etc/machine-id", F_OK) != 0)
288 return EXIT_TEST_SKIP;
292 test_skip(setup_sequential);
293 test_skip(setup_interleaved);
295 test_sequence_numbers();