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-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 struct iovec iovec[1];
67 dual_timestamp_get(&ts);
69 assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
70 iovec[0].iov_base = p;
71 iovec[0].iov_len = strlen(p);
72 assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
76 static void test_check_number (sd_journal *j, int n) {
78 _cleanup_free_ char *k;
82 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
83 assert_se(k = strndup(d, l));
86 assert_se(safe_atoi(k + 7, &x) >= 0);
90 static void test_check_numbers_down (sd_journal *j, int count) {
93 for (i = 1; i <= count; i++) {
95 test_check_number(j, i);
96 assert_ret(r = sd_journal_next(j));
105 static void test_check_numbers_up (sd_journal *j, int count) {
106 for (int i = count; i >= 1; i--) {
108 test_check_number(j, i);
109 assert_ret(r = sd_journal_previous(j));
118 static void setup_sequential(void) {
119 JournalFile *one, *two;
120 one = test_open("one.journal");
121 two = test_open("two.journal");
122 append_number(one, 1, NULL);
123 append_number(one, 2, NULL);
124 append_number(two, 3, NULL);
125 append_number(two, 4, NULL);
130 static void setup_interleaved(void) {
131 JournalFile *one, *two;
132 one = test_open("one.journal");
133 two = test_open("two.journal");
134 append_number(one, 1, NULL);
135 append_number(two, 2, NULL);
136 append_number(one, 3, NULL);
137 append_number(two, 4, NULL);
142 static void test_skip(void (*setup)(void)) {
143 char t[] = "/tmp/journal-skip-XXXXXX";
147 assert_se(mkdtemp(t));
148 assert_se(chdir(t) >= 0);
152 /* Seek to head, iterate down.
154 assert_ret(sd_journal_open_directory(&j, t, 0));
155 assert_ret(sd_journal_seek_head(j));
156 assert_ret(sd_journal_next(j));
157 test_check_numbers_down(j, 4);
160 /* Seek to tail, iterate up.
162 assert_ret(sd_journal_open_directory(&j, t, 0));
163 assert_ret(sd_journal_seek_tail(j));
164 assert_ret(sd_journal_previous(j));
165 test_check_numbers_up(j, 4);
168 /* Seek to tail, skip to head, iterate down.
170 assert_ret(sd_journal_open_directory(&j, t, 0));
171 assert_ret(sd_journal_seek_tail(j));
172 assert_ret(r = sd_journal_previous_skip(j, 4));
174 test_check_numbers_down(j, 4);
177 /* Seek to head, skip to tail, iterate up.
179 assert_ret(sd_journal_open_directory(&j, t, 0));
180 assert_ret(sd_journal_seek_head(j));
181 assert_ret(r = sd_journal_next_skip(j, 4));
183 test_check_numbers_up(j, 4);
189 log_info("Not removing %s", t);
191 journal_directory_vacuum(".", 3000000, 0, NULL, true);
193 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
196 puts("------------------------------------------------------------");
199 static void test_sequence_numbers(void) {
201 char t[] = "/tmp/journal-seq-XXXXXX";
202 JournalFile *one, *two;
204 sd_id128_t seqnum_id;
206 assert_se(mkdtemp(t));
207 assert_se(chdir(t) >= 0);
209 assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
210 true, false, NULL, NULL, NULL, &one) == 0);
212 append_number(one, 1, &seqnum);
213 printf("seqnum=%"PRIu64"\n", seqnum);
214 assert_se(seqnum == 1);
215 append_number(one, 2, &seqnum);
216 printf("seqnum=%"PRIu64"\n", seqnum);
217 assert_se(seqnum == 2);
219 assert_se(one->header->state == STATE_ONLINE);
220 assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
221 assert_se(!sd_id128_equal(one->header->file_id, one->header->boot_id));
222 assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
224 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
226 assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
227 true, false, NULL, NULL, one, &two) == 0);
229 assert_se(two->header->state == STATE_ONLINE);
230 assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
231 assert_se(sd_id128_equal(one->header->machine_id, one->header->machine_id));
232 assert_se(sd_id128_equal(one->header->boot_id, one->header->boot_id));
233 assert_se(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
235 append_number(two, 3, &seqnum);
236 printf("seqnum=%"PRIu64"\n", seqnum);
237 assert_se(seqnum == 3);
238 append_number(two, 4, &seqnum);
239 printf("seqnum=%"PRIu64"\n", seqnum);
240 assert_se(seqnum == 4);
244 append_number(one, 5, &seqnum);
245 printf("seqnum=%"PRIu64"\n", seqnum);
246 assert_se(seqnum == 5);
248 append_number(one, 6, &seqnum);
249 printf("seqnum=%"PRIu64"\n", seqnum);
250 assert_se(seqnum == 6);
257 assert_se(journal_file_open("two.journal", O_RDWR, 0,
258 true, false, NULL, NULL, NULL, &two) == 0);
260 assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
262 append_number(two, 7, &seqnum);
263 printf("seqnum=%"PRIu64"\n", seqnum);
264 assert_se(seqnum == 5);
266 /* So..., here we have the same seqnum in two files with the
274 log_info("Not removing %s", t);
276 journal_directory_vacuum(".", 3000000, 0, NULL, true);
278 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
282 int main(int argc, char *argv[]) {
283 log_set_max_level(LOG_DEBUG);
285 /* journal_file_open requires a valid machine id */
286 if (access("/etc/machine-id", F_OK) != 0)
287 return EXIT_TEST_SKIP;
291 test_skip(setup_sequential);
292 test_skip(setup_interleaved);
294 test_sequence_numbers();