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 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)
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)
62 journal_file_close (f);
65 static void append_number(JournalFile *f, int n, uint64_t *seqnum)
69 struct iovec iovec[1];
71 dual_timestamp_get(&ts);
73 assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
74 iovec[0].iov_base = p;
75 iovec[0].iov_len = strlen(p);
76 assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
80 static void test_check_number (sd_journal *j, int n)
87 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
88 assert_se(k = strndup(d, l));
91 assert_se(safe_atoi(k + 7, &x) >= 0);
95 static void test_check_numbers_down (sd_journal *j, int count)
97 for (int i = 1; i <= count; i++) {
99 test_check_number(j, i);
100 assert_ret(r = sd_journal_next(j));
109 static void test_check_numbers_up (sd_journal *j, int count)
111 for (int i = count; i >= 1; i--) {
113 test_check_number(j, i);
114 assert_ret(r = sd_journal_previous(j));
123 static void setup_sequential(void) {
124 JournalFile *one, *two;
125 one = test_open("one.journal");
126 two = test_open("two.journal");
127 append_number(one, 1, NULL);
128 append_number(one, 2, NULL);
129 append_number(two, 3, NULL);
130 append_number(two, 4, NULL);
135 static void setup_interleaved(void) {
136 JournalFile *one, *two;
137 one = test_open("one.journal");
138 two = test_open("two.journal");
139 append_number(one, 1, NULL);
140 append_number(two, 2, NULL);
141 append_number(one, 3, NULL);
142 append_number(two, 4, NULL);
147 static void test_skip(void (*setup)(void))
149 char t[] = "/tmp/journal-skip-XXXXXX";
153 assert_se(mkdtemp(t));
154 assert_se(chdir(t) >= 0);
158 /* Seek to head, iterate down.
160 assert_ret(sd_journal_open_directory(&j, t, 0));
161 assert_ret(sd_journal_seek_head(j));
162 assert_ret(sd_journal_next(j));
163 test_check_numbers_down(j, 4);
166 /* Seek to tail, iterate up.
168 assert_ret(sd_journal_open_directory(&j, t, 0));
169 assert_ret(sd_journal_seek_tail(j));
170 assert_ret(sd_journal_previous(j));
171 test_check_numbers_up(j, 4);
174 /* Seek to tail, skip to head, iterate down.
176 assert_ret(sd_journal_open_directory(&j, t, 0));
177 assert_ret(sd_journal_seek_tail(j));
178 assert_ret(r = sd_journal_previous_skip(j, 4));
180 test_check_numbers_down(j, 4);
183 /* Seek to head, skip to tail, iterate up.
185 assert_ret(sd_journal_open_directory(&j, t, 0));
186 assert_ret(sd_journal_seek_head(j));
187 assert_ret(r = sd_journal_next_skip(j, 4));
189 test_check_numbers_up(j, 4);
195 log_info("Not removing %s", t);
197 journal_directory_vacuum(".", 3000000, 0, 0, NULL);
199 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
202 puts("------------------------------------------------------------");
205 static void test_sequence_numbers(void) {
207 char t[] = "/tmp/journal-seq-XXXXXX";
208 JournalFile *one, *two;
210 sd_id128_t seqnum_id;
212 assert_se(mkdtemp(t));
213 assert_se(chdir(t) >= 0);
215 assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
216 true, false, NULL, NULL, NULL, &one) == 0);
218 append_number(one, 1, &seqnum);
219 printf("seqnum=%"PRIu64"\n", seqnum);
221 append_number(one, 2, &seqnum);
222 printf("seqnum=%"PRIu64"\n", seqnum);
225 assert(one->header->state == STATE_ONLINE);
226 assert(!sd_id128_equal(one->header->file_id, one->header->machine_id));
227 assert(!sd_id128_equal(one->header->file_id, one->header->boot_id));
228 assert(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
230 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
232 assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
233 true, false, NULL, NULL, one, &two) == 0);
235 assert(two->header->state == STATE_ONLINE);
236 assert(!sd_id128_equal(two->header->file_id, one->header->file_id));
237 assert(sd_id128_equal(one->header->machine_id, one->header->machine_id));
238 assert(sd_id128_equal(one->header->boot_id, one->header->boot_id));
239 assert(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
241 append_number(two, 3, &seqnum);
242 printf("seqnum=%"PRIu64"\n", seqnum);
244 append_number(two, 4, &seqnum);
245 printf("seqnum=%"PRIu64"\n", seqnum);
250 append_number(one, 5, &seqnum);
251 printf("seqnum=%"PRIu64"\n", seqnum);
254 append_number(one, 6, &seqnum);
255 printf("seqnum=%"PRIu64"\n", seqnum);
263 assert_se(journal_file_open("two.journal", O_RDWR, 0,
264 true, false, NULL, NULL, NULL, &two) == 0);
266 assert(sd_id128_equal(two->header->seqnum_id, seqnum_id));
268 append_number(two, 7, &seqnum);
269 printf("seqnum=%"PRIu64"\n", seqnum);
272 /* So..., here we have the same seqnum in two files with the
280 log_info("Not removing %s", t);
282 journal_directory_vacuum(".", 3000000, 0, 0, NULL);
284 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
288 int main(int argc, char *argv[]) {
289 log_set_max_level(LOG_DEBUG);
293 test_skip(setup_sequential);
294 test_skip(setup_interleaved);
296 test_sequence_numbers();