Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <fcntl.h>
4 : : #include <unistd.h>
5 : :
6 : : #include "sd-journal.h"
7 : :
8 : : #include "alloc-util.h"
9 : : #include "chattr-util.h"
10 : : #include "io-util.h"
11 : : #include "journal-file.h"
12 : : #include "journal-vacuum.h"
13 : : #include "log.h"
14 : : #include "parse-util.h"
15 : : #include "rm-rf.h"
16 : : #include "tests.h"
17 : : #include "util.h"
18 : :
19 : : /* This program tests skipping around in a multi-file journal. */
20 : :
21 : : static bool arg_keep = false;
22 : :
23 : 0 : _noreturn_ static void log_assert_errno(const char *text, int error, const char *file, int line, const char *func) {
24 : 0 : log_internal(LOG_CRIT, error, file, line, func,
25 : : "'%s' failed at %s:%u (%s): %m", text, file, line, func);
26 : 0 : abort();
27 : : }
28 : :
29 : : #define assert_ret(expr) \
30 : : do { \
31 : : int _r_ = (expr); \
32 : : if (_unlikely_(_r_ < 0)) \
33 : : log_assert_errno(#expr, -_r_, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
34 : : } while (false)
35 : :
36 : 16 : static JournalFile *test_open(const char *name) {
37 : : JournalFile *f;
38 [ - + ]: 16 : assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &f));
39 : 16 : return f;
40 : : }
41 : :
42 : 28 : static void test_close(JournalFile *f) {
43 : 28 : (void) journal_file_close (f);
44 : 28 : }
45 : :
46 : 60 : static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
47 : : char *p;
48 : : dual_timestamp ts;
49 : : static dual_timestamp previous_ts = {};
50 : : struct iovec iovec[1];
51 : :
52 : 60 : dual_timestamp_get(&ts);
53 : :
54 [ - + ]: 60 : if (ts.monotonic <= previous_ts.monotonic)
55 : 0 : ts.monotonic = previous_ts.monotonic + 1;
56 : :
57 [ - + ]: 60 : if (ts.realtime <= previous_ts.realtime)
58 : 0 : ts.realtime = previous_ts.realtime + 1;
59 : :
60 : 60 : previous_ts = ts;
61 : :
62 [ - + ]: 60 : assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
63 : 60 : iovec[0] = IOVEC_MAKE_STRING(p);
64 [ - + ]: 60 : assert_ret(journal_file_append_entry(f, &ts, NULL, iovec, 1, seqnum, NULL, NULL));
65 : 60 : free(p);
66 : 60 : }
67 : :
68 : 128 : static void test_check_number (sd_journal *j, int n) {
69 : : const void *d;
70 : 128 : _cleanup_free_ char *k;
71 : : size_t l;
72 : : int x;
73 : :
74 [ - + ]: 128 : assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
75 [ - + ]: 128 : assert_se(k = strndup(d, l));
76 : 128 : printf("%s\n", k);
77 : :
78 [ - + ]: 128 : assert_se(safe_atoi(k + 7, &x) >= 0);
79 [ - + ]: 128 : assert_se(n == x);
80 : 128 : }
81 : :
82 : 16 : static void test_check_numbers_down (sd_journal *j, int count) {
83 : : int i;
84 : :
85 [ + + ]: 80 : for (i = 1; i <= count; i++) {
86 : : int r;
87 : 64 : test_check_number(j, i);
88 [ - + ]: 64 : assert_ret(r = sd_journal_next(j));
89 [ + + ]: 64 : if (i == count)
90 [ - + ]: 16 : assert_se(r == 0);
91 : : else
92 [ - + ]: 48 : assert_se(r == 1);
93 : : }
94 : :
95 : 16 : }
96 : :
97 : 16 : static void test_check_numbers_up (sd_journal *j, int count) {
98 [ + + ]: 80 : for (int i = count; i >= 1; i--) {
99 : : int r;
100 : 64 : test_check_number(j, i);
101 [ - + ]: 64 : assert_ret(r = sd_journal_previous(j));
102 [ + + ]: 64 : if (i == 1)
103 [ - + ]: 16 : assert_se(r == 0);
104 : : else
105 [ - + ]: 48 : assert_se(r == 1);
106 : : }
107 : :
108 : 16 : }
109 : :
110 : 4 : static void setup_sequential(void) {
111 : : JournalFile *one, *two;
112 : 4 : one = test_open("one.journal");
113 : 4 : two = test_open("two.journal");
114 : 4 : append_number(one, 1, NULL);
115 : 4 : append_number(one, 2, NULL);
116 : 4 : append_number(two, 3, NULL);
117 : 4 : append_number(two, 4, NULL);
118 : 4 : test_close(one);
119 : 4 : test_close(two);
120 : 4 : }
121 : :
122 : 4 : static void setup_interleaved(void) {
123 : : JournalFile *one, *two;
124 : 4 : one = test_open("one.journal");
125 : 4 : two = test_open("two.journal");
126 : 4 : append_number(one, 1, NULL);
127 : 4 : append_number(two, 2, NULL);
128 : 4 : append_number(one, 3, NULL);
129 : 4 : append_number(two, 4, NULL);
130 : 4 : test_close(one);
131 : 4 : test_close(two);
132 : 4 : }
133 : :
134 : 12 : static void mkdtemp_chdir_chattr(char *path) {
135 [ - + ]: 12 : assert_se(mkdtemp(path));
136 [ - + ]: 12 : assert_se(chdir(path) >= 0);
137 : :
138 : : /* Speed up things a bit on btrfs, ensuring that CoW is turned off for all files created in our
139 : : * directory during the test run */
140 : 12 : (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
141 : 12 : }
142 : :
143 : 8 : static void test_skip(void (*setup)(void)) {
144 : 8 : char t[] = "/var/tmp/journal-skip-XXXXXX";
145 : : sd_journal *j;
146 : : int r;
147 : :
148 : 8 : mkdtemp_chdir_chattr(t);
149 : :
150 : 8 : setup();
151 : :
152 : : /* Seek to head, iterate down.
153 : : */
154 [ - + ]: 8 : assert_ret(sd_journal_open_directory(&j, t, 0));
155 [ - + ]: 8 : assert_ret(sd_journal_seek_head(j));
156 [ - + ]: 8 : assert_ret(sd_journal_next(j));
157 : 8 : test_check_numbers_down(j, 4);
158 : 8 : sd_journal_close(j);
159 : :
160 : : /* Seek to tail, iterate up.
161 : : */
162 [ - + ]: 8 : assert_ret(sd_journal_open_directory(&j, t, 0));
163 [ - + ]: 8 : assert_ret(sd_journal_seek_tail(j));
164 [ - + ]: 8 : assert_ret(sd_journal_previous(j));
165 : 8 : test_check_numbers_up(j, 4);
166 : 8 : sd_journal_close(j);
167 : :
168 : : /* Seek to tail, skip to head, iterate down.
169 : : */
170 [ - + ]: 8 : assert_ret(sd_journal_open_directory(&j, t, 0));
171 [ - + ]: 8 : assert_ret(sd_journal_seek_tail(j));
172 [ - + ]: 8 : assert_ret(r = sd_journal_previous_skip(j, 4));
173 [ - + ]: 8 : assert_se(r == 4);
174 : 8 : test_check_numbers_down(j, 4);
175 : 8 : sd_journal_close(j);
176 : :
177 : : /* Seek to head, skip to tail, iterate up.
178 : : */
179 [ - + ]: 8 : assert_ret(sd_journal_open_directory(&j, t, 0));
180 [ - + ]: 8 : assert_ret(sd_journal_seek_head(j));
181 [ - + ]: 8 : assert_ret(r = sd_journal_next_skip(j, 4));
182 [ - + ]: 8 : assert_se(r == 4);
183 : 8 : test_check_numbers_up(j, 4);
184 : 8 : sd_journal_close(j);
185 : :
186 [ + - ]: 8 : log_info("Done...");
187 : :
188 [ - + ]: 8 : if (arg_keep)
189 [ # # ]: 0 : log_info("Not removing %s", t);
190 : : else {
191 : 8 : journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
192 : :
193 [ - + ]: 8 : assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
194 : : }
195 : :
196 : 8 : puts("------------------------------------------------------------");
197 : 8 : }
198 : :
199 : 4 : static void test_sequence_numbers(void) {
200 : :
201 : 4 : char t[] = "/var/tmp/journal-seq-XXXXXX";
202 : : JournalFile *one, *two;
203 : 4 : uint64_t seqnum = 0;
204 : : sd_id128_t seqnum_id;
205 : :
206 : 4 : mkdtemp_chdir_chattr(t);
207 : :
208 [ - + ]: 4 : assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644,
209 : : true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &one) == 0);
210 : :
211 : 4 : append_number(one, 1, &seqnum);
212 : 4 : printf("seqnum=%"PRIu64"\n", seqnum);
213 [ - + ]: 4 : assert_se(seqnum == 1);
214 : 4 : append_number(one, 2, &seqnum);
215 : 4 : printf("seqnum=%"PRIu64"\n", seqnum);
216 [ - + ]: 4 : assert_se(seqnum == 2);
217 : :
218 [ - + ]: 4 : assert_se(one->header->state == STATE_ONLINE);
219 [ - + ]: 4 : assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
220 [ - + ]: 4 : assert_se(!sd_id128_equal(one->header->file_id, one->header->boot_id));
221 [ - + ]: 4 : assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
222 : :
223 : 4 : memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
224 : :
225 [ - + ]: 4 : assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0644,
226 : : true, (uint64_t) -1, false, NULL, NULL, NULL, one, &two) == 0);
227 : :
228 [ - + ]: 4 : assert_se(two->header->state == STATE_ONLINE);
229 [ - + ]: 4 : assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
230 [ - + ]: 4 : assert_se(sd_id128_equal(one->header->machine_id, one->header->machine_id));
231 [ - + ]: 4 : assert_se(sd_id128_equal(one->header->boot_id, one->header->boot_id));
232 [ - + ]: 4 : assert_se(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
233 : :
234 : 4 : append_number(two, 3, &seqnum);
235 : 4 : printf("seqnum=%"PRIu64"\n", seqnum);
236 [ - + ]: 4 : assert_se(seqnum == 3);
237 : 4 : append_number(two, 4, &seqnum);
238 : 4 : printf("seqnum=%"PRIu64"\n", seqnum);
239 [ - + ]: 4 : assert_se(seqnum == 4);
240 : :
241 : 4 : test_close(two);
242 : :
243 : 4 : append_number(one, 5, &seqnum);
244 : 4 : printf("seqnum=%"PRIu64"\n", seqnum);
245 [ - + ]: 4 : assert_se(seqnum == 5);
246 : :
247 : 4 : append_number(one, 6, &seqnum);
248 : 4 : printf("seqnum=%"PRIu64"\n", seqnum);
249 [ - + ]: 4 : assert_se(seqnum == 6);
250 : :
251 : 4 : test_close(one);
252 : :
253 : : /* restart server */
254 : 4 : seqnum = 0;
255 : :
256 [ - + ]: 4 : assert_se(journal_file_open(-1, "two.journal", O_RDWR, 0,
257 : : true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &two) == 0);
258 : :
259 [ - + ]: 4 : assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
260 : :
261 : 4 : append_number(two, 7, &seqnum);
262 : 4 : printf("seqnum=%"PRIu64"\n", seqnum);
263 [ - + ]: 4 : assert_se(seqnum == 5);
264 : :
265 : : /* So..., here we have the same seqnum in two files with the
266 : : * same seqnum_id. */
267 : :
268 : 4 : test_close(two);
269 : :
270 [ + - ]: 4 : log_info("Done...");
271 : :
272 [ - + ]: 4 : if (arg_keep)
273 [ # # ]: 0 : log_info("Not removing %s", t);
274 : : else {
275 : 4 : journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
276 : :
277 [ - + ]: 4 : assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
278 : : }
279 : 4 : }
280 : :
281 : 4 : int main(int argc, char *argv[]) {
282 : 4 : test_setup_logging(LOG_DEBUG);
283 : :
284 : : /* journal_file_open requires a valid machine id */
285 [ - + ]: 4 : if (access("/etc/machine-id", F_OK) != 0)
286 : 0 : return log_tests_skipped("/etc/machine-id not found");
287 : :
288 : 4 : arg_keep = argc > 1;
289 : :
290 : 4 : test_skip(setup_sequential);
291 : 4 : test_skip(setup_interleaved);
292 : :
293 : 4 : test_sequence_numbers();
294 : :
295 : 4 : return 0;
296 : : }
|