]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/test-journal-interleaving.c
gpt-auto-generator: use EBADSLT code when unable to detect partition type
[thirdparty/systemd.git] / src / journal / test-journal-interleaving.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Marius Vollmer
7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
8
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.
13
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.
18
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/>.
21 ***/
22
23 #include <unistd.h>
24 #include <fcntl.h>
25
26 #include <systemd/sd-journal.h>
27
28 #include "journal-file.h"
29 #include "journal-internal.h"
30 #include "journal-vacuum.h"
31 #include "util.h"
32 #include "log.h"
33
34 /* This program tests skipping around in a multi-file journal.
35 */
36
37 static bool arg_keep = false;
38
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));
43 abort();
44 }
45
46 #define assert_ret(expr) \
47 do { \
48 int _r_ = (expr); \
49 if (_unlikely_(_r_ < 0)) \
50 log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
51 } while (false)
52
53 static JournalFile *test_open(const char *name) {
54 JournalFile *f;
55 assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
56 return f;
57 }
58
59 static void test_close(JournalFile *f) {
60 journal_file_close (f);
61 }
62
63 static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
64 char *p;
65 dual_timestamp ts;
66 struct iovec iovec[1];
67
68 dual_timestamp_get(&ts);
69
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));
74 free(p);
75 }
76
77 static void test_check_number (sd_journal *j, int n) {
78 const void *d;
79 _cleanup_free_ char *k;
80 size_t l;
81 int x;
82
83 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
84 assert_se(k = strndup(d, l));
85 printf("%s\n", k);
86
87 assert_se(safe_atoi(k + 7, &x) >= 0);
88 assert_se(n == x);
89 }
90
91 static void test_check_numbers_down (sd_journal *j, int count) {
92 int i;
93
94 for (i = 1; i <= count; i++) {
95 int r;
96 test_check_number(j, i);
97 assert_ret(r = sd_journal_next(j));
98 if (i == count)
99 assert_se(r == 0);
100 else
101 assert_se(r == 1);
102 }
103
104 }
105
106 static void test_check_numbers_up (sd_journal *j, int count) {
107 for (int i = count; i >= 1; i--) {
108 int r;
109 test_check_number(j, i);
110 assert_ret(r = sd_journal_previous(j));
111 if (i == 1)
112 assert_se(r == 0);
113 else
114 assert_se(r == 1);
115 }
116
117 }
118
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);
127 test_close(one);
128 test_close(two);
129 }
130
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);
139 test_close(one);
140 test_close(two);
141 }
142
143 static void test_skip(void (*setup)(void)) {
144 char t[] = "/tmp/journal-skip-XXXXXX";
145 sd_journal *j;
146 int r;
147
148 assert_se(mkdtemp(t));
149 assert_se(chdir(t) >= 0);
150
151 setup();
152
153 /* Seek to head, iterate down.
154 */
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);
159 sd_journal_close(j);
160
161 /* Seek to tail, iterate up.
162 */
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);
167 sd_journal_close(j);
168
169 /* Seek to tail, skip to head, iterate down.
170 */
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));
174 assert_se(r == 4);
175 test_check_numbers_down(j, 4);
176 sd_journal_close(j);
177
178 /* Seek to head, skip to tail, iterate up.
179 */
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));
183 assert_se(r == 4);
184 test_check_numbers_up(j, 4);
185 sd_journal_close(j);
186
187 log_info("Done...");
188
189 if (arg_keep)
190 log_info("Not removing %s", t);
191 else {
192 journal_directory_vacuum(".", 3000000, 0, 0, NULL);
193
194 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
195 }
196
197 puts("------------------------------------------------------------");
198 }
199
200 static void test_sequence_numbers(void) {
201
202 char t[] = "/tmp/journal-seq-XXXXXX";
203 JournalFile *one, *two;
204 uint64_t seqnum = 0;
205 sd_id128_t seqnum_id;
206
207 assert_se(mkdtemp(t));
208 assert_se(chdir(t) >= 0);
209
210 assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
211 true, false, NULL, NULL, NULL, &one) == 0);
212
213 append_number(one, 1, &seqnum);
214 printf("seqnum=%"PRIu64"\n", seqnum);
215 assert(seqnum == 1);
216 append_number(one, 2, &seqnum);
217 printf("seqnum=%"PRIu64"\n", seqnum);
218 assert(seqnum == 2);
219
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));
224
225 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
226
227 assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
228 true, false, NULL, NULL, one, &two) == 0);
229
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));
235
236 append_number(two, 3, &seqnum);
237 printf("seqnum=%"PRIu64"\n", seqnum);
238 assert(seqnum == 3);
239 append_number(two, 4, &seqnum);
240 printf("seqnum=%"PRIu64"\n", seqnum);
241 assert(seqnum == 4);
242
243 test_close(two);
244
245 append_number(one, 5, &seqnum);
246 printf("seqnum=%"PRIu64"\n", seqnum);
247 assert(seqnum == 5);
248
249 append_number(one, 6, &seqnum);
250 printf("seqnum=%"PRIu64"\n", seqnum);
251 assert(seqnum == 6);
252
253 test_close(one);
254
255 /* restart server */
256 seqnum = 0;
257
258 assert_se(journal_file_open("two.journal", O_RDWR, 0,
259 true, false, NULL, NULL, NULL, &two) == 0);
260
261 assert(sd_id128_equal(two->header->seqnum_id, seqnum_id));
262
263 append_number(two, 7, &seqnum);
264 printf("seqnum=%"PRIu64"\n", seqnum);
265 assert(seqnum == 5);
266
267 /* So..., here we have the same seqnum in two files with the
268 * same seqnum_id. */
269
270 test_close(two);
271
272 log_info("Done...");
273
274 if (arg_keep)
275 log_info("Not removing %s", t);
276 else {
277 journal_directory_vacuum(".", 3000000, 0, 0, NULL);
278
279 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
280 }
281 }
282
283 int main(int argc, char *argv[]) {
284 log_set_max_level(LOG_DEBUG);
285
286 /* journal_file_open requires a valid machine id */
287 if (access("/etc/machine-id", F_OK) != 0)
288 return EXIT_TEST_SKIP;
289
290 arg_keep = argc > 1;
291
292 test_skip(setup_sequential);
293 test_skip(setup_interleaved);
294
295 test_sequence_numbers();
296
297 return 0;
298 }