]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/sd-journal.c
hwdb: Update database of Bluetooth company identifiers
[thirdparty/systemd.git] / src / journal / sd-journal.c
CommitLineData
87d2c1ff
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
87d2c1ff
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
87d2c1ff 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
87d2c1ff
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
87d2c1ff 22#include <errno.h>
87d2c1ff 23#include <fcntl.h>
3fbf9cbb 24#include <stddef.h>
50f20cfd
LP
25#include <unistd.h>
26#include <sys/inotify.h>
0a6f50c0 27#include <poll.h>
85210bff
LP
28#include <sys/vfs.h>
29#include <linux/magic.h>
87d2c1ff
LP
30
31#include "sd-journal.h"
32#include "journal-def.h"
cec736d2 33#include "journal-file.h"
260a2be4 34#include "hashmap.h"
cec736d2 35#include "list.h"
5302ebe1 36#include "strv.h"
9eb977db 37#include "path-util.h"
de7b95cd 38#include "lookup3.h"
807e17f0 39#include "compress.h"
cf244689 40#include "journal-internal.h"
85210bff 41#include "missing.h"
d4205751
LP
42#include "catalog.h"
43#include "replace-var.h"
b6741478 44#include "fileio.h"
87d2c1ff 45
9e8abdf0
LP
46#define JOURNAL_FILES_MAX 7168
47
85210bff
LP
48#define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
49
d4205751
LP
50#define REPLACE_VAR_MAX 256
51
93b73b06
LP
52#define DEFAULT_DATA_THRESHOLD (64*1024)
53
a9a245c1
ZJS
54static void remove_file_real(sd_journal *j, JournalFile *f);
55
a65f06bb
ZJS
56static bool journal_pid_changed(sd_journal *j) {
57 assert(j);
58
59 /* We don't support people creating a journal object and
60 * keeping it around over a fork(). Let's complain. */
61
62 return j->original_pid != getpid();
63}
64
6fe391c5
ZJS
65/* We return an error here only if we didn't manage to
66 memorize the real error. */
3ac251b8
LP
67static int set_put_error(sd_journal *j, int r) {
68 int k;
69
6fe391c5
ZJS
70 if (r >= 0)
71 return r;
72
d5099efc 73 k = set_ensure_allocated(&j->errors, NULL);
3ac251b8
LP
74 if (k < 0)
75 return k;
76
77 return set_put(j->errors, INT_TO_PTR(r));
6fe391c5
ZJS
78}
79
de190aef 80static void detach_location(sd_journal *j) {
8f9b6cd9
LP
81 Iterator i;
82 JournalFile *f;
83
84 assert(j);
85
86 j->current_file = NULL;
87 j->current_field = 0;
88
c1f906bd 89 ORDERED_HASHMAP_FOREACH(f, j->files, i)
1fc605b0 90 journal_file_reset_location(f);
8f9b6cd9
LP
91}
92
de190aef
LP
93static void reset_location(sd_journal *j) {
94 assert(j);
95
96 detach_location(j);
97 zero(j->current_location);
98}
99
a87247dd 100static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
de190aef 101 assert(l);
a87247dd 102 assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
de190aef
LP
103 assert(f);
104 assert(o->object.type == OBJECT_ENTRY);
105
a87247dd 106 l->type = type;
de190aef
LP
107 l->seqnum = le64toh(o->entry.seqnum);
108 l->seqnum_id = f->header->seqnum_id;
109 l->realtime = le64toh(o->entry.realtime);
110 l->monotonic = le64toh(o->entry.monotonic);
ce3fd7e7 111 l->boot_id = o->entry.boot_id;
de190aef
LP
112 l->xor_hash = le64toh(o->entry.xor_hash);
113
114 l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
115}
116
1eb6332d 117static void set_location(sd_journal *j, JournalFile *f, Object *o) {
de190aef
LP
118 assert(j);
119 assert(f);
120 assert(o);
121
1eb6332d 122 init_location(&j->current_location, LOCATION_DISCRETE, f, o);
de190aef
LP
123
124 j->current_file = f;
125 j->current_field = 0;
126
6573ef05
MS
127 /* Let f know its candidate entry was picked. */
128 assert(f->location_type == LOCATION_SEEK);
129 f->location_type = LOCATION_DISCRETE;
de190aef
LP
130}
131
cbdca852
LP
132static int match_is_valid(const void *data, size_t size) {
133 const char *b, *p;
134
135 assert(data);
136
137 if (size < 2)
138 return false;
139
140 if (startswith(data, "__"))
141 return false;
142
143 b = data;
144 for (p = b; p < b + size; p++) {
145
146 if (*p == '=')
147 return p > b;
148
149 if (*p == '_')
150 continue;
151
152 if (*p >= 'A' && *p <= 'Z')
153 continue;
154
155 if (*p >= '0' && *p <= '9')
156 continue;
157
158 return false;
159 }
160
161 return false;
162}
163
164static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
de190aef
LP
165 const uint8_t *a = _a, *b = _b;
166 size_t j;
de190aef
LP
167
168 for (j = 0; j < s && j < t; j++) {
169
de190aef 170 if (a[j] != b[j])
cbdca852 171 return false;
de190aef 172
cbdca852
LP
173 if (a[j] == '=')
174 return true;
de190aef
LP
175 }
176
bc302926 177 assert_not_reached("\"=\" not found");
cbdca852
LP
178}
179
180static Match *match_new(Match *p, MatchType t) {
181 Match *m;
182
183 m = new0(Match, 1);
184 if (!m)
185 return NULL;
186
187 m->type = t;
188
189 if (p) {
190 m->parent = p;
71fda00f 191 LIST_PREPEND(matches, p->matches, m);
cbdca852
LP
192 }
193
194 return m;
195}
196
197static void match_free(Match *m) {
198 assert(m);
199
200 while (m->matches)
201 match_free(m->matches);
202
203 if (m->parent)
71fda00f 204 LIST_REMOVE(matches, m->parent->matches, m);
cbdca852
LP
205
206 free(m->data);
207 free(m);
208}
209
210static void match_free_if_empty(Match *m) {
c5a10d9c 211 if (!m || m->matches)
cbdca852
LP
212 return;
213
214 match_free(m);
de190aef
LP
215}
216
a5344d2c 217_public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
cd34b3c6 218 Match *l3, *l4, *add_here = NULL, *m;
4fd052ae 219 le64_t le_hash;
87d2c1ff 220
1ae464e0
TA
221 assert_return(j, -EINVAL);
222 assert_return(!journal_pid_changed(j), -ECHILD);
223 assert_return(data, -EINVAL);
cbdca852
LP
224
225 if (size == 0)
226 size = strlen(data);
227
1ae464e0 228 assert_return(match_is_valid(data, size), -EINVAL);
1cc101f1 229
cd34b3c6
HH
230 /* level 0: AND term
231 * level 1: OR terms
232 * level 2: AND terms
233 * level 3: OR terms
234 * level 4: concrete matches */
cbdca852
LP
235
236 if (!j->level0) {
cd34b3c6 237 j->level0 = match_new(NULL, MATCH_AND_TERM);
cbdca852
LP
238 if (!j->level0)
239 return -ENOMEM;
240 }
241
242 if (!j->level1) {
cd34b3c6 243 j->level1 = match_new(j->level0, MATCH_OR_TERM);
cbdca852
LP
244 if (!j->level1)
245 return -ENOMEM;
246 }
247
cd34b3c6
HH
248 if (!j->level2) {
249 j->level2 = match_new(j->level1, MATCH_AND_TERM);
250 if (!j->level2)
251 return -ENOMEM;
252 }
253
254 assert(j->level0->type == MATCH_AND_TERM);
255 assert(j->level1->type == MATCH_OR_TERM);
256 assert(j->level2->type == MATCH_AND_TERM);
ab4979d2 257
de190aef
LP
258 le_hash = htole64(hash64(data, size));
259
cd34b3c6
HH
260 LIST_FOREACH(matches, l3, j->level2->matches) {
261 assert(l3->type == MATCH_OR_TERM);
de190aef 262
cd34b3c6
HH
263 LIST_FOREACH(matches, l4, l3->matches) {
264 assert(l4->type == MATCH_DISCRETE);
de190aef 265
cbdca852
LP
266 /* Exactly the same match already? Then ignore
267 * this addition */
cd34b3c6
HH
268 if (l4->le_hash == le_hash &&
269 l4->size == size &&
270 memcmp(l4->data, data, size) == 0)
cbdca852
LP
271 return 0;
272
273 /* Same field? Then let's add this to this OR term */
cd34b3c6
HH
274 if (same_field(data, size, l4->data, l4->size)) {
275 add_here = l3;
cbdca852
LP
276 break;
277 }
278 }
279
280 if (add_here)
281 break;
de190aef
LP
282 }
283
cbdca852 284 if (!add_here) {
cd34b3c6 285 add_here = match_new(j->level2, MATCH_OR_TERM);
cbdca852
LP
286 if (!add_here)
287 goto fail;
288 }
289
290 m = match_new(add_here, MATCH_DISCRETE);
cec736d2 291 if (!m)
cbdca852 292 goto fail;
87d2c1ff 293
cbdca852 294 m->le_hash = le_hash;
1cc101f1 295 m->size = size;
cbdca852
LP
296 m->data = memdup(data, size);
297 if (!m->data)
298 goto fail;
299
300 detach_location(j);
301
302 return 0;
303
304fail:
c5a10d9c
ZJS
305 match_free_if_empty(add_here);
306 match_free_if_empty(j->level2);
307 match_free_if_empty(j->level1);
308 match_free_if_empty(j->level0);
cbdca852
LP
309
310 return -ENOMEM;
311}
312
cd34b3c6 313_public_ int sd_journal_add_conjunction(sd_journal *j) {
1ae464e0
TA
314 assert_return(j, -EINVAL);
315 assert_return(!journal_pid_changed(j), -ECHILD);
1cc101f1 316
cbdca852
LP
317 if (!j->level0)
318 return 0;
319
320 if (!j->level1)
321 return 0;
322
323 if (!j->level1->matches)
324 return 0;
325
cd34b3c6
HH
326 j->level1 = NULL;
327 j->level2 = NULL;
328
329 return 0;
330}
331
332_public_ int sd_journal_add_disjunction(sd_journal *j) {
1ae464e0
TA
333 assert_return(j, -EINVAL);
334 assert_return(!journal_pid_changed(j), -ECHILD);
cd34b3c6
HH
335
336 if (!j->level0)
337 return 0;
338
339 if (!j->level1)
340 return 0;
341
342 if (!j->level2)
343 return 0;
344
345 if (!j->level2->matches)
346 return 0;
cbdca852 347
cd34b3c6 348 j->level2 = NULL;
cbdca852
LP
349 return 0;
350}
351
352static char *match_make_string(Match *m) {
353 char *p, *r;
354 Match *i;
355 bool enclose = false;
356
357 if (!m)
4ad16808 358 return strdup("none");
cbdca852
LP
359
360 if (m->type == MATCH_DISCRETE)
361 return strndup(m->data, m->size);
362
363 p = NULL;
364 LIST_FOREACH(matches, i, m->matches) {
365 char *t, *k;
366
367 t = match_make_string(i);
368 if (!t) {
369 free(p);
370 return NULL;
371 }
372
373 if (p) {
b7def684 374 k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t, NULL);
cbdca852
LP
375 free(p);
376 free(t);
377
378 if (!k)
379 return NULL;
380
381 p = k;
382
383 enclose = true;
bc302926 384 } else
cbdca852 385 p = t;
87d2c1ff
LP
386 }
387
cbdca852 388 if (enclose) {
b7def684 389 r = strjoin("(", p, ")", NULL);
cbdca852
LP
390 free(p);
391 return r;
392 }
87d2c1ff 393
cbdca852
LP
394 return p;
395}
de7b95cd 396
cbdca852
LP
397char *journal_make_match_string(sd_journal *j) {
398 assert(j);
8f9b6cd9 399
cbdca852 400 return match_make_string(j->level0);
87d2c1ff
LP
401}
402
a5344d2c
LP
403_public_ void sd_journal_flush_matches(sd_journal *j) {
404 if (!j)
405 return;
87d2c1ff 406
cbdca852
LP
407 if (j->level0)
408 match_free(j->level0);
de7b95cd 409
cd34b3c6 410 j->level0 = j->level1 = j->level2 = NULL;
8f9b6cd9 411
de190aef 412 detach_location(j);
87d2c1ff
LP
413}
414
487d3720
MS
415_pure_ static int compare_with_location(JournalFile *f, Location *l) {
416 assert(f);
de190aef 417 assert(l);
487d3720 418 assert(f->location_type == LOCATION_SEEK);
a87247dd 419 assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
de190aef
LP
420
421 if (l->monotonic_set &&
487d3720 422 sd_id128_equal(f->current_boot_id, l->boot_id) &&
de190aef 423 l->realtime_set &&
487d3720 424 f->current_realtime == l->realtime &&
de190aef 425 l->xor_hash_set &&
487d3720 426 f->current_xor_hash == l->xor_hash)
de190aef
LP
427 return 0;
428
429 if (l->seqnum_set &&
487d3720 430 sd_id128_equal(f->header->seqnum_id, l->seqnum_id)) {
de190aef 431
487d3720 432 if (f->current_seqnum < l->seqnum)
de190aef 433 return -1;
487d3720 434 if (f->current_seqnum > l->seqnum)
de190aef
LP
435 return 1;
436 }
437
438 if (l->monotonic_set &&
487d3720 439 sd_id128_equal(f->current_boot_id, l->boot_id)) {
de190aef 440
487d3720 441 if (f->current_monotonic < l->monotonic)
de190aef 442 return -1;
487d3720 443 if (f->current_monotonic > l->monotonic)
de190aef
LP
444 return 1;
445 }
446
447 if (l->realtime_set) {
448
487d3720 449 if (f->current_realtime < l->realtime)
de190aef 450 return -1;
487d3720 451 if (f->current_realtime > l->realtime)
de190aef
LP
452 return 1;
453 }
454
455 if (l->xor_hash_set) {
de190aef 456
487d3720 457 if (f->current_xor_hash < l->xor_hash)
de190aef 458 return -1;
487d3720 459 if (f->current_xor_hash > l->xor_hash)
de190aef
LP
460 return 1;
461 }
462
463 return 0;
464}
465
cbdca852
LP
466static int next_for_match(
467 sd_journal *j,
468 Match *m,
469 JournalFile *f,
470 uint64_t after_offset,
471 direction_t direction,
472 Object **ret,
473 uint64_t *offset) {
474
de7b95cd 475 int r;
cbdca852
LP
476 uint64_t np = 0;
477 Object *n;
de7b95cd
LP
478
479 assert(j);
cbdca852
LP
480 assert(m);
481 assert(f);
de7b95cd 482
cbdca852
LP
483 if (m->type == MATCH_DISCRETE) {
484 uint64_t dp;
de190aef 485
cbdca852 486 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
de190aef
LP
487 if (r <= 0)
488 return r;
489
cbdca852 490 return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset);
de190aef 491
cbdca852
LP
492 } else if (m->type == MATCH_OR_TERM) {
493 Match *i;
de7b95cd 494
cbdca852 495 /* Find the earliest match beyond after_offset */
de190aef 496
cbdca852
LP
497 LIST_FOREACH(matches, i, m->matches) {
498 uint64_t cp;
de190aef 499
cbdca852 500 r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
b4e5f920
LP
501 if (r < 0)
502 return r;
cbdca852 503 else if (r > 0) {
bc302926 504 if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
cbdca852
LP
505 np = cp;
506 }
507 }
b4e5f920 508
bc302926
ZJS
509 if (np == 0)
510 return 0;
511
cbdca852 512 } else if (m->type == MATCH_AND_TERM) {
2bc8ca0c 513 Match *i, *last_moved;
de190aef 514
cbdca852 515 /* Always jump to the next matching entry and repeat
2bc8ca0c 516 * this until we find an offset that matches for all
cbdca852 517 * matches. */
de190aef 518
cbdca852
LP
519 if (!m->matches)
520 return 0;
de7b95cd 521
2bc8ca0c
ZJS
522 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
523 if (r <= 0)
524 return r;
de190aef 525
2bc8ca0c
ZJS
526 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
527 last_moved = m->matches;
de190aef 528
2bc8ca0c
ZJS
529 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
530 uint64_t cp;
de190aef 531
2bc8ca0c
ZJS
532 r = next_for_match(j, i, f, np, direction, NULL, &cp);
533 if (r <= 0)
534 return r;
de190aef 535
2bc8ca0c
ZJS
536 assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
537 if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
538 np = cp;
539 last_moved = i;
de190aef 540 }
2bc8ca0c 541 }
cbdca852 542 }
de190aef 543
bc302926 544 assert(np > 0);
de190aef 545
cbdca852
LP
546 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
547 if (r < 0)
548 return r;
de7b95cd 549
de190aef 550 if (ret)
cbdca852 551 *ret = n;
de190aef 552 if (offset)
cbdca852 553 *offset = np;
de190aef
LP
554
555 return 1;
556}
557
cbdca852
LP
558static int find_location_for_match(
559 sd_journal *j,
560 Match *m,
561 JournalFile *f,
562 direction_t direction,
563 Object **ret,
564 uint64_t *offset) {
565
de190aef 566 int r;
de190aef
LP
567
568 assert(j);
cbdca852 569 assert(m);
de190aef 570 assert(f);
de190aef 571
cbdca852
LP
572 if (m->type == MATCH_DISCRETE) {
573 uint64_t dp;
de190aef 574
cbdca852 575 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
de7b95cd
LP
576 if (r <= 0)
577 return r;
578
cbdca852 579 /* FIXME: missing: find by monotonic */
de7b95cd 580
cbdca852
LP
581 if (j->current_location.type == LOCATION_HEAD)
582 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
583 if (j->current_location.type == LOCATION_TAIL)
584 return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset);
585 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
586 return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
587 if (j->current_location.monotonic_set) {
588 r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
589 if (r != -ENOENT)
590 return r;
591 }
592 if (j->current_location.realtime_set)
593 return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
de190aef 594
cbdca852 595 return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset);
de7b95cd 596
cbdca852
LP
597 } else if (m->type == MATCH_OR_TERM) {
598 uint64_t np = 0;
599 Object *n;
600 Match *i;
de7b95cd 601
cbdca852 602 /* Find the earliest match */
de7b95cd 603
cbdca852
LP
604 LIST_FOREACH(matches, i, m->matches) {
605 uint64_t cp;
606
607 r = find_location_for_match(j, i, f, direction, NULL, &cp);
608 if (r < 0)
609 return r;
610 else if (r > 0) {
611 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
612 np = cp;
de190aef 613 }
cbdca852 614 }
de190aef 615
cbdca852
LP
616 if (np == 0)
617 return 0;
de7b95cd 618
cbdca852
LP
619 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
620 if (r < 0)
621 return r;
de7b95cd 622
cbdca852
LP
623 if (ret)
624 *ret = n;
625 if (offset)
626 *offset = np;
de190aef 627
cbdca852 628 return 1;
e892bd17 629
cbdca852
LP
630 } else {
631 Match *i;
632 uint64_t np = 0;
633
634 assert(m->type == MATCH_AND_TERM);
635
636 /* First jump to the last match, and then find the
637 * next one where all matches match */
638
639 if (!m->matches)
640 return 0;
641
642 LIST_FOREACH(matches, i, m->matches) {
643 uint64_t cp;
644
645 r = find_location_for_match(j, i, f, direction, NULL, &cp);
646 if (r <= 0)
4b067dc9
LP
647 return r;
648
bc302926 649 if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
cbdca852 650 np = cp;
de7b95cd
LP
651 }
652
cbdca852
LP
653 return next_for_match(j, m, f, np, direction, ret, offset);
654 }
655}
de190aef 656
cbdca852
LP
657static int find_location_with_matches(
658 sd_journal *j,
659 JournalFile *f,
660 direction_t direction,
661 Object **ret,
662 uint64_t *offset) {
663
664 int r;
665
666 assert(j);
667 assert(f);
668 assert(ret);
669 assert(offset);
670
671 if (!j->level0) {
672 /* No matches is simple */
673
674 if (j->current_location.type == LOCATION_HEAD)
f534928a 675 return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset);
cbdca852 676 if (j->current_location.type == LOCATION_TAIL)
f534928a 677 return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset);
cbdca852
LP
678 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
679 return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
680 if (j->current_location.monotonic_set) {
681 r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
682 if (r != -ENOENT)
683 return r;
de7b95cd 684 }
cbdca852
LP
685 if (j->current_location.realtime_set)
686 return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
de7b95cd 687
f534928a 688 return journal_file_next_entry(f, 0, direction, ret, offset);
cbdca852
LP
689 } else
690 return find_location_for_match(j, j->level0, f, direction, ret, offset);
691}
de7b95cd 692
cbdca852
LP
693static int next_with_matches(
694 sd_journal *j,
695 JournalFile *f,
696 direction_t direction,
697 Object **ret,
698 uint64_t *offset) {
699
cbdca852
LP
700 assert(j);
701 assert(f);
702 assert(ret);
703 assert(offset);
704
cbdca852
LP
705 /* No matches is easy. We simple advance the file
706 * pointer by one. */
707 if (!j->level0)
b29ddfcb 708 return journal_file_next_entry(f, f->current_offset, direction, ret, offset);
cbdca852
LP
709
710 /* If we have a match then we look for the next matching entry
49f43d5f 711 * with an offset at least one step larger */
b29ddfcb
MS
712 return next_for_match(j, j->level0, f,
713 direction == DIRECTION_DOWN ? f->current_offset + 1
714 : f->current_offset - 1,
715 direction, ret, offset);
de7b95cd
LP
716}
717
58439db4 718static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) {
de190aef 719 Object *c;
6e693b42 720 uint64_t cp, n_entries;
cbdca852 721 int r;
de190aef
LP
722
723 assert(j);
724 assert(f);
725
87011c25 726 if (f->last_direction == direction && f->current_offset > 0) {
668c965a
MS
727 /* If we hit EOF before, recheck if any new entries arrived. */
728 n_entries = le64toh(f->header->n_entries);
729 if (f->location_type == LOCATION_TAIL && n_entries == f->last_n_entries)
730 return 0;
731 f->last_n_entries = n_entries;
732
7943f422
MS
733 /* LOCATION_SEEK here means we did the work in a previous
734 * iteration and the current location already points to a
735 * candidate entry. */
487d3720
MS
736 if (f->location_type != LOCATION_SEEK) {
737 r = next_with_matches(j, f, direction, &c, &cp);
738 if (r <= 0)
739 return r;
466ccd92 740
487d3720
MS
741 journal_file_save_location(f, direction, c, cp);
742 }
de190aef 743 } else {
cbdca852 744 r = find_location_with_matches(j, f, direction, &c, &cp);
de190aef
LP
745 if (r <= 0)
746 return r;
487d3720
MS
747
748 journal_file_save_location(f, direction, c, cp);
de190aef
LP
749 }
750
bc302926 751 /* OK, we found the spot, now let's advance until an entry
cbdca852
LP
752 * that is actually different from what we were previously
753 * looking at. This is necessary to handle entries which exist
754 * in two (or more) journal files, and which shall all be
755 * suppressed but one. */
756
de190aef
LP
757 for (;;) {
758 bool found;
759
760 if (j->current_location.type == LOCATION_DISCRETE) {
761 int k;
762
487d3720 763 k = compare_with_location(f, &j->current_location);
1cdf7175
CH
764
765 found = direction == DIRECTION_DOWN ? k > 0 : k < 0;
de190aef
LP
766 } else
767 found = true;
768
487d3720 769 if (found)
de190aef 770 return 1;
de190aef
LP
771
772 r = next_with_matches(j, f, direction, &c, &cp);
773 if (r <= 0)
774 return r;
487d3720
MS
775
776 journal_file_save_location(f, direction, c, cp);
de190aef
LP
777 }
778}
779
e892bd17 780static int real_journal_next(sd_journal *j, direction_t direction) {
468b21de 781 JournalFile *f, *new_file = NULL;
cec736d2 782 Iterator i;
a002d44b 783 Object *o;
87d2c1ff
LP
784 int r;
785
1ae464e0
TA
786 assert_return(j, -EINVAL);
787 assert_return(!journal_pid_changed(j), -ECHILD);
87d2c1ff 788
c1f906bd 789 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
de190aef 790 bool found;
87d2c1ff 791
58439db4 792 r = next_beyond_location(j, f, direction);
e590af26 793 if (r < 0) {
da927ba9 794 log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path);
a9a245c1 795 remove_file_real(j, f);
e590af26 796 continue;
6573ef05
MS
797 } else if (r == 0) {
798 f->location_type = LOCATION_TAIL;
cec736d2 799 continue;
6573ef05 800 }
87d2c1ff 801
468b21de 802 if (!new_file)
de190aef
LP
803 found = true;
804 else {
805 int k;
806
d8ae66d7 807 k = journal_file_compare_locations(f, new_file);
de190aef 808
bc302926 809 found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
de190aef
LP
810 }
811
e499c999 812 if (found)
468b21de 813 new_file = f;
87d2c1ff
LP
814 }
815
468b21de 816 if (!new_file)
de190aef 817 return 0;
ae2cc8ef 818
e499c999 819 r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o);
468b21de
LP
820 if (r < 0)
821 return r;
822
1eb6332d 823 set_location(j, new_file, o);
ae2cc8ef 824
de190aef
LP
825 return 1;
826}
ae2cc8ef 827
a5344d2c 828_public_ int sd_journal_next(sd_journal *j) {
de190aef
LP
829 return real_journal_next(j, DIRECTION_DOWN);
830}
ae2cc8ef 831
a5344d2c 832_public_ int sd_journal_previous(sd_journal *j) {
de190aef
LP
833 return real_journal_next(j, DIRECTION_UP);
834}
ae2cc8ef 835
6f003b43 836static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
de190aef 837 int c = 0, r;
ae2cc8ef 838
1ae464e0
TA
839 assert_return(j, -EINVAL);
840 assert_return(!journal_pid_changed(j), -ECHILD);
de190aef 841
6f003b43
LP
842 if (skip == 0) {
843 /* If this is not a discrete skip, then at least
844 * resolve the current location */
845 if (j->current_location.type != LOCATION_DISCRETE)
846 return real_journal_next(j, direction);
847
848 return 0;
849 }
850
851 do {
852 r = real_journal_next(j, direction);
de190aef
LP
853 if (r < 0)
854 return r;
855
856 if (r == 0)
857 return c;
858
859 skip--;
860 c++;
6f003b43 861 } while (skip > 0);
87d2c1ff 862
de190aef 863 return c;
87d2c1ff
LP
864}
865
6f003b43
LP
866_public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
867 return real_journal_next_skip(j, DIRECTION_DOWN, skip);
868}
de190aef 869
6f003b43
LP
870_public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
871 return real_journal_next_skip(j, DIRECTION_UP, skip);
87d2c1ff
LP
872}
873
a5344d2c 874_public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
cec736d2 875 Object *o;
87d2c1ff 876 int r;
3fbf9cbb 877 char bid[33], sid[33];
87d2c1ff 878
1ae464e0
TA
879 assert_return(j, -EINVAL);
880 assert_return(!journal_pid_changed(j), -ECHILD);
881 assert_return(cursor, -EINVAL);
87d2c1ff 882
3fbf9cbb
LP
883 if (!j->current_file || j->current_file->current_offset <= 0)
884 return -EADDRNOTAVAIL;
87d2c1ff 885
de190aef 886 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
87d2c1ff
LP
887 if (r < 0)
888 return r;
889
3fbf9cbb
LP
890 sd_id128_to_string(j->current_file->header->seqnum_id, sid);
891 sd_id128_to_string(o->entry.boot_id, bid);
87d2c1ff 892
3fbf9cbb 893 if (asprintf(cursor,
507f22bd
ZJS
894 "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
895 sid, le64toh(o->entry.seqnum),
896 bid, le64toh(o->entry.monotonic),
897 le64toh(o->entry.realtime),
898 le64toh(o->entry.xor_hash)) < 0)
3fbf9cbb 899 return -ENOMEM;
87d2c1ff 900
6f47ad30 901 return 0;
87d2c1ff
LP
902}
903
a5344d2c 904_public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
a2a5291b 905 const char *word, *state;
de190aef 906 size_t l;
de190aef
LP
907 unsigned long long seqnum, monotonic, realtime, xor_hash;
908 bool
909 seqnum_id_set = false,
910 seqnum_set = false,
911 boot_id_set = false,
912 monotonic_set = false,
913 realtime_set = false,
914 xor_hash_set = false;
915 sd_id128_t seqnum_id, boot_id;
916
1ae464e0
TA
917 assert_return(j, -EINVAL);
918 assert_return(!journal_pid_changed(j), -ECHILD);
919 assert_return(!isempty(cursor), -EINVAL);
de190aef 920
a2a5291b 921 FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
de190aef
LP
922 char *item;
923 int k = 0;
924
a2a5291b 925 if (l < 2 || word[1] != '=')
de190aef
LP
926 return -EINVAL;
927
a2a5291b 928 item = strndup(word, l);
de190aef
LP
929 if (!item)
930 return -ENOMEM;
931
a2a5291b 932 switch (word[0]) {
de190aef
LP
933
934 case 's':
935 seqnum_id_set = true;
be3ea5ea 936 k = sd_id128_from_string(item+2, &seqnum_id);
de190aef
LP
937 break;
938
939 case 'i':
940 seqnum_set = true;
be3ea5ea 941 if (sscanf(item+2, "%llx", &seqnum) != 1)
de190aef
LP
942 k = -EINVAL;
943 break;
944
945 case 'b':
946 boot_id_set = true;
be3ea5ea 947 k = sd_id128_from_string(item+2, &boot_id);
de190aef
LP
948 break;
949
950 case 'm':
951 monotonic_set = true;
be3ea5ea 952 if (sscanf(item+2, "%llx", &monotonic) != 1)
de190aef
LP
953 k = -EINVAL;
954 break;
955
956 case 't':
957 realtime_set = true;
be3ea5ea 958 if (sscanf(item+2, "%llx", &realtime) != 1)
de190aef
LP
959 k = -EINVAL;
960 break;
961
962 case 'x':
963 xor_hash_set = true;
be3ea5ea 964 if (sscanf(item+2, "%llx", &xor_hash) != 1)
de190aef
LP
965 k = -EINVAL;
966 break;
967 }
968
969 free(item);
970
971 if (k < 0)
972 return k;
973 }
974
975 if ((!seqnum_set || !seqnum_id_set) &&
976 (!monotonic_set || !boot_id_set) &&
977 !realtime_set)
978 return -EINVAL;
979
980 reset_location(j);
981
a87247dd 982 j->current_location.type = LOCATION_SEEK;
de190aef
LP
983
984 if (realtime_set) {
985 j->current_location.realtime = (uint64_t) realtime;
986 j->current_location.realtime_set = true;
987 }
988
989 if (seqnum_set && seqnum_id_set) {
990 j->current_location.seqnum = (uint64_t) seqnum;
991 j->current_location.seqnum_id = seqnum_id;
992 j->current_location.seqnum_set = true;
993 }
994
995 if (monotonic_set && boot_id_set) {
996 j->current_location.monotonic = (uint64_t) monotonic;
997 j->current_location.boot_id = boot_id;
998 j->current_location.monotonic_set = true;
999 }
1000
1001 if (xor_hash_set) {
1002 j->current_location.xor_hash = (uint64_t) xor_hash;
1003 j->current_location.xor_hash_set = true;
1004 }
1005
1006 return 0;
1007}
1008
c6511e85
LP
1009_public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1010 int r;
a2a5291b 1011 const char *word, *state;
c6511e85
LP
1012 size_t l;
1013 Object *o;
1014
1ae464e0
TA
1015 assert_return(j, -EINVAL);
1016 assert_return(!journal_pid_changed(j), -ECHILD);
1017 assert_return(!isempty(cursor), -EINVAL);
c6511e85
LP
1018
1019 if (!j->current_file || j->current_file->current_offset <= 0)
1020 return -EADDRNOTAVAIL;
1021
1022 r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1023 if (r < 0)
1024 return r;
1025
a2a5291b 1026 FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
c6511e85
LP
1027 _cleanup_free_ char *item = NULL;
1028 sd_id128_t id;
1029 unsigned long long ll;
1030 int k = 0;
1031
a2a5291b 1032 if (l < 2 || word[1] != '=')
c6511e85
LP
1033 return -EINVAL;
1034
a2a5291b 1035 item = strndup(word, l);
c6511e85
LP
1036 if (!item)
1037 return -ENOMEM;
1038
a2a5291b 1039 switch (word[0]) {
c6511e85
LP
1040
1041 case 's':
1042 k = sd_id128_from_string(item+2, &id);
1043 if (k < 0)
1044 return k;
1045 if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1046 return 0;
1047 break;
1048
1049 case 'i':
1050 if (sscanf(item+2, "%llx", &ll) != 1)
1051 return -EINVAL;
1052 if (ll != le64toh(o->entry.seqnum))
1053 return 0;
1054 break;
1055
1056 case 'b':
1057 k = sd_id128_from_string(item+2, &id);
1058 if (k < 0)
1059 return k;
1060 if (!sd_id128_equal(id, o->entry.boot_id))
1061 return 0;
1062 break;
1063
1064 case 'm':
1065 if (sscanf(item+2, "%llx", &ll) != 1)
1066 return -EINVAL;
1067 if (ll != le64toh(o->entry.monotonic))
1068 return 0;
1069 break;
1070
1071 case 't':
1072 if (sscanf(item+2, "%llx", &ll) != 1)
1073 return -EINVAL;
1074 if (ll != le64toh(o->entry.realtime))
1075 return 0;
1076 break;
1077
1078 case 'x':
1079 if (sscanf(item+2, "%llx", &ll) != 1)
1080 return -EINVAL;
1081 if (ll != le64toh(o->entry.xor_hash))
1082 return 0;
1083 break;
1084 }
1085 }
1086
1087 return 1;
1088}
1089
1090
a5344d2c 1091_public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1ae464e0
TA
1092 assert_return(j, -EINVAL);
1093 assert_return(!journal_pid_changed(j), -ECHILD);
de190aef
LP
1094
1095 reset_location(j);
a87247dd 1096 j->current_location.type = LOCATION_SEEK;
de190aef
LP
1097 j->current_location.boot_id = boot_id;
1098 j->current_location.monotonic = usec;
1099 j->current_location.monotonic_set = true;
1100
1101 return 0;
1102}
1103
a5344d2c 1104_public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
1ae464e0
TA
1105 assert_return(j, -EINVAL);
1106 assert_return(!journal_pid_changed(j), -ECHILD);
de190aef
LP
1107
1108 reset_location(j);
a87247dd 1109 j->current_location.type = LOCATION_SEEK;
de190aef
LP
1110 j->current_location.realtime = usec;
1111 j->current_location.realtime_set = true;
1112
1113 return 0;
1114}
1115
a5344d2c 1116_public_ int sd_journal_seek_head(sd_journal *j) {
1ae464e0
TA
1117 assert_return(j, -EINVAL);
1118 assert_return(!journal_pid_changed(j), -ECHILD);
de190aef
LP
1119
1120 reset_location(j);
1121 j->current_location.type = LOCATION_HEAD;
1122
1123 return 0;
1124}
1125
a5344d2c 1126_public_ int sd_journal_seek_tail(sd_journal *j) {
1ae464e0
TA
1127 assert_return(j, -EINVAL);
1128 assert_return(!journal_pid_changed(j), -ECHILD);
de190aef
LP
1129
1130 reset_location(j);
1131 j->current_location.type = LOCATION_TAIL;
1132
1133 return 0;
87d2c1ff
LP
1134}
1135
85210bff
LP
1136static void check_network(sd_journal *j, int fd) {
1137 struct statfs sfs;
1138
1139 assert(j);
1140
1141 if (j->on_network)
1142 return;
1143
1144 if (fstatfs(fd, &sfs) < 0)
1145 return;
1146
1147 j->on_network =
c51cf056
ZJS
1148 F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) ||
1149 F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) ||
1150 F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) ||
1151 F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) ||
1152 F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC);
85210bff
LP
1153}
1154
a688baa8
ZJS
1155static bool file_has_type_prefix(const char *prefix, const char *filename) {
1156 const char *full, *tilded, *atted;
1157
63c372cb
LP
1158 full = strjoina(prefix, ".journal");
1159 tilded = strjoina(full, "~");
1160 atted = strjoina(prefix, "@");
a688baa8
ZJS
1161
1162 return streq(filename, full) ||
1163 streq(filename, tilded) ||
1164 startswith(filename, atted);
1165}
1166
1167static bool file_type_wanted(int flags, const char *filename) {
1168 if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1169 return false;
1170
1171 /* no flags set → every type is OK */
1172 if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1173 return true;
1174
1175 if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1176 return true;
1177
1178 if (flags & SD_JOURNAL_CURRENT_USER) {
1179 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1180
5ffa8c81 1181 xsprintf(prefix, "user-"UID_FMT, getuid());
a688baa8
ZJS
1182
1183 if (file_has_type_prefix(prefix, filename))
1184 return true;
1185 }
1186
1187 return false;
1188}
1189
5302ebe1 1190static int add_any_file(sd_journal *j, const char *path) {
39883f62 1191 JournalFile *f = NULL;
5302ebe1 1192 int r;
3fbf9cbb
LP
1193
1194 assert(j);
5302ebe1 1195 assert(path);
3fbf9cbb 1196
c1f906bd 1197 if (ordered_hashmap_get(j->files, path))
50f20cfd 1198 return 0;
50f20cfd 1199
9e8abdf0
LP
1200 if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1201 log_warning("Too many open journal files, not adding %s.", path);
1202 return set_put_error(j, -ETOOMANYREFS);
1203 }
1204
16e9f408 1205 r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
5302ebe1 1206 if (r < 0)
3fbf9cbb 1207 return r;
3fbf9cbb 1208
72f59706 1209 /* journal_file_dump(f); */
de190aef 1210
c1f906bd 1211 r = ordered_hashmap_put(j->files, f->path, f);
3fbf9cbb
LP
1212 if (r < 0) {
1213 journal_file_close(f);
1214 return r;
1215 }
1216
5ec76417 1217 log_debug("File %s added.", f->path);
a50d7d43 1218
85210bff
LP
1219 check_network(j, f->fd);
1220
a963990f
LP
1221 j->current_invalidate_counter ++;
1222
50f20cfd
LP
1223 return 0;
1224}
1225
5302ebe1
ZJS
1226static int add_file(sd_journal *j, const char *prefix, const char *filename) {
1227 _cleanup_free_ char *path = NULL;
1228 int r;
1229
1230 assert(j);
1231 assert(prefix);
1232 assert(filename);
1233
1234 if (j->no_new_files ||
1235 !file_type_wanted(j->flags, filename))
1236 return 0;
1237
1238 path = strjoin(prefix, "/", filename, NULL);
1239 if (!path)
1240 return -ENOMEM;
1241
1242 r = add_any_file(j, path);
1243 if (r == -ENOENT)
1244 return 0;
1245 return 0;
1246}
1247
a963990f 1248static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
a9a245c1 1249 _cleanup_free_ char *path;
50f20cfd
LP
1250 JournalFile *f;
1251
1252 assert(j);
1253 assert(prefix);
1254 assert(filename);
1255
b7def684 1256 path = strjoin(prefix, "/", filename, NULL);
a963990f 1257 if (!path)
50f20cfd
LP
1258 return -ENOMEM;
1259
c1f906bd 1260 f = ordered_hashmap_get(j->files, path);
50f20cfd
LP
1261 if (!f)
1262 return 0;
1263
a9a245c1
ZJS
1264 remove_file_real(j, f);
1265 return 0;
1266}
1267
1268static void remove_file_real(sd_journal *j, JournalFile *f) {
1269 assert(j);
1270 assert(f);
1271
c1f906bd 1272 ordered_hashmap_remove(j->files, f->path);
44a5fa34 1273
5ec76417 1274 log_debug("File %s removed.", f->path);
44a5fa34 1275
3c1668da
LP
1276 if (j->current_file == f) {
1277 j->current_file = NULL;
1278 j->current_field = 0;
1279 }
1280
1281 if (j->unique_file == f) {
360af4cf 1282 /* Jump to the next unique_file or NULL if that one was last */
c1f906bd 1283 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
3c1668da 1284 j->unique_offset = 0;
360af4cf
ZJS
1285 if (!j->unique_file)
1286 j->unique_file_lost = true;
3c1668da
LP
1287 }
1288
50f20cfd
LP
1289 journal_file_close(f);
1290
a963990f 1291 j->current_invalidate_counter ++;
3fbf9cbb
LP
1292}
1293
a963990f 1294static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
7fd1b19b 1295 _cleanup_free_ char *path = NULL;
3fbf9cbb 1296 int r;
7fd1b19b 1297 _cleanup_closedir_ DIR *d = NULL;
cf244689 1298 sd_id128_t id, mid;
a963990f 1299 Directory *m;
3fbf9cbb
LP
1300
1301 assert(j);
1302 assert(prefix);
a963990f 1303 assert(dirname);
3fbf9cbb 1304
d95b1fb3
ZJS
1305 log_debug("Considering %s/%s.", prefix, dirname);
1306
cf244689 1307 if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
a963990f 1308 (sd_id128_from_string(dirname, &id) < 0 ||
cf244689 1309 sd_id128_get_machine(&mid) < 0 ||
d95b1fb3 1310 !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
cf244689
LP
1311 return 0;
1312
b7def684 1313 path = strjoin(prefix, "/", dirname, NULL);
a963990f 1314 if (!path)
3fbf9cbb
LP
1315 return -ENOMEM;
1316
a963990f 1317 d = opendir(path);
3fbf9cbb 1318 if (!d) {
56f64d95 1319 log_debug_errno(errno, "Failed to open %s: %m", path);
3fbf9cbb
LP
1320 if (errno == ENOENT)
1321 return 0;
3fbf9cbb
LP
1322 return -errno;
1323 }
1324
a963990f
LP
1325 m = hashmap_get(j->directories_by_path, path);
1326 if (!m) {
1327 m = new0(Directory, 1);
a50d7d43 1328 if (!m)
a963990f 1329 return -ENOMEM;
a963990f
LP
1330
1331 m->is_root = false;
1332 m->path = path;
1333
1334 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
a963990f
LP
1335 free(m);
1336 return -ENOMEM;
1337 }
1338
a50d7d43 1339 path = NULL; /* avoid freeing in cleanup */
a963990f
LP
1340 j->current_invalidate_counter ++;
1341
5ec76417 1342 log_debug("Directory %s added.", m->path);
a963990f 1343
a50d7d43 1344 } else if (m->is_root)
a963990f 1345 return 0;
a963990f
LP
1346
1347 if (m->wd <= 0 && j->inotify_fd >= 0) {
1348
1349 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1350 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
5e6870ea 1351 IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
4a842cad 1352 IN_ONLYDIR);
a963990f
LP
1353
1354 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1355 inotify_rm_watch(j->inotify_fd, m->wd);
1356 }
1357
1358 for (;;) {
7d5e9c0f 1359 struct dirent *de;
a963990f 1360
bde1fdd7
FW
1361 errno = 0;
1362 de = readdir(d);
1363 if (!de && errno != 0) {
1364 r = -errno;
56f64d95 1365 log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
bde1fdd7
FW
1366 return r;
1367 }
1368 if (!de)
a963990f
LP
1369 break;
1370
de2c3907
LP
1371 if (dirent_is_file_with_suffix(de, ".journal") ||
1372 dirent_is_file_with_suffix(de, ".journal~")) {
a963990f 1373 r = add_file(j, m->path, de->d_name);
6fe391c5 1374 if (r < 0) {
c33b3297
MS
1375 log_debug_errno(r, "Failed to add file %s/%s: %m",
1376 m->path, de->d_name);
3ac251b8 1377 r = set_put_error(j, r);
6fe391c5
ZJS
1378 if (r < 0)
1379 return r;
1380 }
a963990f
LP
1381 }
1382 }
1383
85210bff
LP
1384 check_network(j, dirfd(d));
1385
a963990f
LP
1386 return 0;
1387}
1388
89739579 1389static int add_root_directory(sd_journal *j, const char *p) {
7fd1b19b 1390 _cleanup_closedir_ DIR *d = NULL;
a963990f
LP
1391 Directory *m;
1392 int r;
1393
1394 assert(j);
1395 assert(p);
1396
1397 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1398 !path_startswith(p, "/run"))
1399 return -EINVAL;
1400
89739579 1401 if (j->prefix)
63c372cb 1402 p = strjoina(j->prefix, p);
b6741478 1403
a963990f
LP
1404 d = opendir(p);
1405 if (!d)
1406 return -errno;
1407
1408 m = hashmap_get(j->directories_by_path, p);
1409 if (!m) {
1410 m = new0(Directory, 1);
a50d7d43 1411 if (!m)
a963990f 1412 return -ENOMEM;
a963990f
LP
1413
1414 m->is_root = true;
1415 m->path = strdup(p);
1416 if (!m->path) {
a963990f
LP
1417 free(m);
1418 return -ENOMEM;
1419 }
1420
1421 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
a963990f
LP
1422 free(m->path);
1423 free(m);
1424 return -ENOMEM;
1425 }
1426
1427 j->current_invalidate_counter ++;
1428
5ec76417 1429 log_debug("Root directory %s added.", m->path);
a963990f 1430
a50d7d43 1431 } else if (!m->is_root)
a963990f 1432 return 0;
50f20cfd 1433
a963990f
LP
1434 if (m->wd <= 0 && j->inotify_fd >= 0) {
1435
1436 m->wd = inotify_add_watch(j->inotify_fd, m->path,
1437 IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
4a842cad 1438 IN_ONLYDIR);
a963990f
LP
1439
1440 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
1441 inotify_rm_watch(j->inotify_fd, m->wd);
1442 }
50f20cfd 1443
5302ebe1
ZJS
1444 if (j->no_new_files)
1445 return 0;
1446
3fbf9cbb 1447 for (;;) {
7d5e9c0f 1448 struct dirent *de;
a963990f 1449 sd_id128_t id;
3fbf9cbb 1450
bde1fdd7
FW
1451 errno = 0;
1452 de = readdir(d);
1453 if (!de && errno != 0) {
1454 r = -errno;
56f64d95 1455 log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
bde1fdd7
FW
1456 return r;
1457 }
1458 if (!de)
3fbf9cbb
LP
1459 break;
1460
de2c3907
LP
1461 if (dirent_is_file_with_suffix(de, ".journal") ||
1462 dirent_is_file_with_suffix(de, ".journal~")) {
a963990f 1463 r = add_file(j, m->path, de->d_name);
6fe391c5 1464 if (r < 0) {
c33b3297
MS
1465 log_debug_errno(r, "Failed to add file %s/%s: %m",
1466 m->path, de->d_name);
3ac251b8 1467 r = set_put_error(j, r);
6fe391c5
ZJS
1468 if (r < 0)
1469 return r;
1470 }
6f5878a2 1471 } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
a963990f
LP
1472 sd_id128_from_string(de->d_name, &id) >= 0) {
1473
1474 r = add_directory(j, m->path, de->d_name);
1475 if (r < 0)
da927ba9 1476 log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
a963990f 1477 }
3fbf9cbb
LP
1478 }
1479
85210bff
LP
1480 check_network(j, dirfd(d));
1481
a963990f
LP
1482 return 0;
1483}
1484
1485static int remove_directory(sd_journal *j, Directory *d) {
1486 assert(j);
1487
1488 if (d->wd > 0) {
1489 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1490
1491 if (j->inotify_fd >= 0)
1492 inotify_rm_watch(j->inotify_fd, d->wd);
1493 }
1494
1495 hashmap_remove(j->directories_by_path, d->path);
1496
1497 if (d->is_root)
5ec76417 1498 log_debug("Root directory %s removed.", d->path);
a963990f 1499 else
5ec76417 1500 log_debug("Directory %s removed.", d->path);
a963990f
LP
1501
1502 free(d->path);
1503 free(d);
50f20cfd 1504
3fbf9cbb
LP
1505 return 0;
1506}
1507
89739579 1508static int add_search_paths(sd_journal *j) {
6fe391c5 1509 int r;
a963990f
LP
1510 const char search_paths[] =
1511 "/run/log/journal\0"
1512 "/var/log/journal\0";
1513 const char *p;
50f20cfd
LP
1514
1515 assert(j);
50f20cfd 1516
a963990f
LP
1517 /* We ignore most errors here, since the idea is to only open
1518 * what's actually accessible, and ignore the rest. */
50f20cfd 1519
6fe391c5 1520 NULSTR_FOREACH(p, search_paths) {
89739579 1521 r = add_root_directory(j, p);
3ac251b8
LP
1522 if (r < 0 && r != -ENOENT) {
1523 r = set_put_error(j, r);
1524 if (r < 0)
1525 return r;
1526 }
6fe391c5 1527 }
50f20cfd 1528
a963990f 1529 return 0;
50f20cfd
LP
1530}
1531
5302ebe1
ZJS
1532static int add_current_paths(sd_journal *j) {
1533 Iterator i;
1534 JournalFile *f;
1535
1536 assert(j);
1537 assert(j->no_new_files);
1538
1539 /* Simply adds all directories for files we have open as
1540 * "root" directories. We don't expect errors here, so we
1541 * treat them as fatal. */
1542
c1f906bd 1543 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
5302ebe1 1544 _cleanup_free_ char *dir;
e9174f29 1545 int r;
5302ebe1
ZJS
1546
1547 dir = dirname_malloc(f->path);
1548 if (!dir)
1549 return -ENOMEM;
1550
89739579 1551 r = add_root_directory(j, dir);
5302ebe1
ZJS
1552 if (r < 0) {
1553 set_put_error(j, r);
1554 return r;
1555 }
1556 }
1557
1558 return 0;
1559}
1560
1561
a963990f 1562static int allocate_inotify(sd_journal *j) {
50f20cfd 1563 assert(j);
50f20cfd 1564
a963990f
LP
1565 if (j->inotify_fd < 0) {
1566 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1567 if (j->inotify_fd < 0)
1568 return -errno;
1569 }
50f20cfd 1570
a963990f 1571 if (!j->directories_by_wd) {
d5099efc 1572 j->directories_by_wd = hashmap_new(NULL);
a963990f
LP
1573 if (!j->directories_by_wd)
1574 return -ENOMEM;
50f20cfd 1575 }
a963990f
LP
1576
1577 return 0;
50f20cfd
LP
1578}
1579
7827b1a1 1580static sd_journal *journal_new(int flags, const char *path) {
a963990f 1581 sd_journal *j;
50f20cfd 1582
a963990f
LP
1583 j = new0(sd_journal, 1);
1584 if (!j)
1585 return NULL;
50f20cfd 1586
a65f06bb 1587 j->original_pid = getpid();
a963990f
LP
1588 j->inotify_fd = -1;
1589 j->flags = flags;
93b73b06 1590 j->data_threshold = DEFAULT_DATA_THRESHOLD;
50f20cfd 1591
7827b1a1
LP
1592 if (path) {
1593 j->path = strdup(path);
6180fc61
ZJS
1594 if (!j->path)
1595 goto fail;
7827b1a1
LP
1596 }
1597
c1f906bd 1598 j->files = ordered_hashmap_new(&string_hash_ops);
d5099efc 1599 j->directories_by_path = hashmap_new(&string_hash_ops);
84168d80 1600 j->mmap = mmap_cache_new();
3ac251b8 1601 if (!j->files || !j->directories_by_path || !j->mmap)
6180fc61 1602 goto fail;
16e9f408 1603
a963990f 1604 return j;
6180fc61
ZJS
1605
1606fail:
1607 sd_journal_close(j);
1608 return NULL;
50f20cfd
LP
1609}
1610
a5344d2c 1611_public_ int sd_journal_open(sd_journal **ret, int flags) {
87d2c1ff 1612 sd_journal *j;
3fbf9cbb 1613 int r;
87d2c1ff 1614
1ae464e0 1615 assert_return(ret, -EINVAL);
b6741478 1616 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL);
87d2c1ff 1617
7827b1a1 1618 j = journal_new(flags, NULL);
87d2c1ff
LP
1619 if (!j)
1620 return -ENOMEM;
1621
89739579 1622 r = add_search_paths(j);
a963990f 1623 if (r < 0)
50f20cfd 1624 goto fail;
50f20cfd 1625
a963990f
LP
1626 *ret = j;
1627 return 0;
cf244689 1628
a963990f
LP
1629fail:
1630 sd_journal_close(j);
87d2c1ff 1631
a963990f
LP
1632 return r;
1633}
50f20cfd 1634
b6741478
LP
1635_public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
1636 _cleanup_free_ char *root = NULL, *class = NULL;
1637 sd_journal *j;
1638 char *p;
1639 int r;
1640
1641 assert_return(machine, -EINVAL);
1642 assert_return(ret, -EINVAL);
1643 assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL);
affcf189 1644 assert_return(machine_name_is_valid(machine), -EINVAL);
b6741478 1645
63c372cb 1646 p = strjoina("/run/systemd/machines/", machine);
b6741478
LP
1647 r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL);
1648 if (r == -ENOENT)
1649 return -EHOSTDOWN;
1650 if (r < 0)
1651 return r;
1652 if (!root)
1653 return -ENODATA;
1654
1655 if (!streq_ptr(class, "container"))
1656 return -EIO;
1657
1658 j = journal_new(flags, NULL);
1659 if (!j)
1660 return -ENOMEM;
1661
89739579
LP
1662 j->prefix = root;
1663 root = NULL;
1664
1665 r = add_search_paths(j);
b6741478
LP
1666 if (r < 0)
1667 goto fail;
1668
1669 *ret = j;
1670 return 0;
1671
1672fail:
1673 sd_journal_close(j);
1674 return r;
1675}
1676
a963990f
LP
1677_public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1678 sd_journal *j;
1679 int r;
87d2c1ff 1680
1ae464e0
TA
1681 assert_return(ret, -EINVAL);
1682 assert_return(path, -EINVAL);
1683 assert_return(flags == 0, -EINVAL);
87d2c1ff 1684
7827b1a1 1685 j = journal_new(flags, path);
a963990f
LP
1686 if (!j)
1687 return -ENOMEM;
3fbf9cbb 1688
89739579 1689 r = add_root_directory(j, path);
6fe391c5 1690 if (r < 0) {
3ac251b8 1691 set_put_error(j, r);
a963990f 1692 goto fail;
6fe391c5 1693 }
87d2c1ff
LP
1694
1695 *ret = j;
1696 return 0;
1697
1698fail:
1699 sd_journal_close(j);
1700
1701 return r;
a963990f 1702}
87d2c1ff 1703
5302ebe1
ZJS
1704_public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
1705 sd_journal *j;
1706 const char **path;
1707 int r;
1708
1ae464e0
TA
1709 assert_return(ret, -EINVAL);
1710 assert_return(flags == 0, -EINVAL);
5302ebe1
ZJS
1711
1712 j = journal_new(flags, NULL);
1713 if (!j)
1714 return -ENOMEM;
1715
1716 STRV_FOREACH(path, paths) {
1717 r = add_any_file(j, *path);
1718 if (r < 0) {
da927ba9 1719 log_error_errno(r, "Failed to open %s: %m", *path);
5302ebe1
ZJS
1720 goto fail;
1721 }
1722 }
1723
1724 j->no_new_files = true;
1725
1726 *ret = j;
1727 return 0;
1728
1729fail:
1730 sd_journal_close(j);
1731
1732 return r;
1733}
1734
a5344d2c 1735_public_ void sd_journal_close(sd_journal *j) {
a963990f
LP
1736 Directory *d;
1737 JournalFile *f;
1738
a5344d2c
LP
1739 if (!j)
1740 return;
87d2c1ff 1741
54b1da83
LP
1742 sd_journal_flush_matches(j);
1743
c1f906bd 1744 while ((f = ordered_hashmap_steal_first(j->files)))
a963990f 1745 journal_file_close(f);
50f20cfd 1746
c1f906bd 1747 ordered_hashmap_free(j->files);
260a2be4 1748
a963990f
LP
1749 while ((d = hashmap_first(j->directories_by_path)))
1750 remove_directory(j, d);
260a2be4 1751
a963990f
LP
1752 while ((d = hashmap_first(j->directories_by_wd)))
1753 remove_directory(j, d);
87d2c1ff 1754
a963990f
LP
1755 hashmap_free(j->directories_by_path);
1756 hashmap_free(j->directories_by_wd);
1cc101f1 1757
03e334a1 1758 safe_close(j->inotify_fd);
50f20cfd 1759
bf807d4d
LP
1760 if (j->mmap) {
1761 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
16e9f408 1762 mmap_cache_unref(j->mmap);
bf807d4d 1763 }
16e9f408 1764
7827b1a1 1765 free(j->path);
89739579 1766 free(j->prefix);
3c1668da 1767 free(j->unique_field);
6fe391c5 1768 set_free(j->errors);
87d2c1ff
LP
1769 free(j);
1770}
3fbf9cbb 1771
a5344d2c 1772_public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
3fbf9cbb
LP
1773 Object *o;
1774 JournalFile *f;
1775 int r;
1776
1ae464e0
TA
1777 assert_return(j, -EINVAL);
1778 assert_return(!journal_pid_changed(j), -ECHILD);
1779 assert_return(ret, -EINVAL);
3fbf9cbb
LP
1780
1781 f = j->current_file;
1782 if (!f)
de190aef 1783 return -EADDRNOTAVAIL;
3fbf9cbb
LP
1784
1785 if (f->current_offset <= 0)
de190aef 1786 return -EADDRNOTAVAIL;
3fbf9cbb 1787
de190aef 1788 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
3fbf9cbb
LP
1789 if (r < 0)
1790 return r;
1791
1792 *ret = le64toh(o->entry.realtime);
de190aef 1793 return 0;
3fbf9cbb
LP
1794}
1795
a5344d2c 1796_public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
3fbf9cbb
LP
1797 Object *o;
1798 JournalFile *f;
1799 int r;
1800 sd_id128_t id;
1801
1ae464e0
TA
1802 assert_return(j, -EINVAL);
1803 assert_return(!journal_pid_changed(j), -ECHILD);
3fbf9cbb
LP
1804
1805 f = j->current_file;
1806 if (!f)
de190aef 1807 return -EADDRNOTAVAIL;
3fbf9cbb
LP
1808
1809 if (f->current_offset <= 0)
de190aef 1810 return -EADDRNOTAVAIL;
3fbf9cbb 1811
de190aef 1812 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
3fbf9cbb
LP
1813 if (r < 0)
1814 return r;
1815
de190aef
LP
1816 if (ret_boot_id)
1817 *ret_boot_id = o->entry.boot_id;
1818 else {
1819 r = sd_id128_get_boot(&id);
1820 if (r < 0)
1821 return r;
3fbf9cbb 1822
de190aef 1823 if (!sd_id128_equal(id, o->entry.boot_id))
df50185b 1824 return -ESTALE;
de190aef 1825 }
3fbf9cbb 1826
14a65d65
LP
1827 if (ret)
1828 *ret = le64toh(o->entry.monotonic);
1829
de190aef 1830 return 0;
3fbf9cbb
LP
1831}
1832
362a3f81
LP
1833static bool field_is_valid(const char *field) {
1834 const char *p;
1835
1836 assert(field);
1837
1838 if (isempty(field))
1839 return false;
1840
1841 if (startswith(field, "__"))
1842 return false;
1843
1844 for (p = field; *p; p++) {
1845
1846 if (*p == '_')
1847 continue;
1848
1849 if (*p >= 'A' && *p <= 'Z')
1850 continue;
1851
1852 if (*p >= '0' && *p <= '9')
1853 continue;
1854
1855 return false;
1856 }
1857
1858 return true;
1859}
1860
a5344d2c 1861_public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
3fbf9cbb
LP
1862 JournalFile *f;
1863 uint64_t i, n;
1864 size_t field_length;
1865 int r;
1866 Object *o;
1867
1ae464e0
TA
1868 assert_return(j, -EINVAL);
1869 assert_return(!journal_pid_changed(j), -ECHILD);
1870 assert_return(field, -EINVAL);
1871 assert_return(data, -EINVAL);
1872 assert_return(size, -EINVAL);
1873 assert_return(field_is_valid(field), -EINVAL);
3fbf9cbb
LP
1874
1875 f = j->current_file;
1876 if (!f)
de190aef 1877 return -EADDRNOTAVAIL;
3fbf9cbb
LP
1878
1879 if (f->current_offset <= 0)
de190aef 1880 return -EADDRNOTAVAIL;
3fbf9cbb 1881
de190aef 1882 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
3fbf9cbb
LP
1883 if (r < 0)
1884 return r;
1885
1886 field_length = strlen(field);
1887
1888 n = journal_file_entry_n_items(o);
1889 for (i = 0; i < n; i++) {
4fd052ae
FC
1890 uint64_t p, l;
1891 le64_t le_hash;
3fbf9cbb 1892 size_t t;
1ec7120e 1893 int compression;
3fbf9cbb
LP
1894
1895 p = le64toh(o->entry.items[i].object_offset);
807e17f0 1896 le_hash = o->entry.items[i].hash;
de190aef 1897 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
3fbf9cbb
LP
1898 if (r < 0)
1899 return r;
1900
de190aef 1901 if (le_hash != o->data.hash)
de7b95cd
LP
1902 return -EBADMSG;
1903
3fbf9cbb
LP
1904 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1905
1ec7120e 1906 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
3b1a55e1
ZJS
1907 if (compression) {
1908#if defined(HAVE_XZ) || defined(HAVE_LZ4)
1909 if (decompress_startswith(compression,
1910 o->data.payload, l,
1911 &f->compress_buffer, &f->compress_buffer_size,
1912 field, field_length, '=')) {
1913
fa1c4b51 1914 size_t rsize;
3b1a55e1
ZJS
1915
1916 r = decompress_blob(compression,
1917 o->data.payload, l,
1918 &f->compress_buffer, &f->compress_buffer_size, &rsize,
1919 j->data_threshold);
1920 if (r < 0)
1921 return r;
807e17f0 1922
3b1a55e1
ZJS
1923 *data = f->compress_buffer;
1924 *size = (size_t) rsize;
807e17f0 1925
3b1a55e1
ZJS
1926 return 0;
1927 }
1928#else
1929 return -EPROTONOSUPPORT;
1930#endif
807e17f0
LP
1931 } else if (l >= field_length+1 &&
1932 memcmp(o->data.payload, field, field_length) == 0 &&
1933 o->data.payload[field_length] == '=') {
3fbf9cbb 1934
161e54f8 1935 t = (size_t) l;
3fbf9cbb 1936
161e54f8
LP
1937 if ((uint64_t) t != l)
1938 return -E2BIG;
3fbf9cbb 1939
161e54f8
LP
1940 *data = o->data.payload;
1941 *size = t;
3fbf9cbb 1942
99613ec5 1943 return 0;
161e54f8 1944 }
3fbf9cbb 1945
de190aef 1946 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
161e54f8
LP
1947 if (r < 0)
1948 return r;
3fbf9cbb
LP
1949 }
1950
de190aef 1951 return -ENOENT;
3fbf9cbb
LP
1952}
1953
93b73b06 1954static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
3c1668da
LP
1955 size_t t;
1956 uint64_t l;
3b1a55e1 1957 int compression;
3c1668da
LP
1958
1959 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1960 t = (size_t) l;
1961
1962 /* We can't read objects larger than 4G on a 32bit machine */
1963 if ((uint64_t) t != l)
1964 return -E2BIG;
1965
1ec7120e
ZJS
1966 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
1967 if (compression) {
3b1a55e1 1968#if defined(HAVE_XZ) || defined(HAVE_LZ4)
fa1c4b51 1969 size_t rsize;
3b1a55e1 1970 int r;
3c1668da 1971
1ec7120e
ZJS
1972 r = decompress_blob(compression,
1973 o->data.payload, l, &f->compress_buffer,
1974 &f->compress_buffer_size, &rsize, j->data_threshold);
1975 if (r < 0)
1976 return r;
3c1668da
LP
1977
1978 *data = f->compress_buffer;
1979 *size = (size_t) rsize;
3b1a55e1
ZJS
1980#else
1981 return -EPROTONOSUPPORT;
1982#endif
3c1668da
LP
1983 } else {
1984 *data = o->data.payload;
1985 *size = t;
1986 }
1987
1988 return 0;
1989}
1990
a5344d2c 1991_public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
3fbf9cbb 1992 JournalFile *f;
3c1668da 1993 uint64_t p, n;
4fd052ae 1994 le64_t le_hash;
3fbf9cbb
LP
1995 int r;
1996 Object *o;
1997
1ae464e0
TA
1998 assert_return(j, -EINVAL);
1999 assert_return(!journal_pid_changed(j), -ECHILD);
2000 assert_return(data, -EINVAL);
2001 assert_return(size, -EINVAL);
3fbf9cbb
LP
2002
2003 f = j->current_file;
2004 if (!f)
de190aef 2005 return -EADDRNOTAVAIL;
3fbf9cbb
LP
2006
2007 if (f->current_offset <= 0)
de190aef 2008 return -EADDRNOTAVAIL;
3fbf9cbb 2009
de190aef 2010 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
3fbf9cbb
LP
2011 if (r < 0)
2012 return r;
2013
2014 n = journal_file_entry_n_items(o);
7210bfb3 2015 if (j->current_field >= n)
3fbf9cbb
LP
2016 return 0;
2017
7210bfb3 2018 p = le64toh(o->entry.items[j->current_field].object_offset);
de190aef
LP
2019 le_hash = o->entry.items[j->current_field].hash;
2020 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
3fbf9cbb
LP
2021 if (r < 0)
2022 return r;
2023
de190aef 2024 if (le_hash != o->data.hash)
de7b95cd
LP
2025 return -EBADMSG;
2026
93b73b06 2027 r = return_data(j, f, o, data, size);
3c1668da
LP
2028 if (r < 0)
2029 return r;
3fbf9cbb 2030
7210bfb3 2031 j->current_field ++;
3fbf9cbb
LP
2032
2033 return 1;
2034}
c2373f84 2035
a5344d2c
LP
2036_public_ void sd_journal_restart_data(sd_journal *j) {
2037 if (!j)
2038 return;
8725d60a
LP
2039
2040 j->current_field = 0;
c2373f84 2041}
50f20cfd 2042
a5344d2c 2043_public_ int sd_journal_get_fd(sd_journal *j) {
a963990f
LP
2044 int r;
2045
1ae464e0
TA
2046 assert_return(j, -EINVAL);
2047 assert_return(!journal_pid_changed(j), -ECHILD);
50f20cfd 2048
a963990f
LP
2049 if (j->inotify_fd >= 0)
2050 return j->inotify_fd;
2051
2052 r = allocate_inotify(j);
2053 if (r < 0)
2054 return r;
2055
2056 /* Iterate through all dirs again, to add them to the
2057 * inotify */
5302ebe1
ZJS
2058 if (j->no_new_files)
2059 r = add_current_paths(j);
2060 else if (j->path)
89739579 2061 r = add_root_directory(j, j->path);
7827b1a1 2062 else
89739579 2063 r = add_search_paths(j);
a963990f
LP
2064 if (r < 0)
2065 return r;
2066
50f20cfd
LP
2067 return j->inotify_fd;
2068}
2069
ee531d94
LP
2070_public_ int sd_journal_get_events(sd_journal *j) {
2071 int fd;
2072
1ae464e0
TA
2073 assert_return(j, -EINVAL);
2074 assert_return(!journal_pid_changed(j), -ECHILD);
ee531d94
LP
2075
2076 fd = sd_journal_get_fd(j);
2077 if (fd < 0)
2078 return fd;
2079
2080 return POLLIN;
2081}
2082
39c155ea
LP
2083_public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2084 int fd;
2085
1ae464e0
TA
2086 assert_return(j, -EINVAL);
2087 assert_return(!journal_pid_changed(j), -ECHILD);
2088 assert_return(timeout_usec, -EINVAL);
39c155ea
LP
2089
2090 fd = sd_journal_get_fd(j);
2091 if (fd < 0)
2092 return fd;
2093
2094 if (!j->on_network) {
2095 *timeout_usec = (uint64_t) -1;
2096 return 0;
2097 }
2098
2099 /* If we are on the network we need to regularly check for
2100 * changes manually */
2101
2102 *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2103 return 1;
2104}
2105
50f20cfd 2106static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
a963990f 2107 Directory *d;
50f20cfd
LP
2108 int r;
2109
2110 assert(j);
2111 assert(e);
2112
2113 /* Is this a subdirectory we watch? */
a963990f
LP
2114 d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2115 if (d) {
2116 sd_id128_t id;
50f20cfd 2117
de2c3907
LP
2118 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2119 (endswith(e->name, ".journal") ||
2120 endswith(e->name, ".journal~"))) {
50f20cfd
LP
2121
2122 /* Event for a journal file */
2123
2124 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
a963990f 2125 r = add_file(j, d->path, e->name);
6fe391c5 2126 if (r < 0) {
c33b3297
MS
2127 log_debug_errno(r, "Failed to add file %s/%s: %m",
2128 d->path, e->name);
3ac251b8 2129 set_put_error(j, r);
6fe391c5 2130 }
a963990f 2131
5e6870ea 2132 } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
50f20cfd 2133
a963990f 2134 r = remove_file(j, d->path, e->name);
50f20cfd 2135 if (r < 0)
da927ba9 2136 log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
50f20cfd
LP
2137 }
2138
a963990f 2139 } else if (!d->is_root && e->len == 0) {
50f20cfd 2140
a963990f 2141 /* Event for a subdirectory */
50f20cfd 2142
a963990f
LP
2143 if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
2144 r = remove_directory(j, d);
50f20cfd 2145 if (r < 0)
da927ba9 2146 log_debug_errno(r, "Failed to remove directory %s: %m", d->path);
50f20cfd
LP
2147 }
2148
50f20cfd 2149
a963990f 2150 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
50f20cfd 2151
a963990f 2152 /* Event for root directory */
50f20cfd 2153
a963990f
LP
2154 if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2155 r = add_directory(j, d->path, e->name);
50f20cfd 2156 if (r < 0)
da927ba9 2157 log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
50f20cfd
LP
2158 }
2159 }
2160
2161 return;
2162 }
2163
2164 if (e->mask & IN_IGNORED)
2165 return;
2166
2167 log_warning("Unknown inotify event.");
2168}
2169
a963990f
LP
2170static int determine_change(sd_journal *j) {
2171 bool b;
2172
2173 assert(j);
2174
2175 b = j->current_invalidate_counter != j->last_invalidate_counter;
2176 j->last_invalidate_counter = j->current_invalidate_counter;
2177
2178 return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2179}
2180
a5344d2c 2181_public_ int sd_journal_process(sd_journal *j) {
a963990f 2182 bool got_something = false;
50f20cfd 2183
1ae464e0
TA
2184 assert_return(j, -EINVAL);
2185 assert_return(!journal_pid_changed(j), -ECHILD);
50f20cfd 2186
39c155ea
LP
2187 j->last_process_usec = now(CLOCK_MONOTONIC);
2188
50f20cfd 2189 for (;;) {
0254e944 2190 union inotify_event_buffer buffer;
50f20cfd
LP
2191 struct inotify_event *e;
2192 ssize_t l;
2193
0254e944 2194 l = read(j->inotify_fd, &buffer, sizeof(buffer));
50f20cfd 2195 if (l < 0) {
a963990f
LP
2196 if (errno == EAGAIN || errno == EINTR)
2197 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
50f20cfd
LP
2198
2199 return -errno;
2200 }
2201
a963990f
LP
2202 got_something = true;
2203
f7c1ad4f 2204 FOREACH_INOTIFY_EVENT(e, buffer, l)
50f20cfd 2205 process_inotify_event(j, e);
50f20cfd
LP
2206 }
2207}
6ad1d1c3 2208
e02d1cf7 2209_public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
a963990f 2210 int r;
39c155ea 2211 uint64_t t;
e02d1cf7 2212
1ae464e0
TA
2213 assert_return(j, -EINVAL);
2214 assert_return(!journal_pid_changed(j), -ECHILD);
e02d1cf7 2215
a963990f
LP
2216 if (j->inotify_fd < 0) {
2217
2218 /* This is the first invocation, hence create the
2219 * inotify watch */
2220 r = sd_journal_get_fd(j);
2221 if (r < 0)
2222 return r;
2223
2224 /* The journal might have changed since the context
2225 * object was created and we weren't watching before,
2226 * hence don't wait for anything, and return
2227 * immediately. */
2228 return determine_change(j);
2229 }
2230
39c155ea
LP
2231 r = sd_journal_get_timeout(j, &t);
2232 if (r < 0)
2233 return r;
2234
2235 if (t != (uint64_t) -1) {
2236 usec_t n;
2237
2238 n = now(CLOCK_MONOTONIC);
2239 t = t > n ? t - n : 0;
85210bff 2240
39c155ea
LP
2241 if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
2242 timeout_usec = t;
85210bff
LP
2243 }
2244
a963990f
LP
2245 do {
2246 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2247 } while (r == -EINTR);
e02d1cf7
LP
2248
2249 if (r < 0)
2250 return r;
2251
a963990f 2252 return sd_journal_process(j);
e02d1cf7
LP
2253}
2254
08984293
LP
2255_public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2256 Iterator i;
2257 JournalFile *f;
2258 bool first = true;
581483bf 2259 uint64_t fmin = 0, tmax = 0;
08984293
LP
2260 int r;
2261
1ae464e0
TA
2262 assert_return(j, -EINVAL);
2263 assert_return(!journal_pid_changed(j), -ECHILD);
2264 assert_return(from || to, -EINVAL);
2265 assert_return(from != to, -EINVAL);
08984293 2266
c1f906bd 2267 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
08984293
LP
2268 usec_t fr, t;
2269
2270 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
9f8d2983
LP
2271 if (r == -ENOENT)
2272 continue;
08984293
LP
2273 if (r < 0)
2274 return r;
2275 if (r == 0)
2276 continue;
2277
2278 if (first) {
581483bf
LP
2279 fmin = fr;
2280 tmax = t;
08984293
LP
2281 first = false;
2282 } else {
581483bf
LP
2283 fmin = MIN(fr, fmin);
2284 tmax = MAX(t, tmax);
08984293
LP
2285 }
2286 }
2287
581483bf
LP
2288 if (from)
2289 *from = fmin;
2290 if (to)
2291 *to = tmax;
2292
08984293
LP
2293 return first ? 0 : 1;
2294}
2295
2296_public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2297 Iterator i;
2298 JournalFile *f;
1651e2c6 2299 bool found = false;
08984293
LP
2300 int r;
2301
1ae464e0
TA
2302 assert_return(j, -EINVAL);
2303 assert_return(!journal_pid_changed(j), -ECHILD);
2304 assert_return(from || to, -EINVAL);
2305 assert_return(from != to, -EINVAL);
08984293 2306
c1f906bd 2307 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
08984293
LP
2308 usec_t fr, t;
2309
2310 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
9f8d2983
LP
2311 if (r == -ENOENT)
2312 continue;
08984293
LP
2313 if (r < 0)
2314 return r;
2315 if (r == 0)
2316 continue;
2317
1651e2c6 2318 if (found) {
08984293 2319 if (from)
1651e2c6 2320 *from = MIN(fr, *from);
08984293 2321 if (to)
1651e2c6 2322 *to = MAX(t, *to);
08984293
LP
2323 } else {
2324 if (from)
1651e2c6 2325 *from = fr;
08984293 2326 if (to)
1651e2c6
ZJS
2327 *to = t;
2328 found = true;
08984293
LP
2329 }
2330 }
2331
1651e2c6 2332 return found;
08984293
LP
2333}
2334
dca6219e
LP
2335void journal_print_header(sd_journal *j) {
2336 Iterator i;
2337 JournalFile *f;
2338 bool newline = false;
2339
2340 assert(j);
2341
c1f906bd 2342 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
dca6219e
LP
2343 if (newline)
2344 putchar('\n');
2345 else
2346 newline = true;
2347
2348 journal_file_print_header(f);
2349 }
2350}
08984293 2351
a1a03e30
LP
2352_public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2353 Iterator i;
2354 JournalFile *f;
2355 uint64_t sum = 0;
2356
1ae464e0
TA
2357 assert_return(j, -EINVAL);
2358 assert_return(!journal_pid_changed(j), -ECHILD);
2359 assert_return(bytes, -EINVAL);
a1a03e30 2360
c1f906bd 2361 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
a1a03e30
LP
2362 struct stat st;
2363
2364 if (fstat(f->fd, &st) < 0)
2365 return -errno;
2366
2367 sum += (uint64_t) st.st_blocks * 512ULL;
2368 }
2369
2370 *bytes = sum;
2371 return 0;
2372}
2373
3c1668da
LP
2374_public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2375 char *f;
2376
1ae464e0
TA
2377 assert_return(j, -EINVAL);
2378 assert_return(!journal_pid_changed(j), -ECHILD);
2379 assert_return(!isempty(field), -EINVAL);
2380 assert_return(field_is_valid(field), -EINVAL);
3c1668da
LP
2381
2382 f = strdup(field);
2383 if (!f)
2384 return -ENOMEM;
2385
2386 free(j->unique_field);
2387 j->unique_field = f;
2388 j->unique_file = NULL;
2389 j->unique_offset = 0;
360af4cf 2390 j->unique_file_lost = false;
3c1668da
LP
2391
2392 return 0;
2393}
2394
2395_public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
3c1668da 2396 size_t k;
19a2bd80 2397
1ae464e0
TA
2398 assert_return(j, -EINVAL);
2399 assert_return(!journal_pid_changed(j), -ECHILD);
2400 assert_return(data, -EINVAL);
2401 assert_return(l, -EINVAL);
2402 assert_return(j->unique_field, -EINVAL);
19a2bd80 2403
3c1668da 2404 k = strlen(j->unique_field);
19a2bd80 2405
3c1668da 2406 if (!j->unique_file) {
360af4cf
ZJS
2407 if (j->unique_file_lost)
2408 return 0;
2409
c1f906bd 2410 j->unique_file = ordered_hashmap_first(j->files);
3c1668da
LP
2411 if (!j->unique_file)
2412 return 0;
360af4cf 2413
3c1668da
LP
2414 j->unique_offset = 0;
2415 }
19a2bd80 2416
3c1668da
LP
2417 for (;;) {
2418 JournalFile *of;
2419 Iterator i;
ae97089d 2420 Object *o;
3c1668da
LP
2421 const void *odata;
2422 size_t ol;
2423 bool found;
ae97089d 2424 int r;
3c1668da 2425
bdc02927 2426 /* Proceed to next data object in the field's linked list */
3c1668da
LP
2427 if (j->unique_offset == 0) {
2428 r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2429 if (r < 0)
2430 return r;
2431
2432 j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2433 } else {
2434 r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2435 if (r < 0)
2436 return r;
2437
2438 j->unique_offset = le64toh(o->data.next_field_offset);
2439 }
2440
2441 /* We reached the end of the list? Then start again, with the next file */
2442 if (j->unique_offset == 0) {
c1f906bd 2443 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
360af4cf 2444 if (!j->unique_file)
3c1668da
LP
2445 return 0;
2446
3c1668da
LP
2447 continue;
2448 }
2449
d05089d8
MS
2450 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2451 * instead, so that we can look at this data object at the same
3c1668da 2452 * time as one on another file */
d05089d8 2453 r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o);
3c1668da
LP
2454 if (r < 0)
2455 return r;
2456
2457 /* Let's do the type check by hand, since we used 0 context above. */
ae97089d 2458 if (o->object.type != OBJECT_DATA) {
36202fd2 2459 log_debug("%s:offset " OFSfmt ": object has type %d, expected %d",
ae97089d
ZJS
2460 j->unique_file->path, j->unique_offset,
2461 o->object.type, OBJECT_DATA);
3c1668da 2462 return -EBADMSG;
ae97089d
ZJS
2463 }
2464
93b73b06 2465 r = return_data(j, j->unique_file, o, &odata, &ol);
3c1668da
LP
2466 if (r < 0)
2467 return r;
2468
0f99f74a
ZJS
2469 /* Check if we have at least the field name and "=". */
2470 if (ol <= k) {
2471 log_debug("%s:offset " OFSfmt ": object has size %zu, expected at least %zu",
2472 j->unique_file->path, j->unique_offset,
2473 ol, k + 1);
2474 return -EBADMSG;
2475 }
2476
2477 if (memcmp(odata, j->unique_field, k) || ((const char*) odata)[k] != '=') {
2478 log_debug("%s:offset " OFSfmt ": object does not start with \"%s=\"",
2479 j->unique_file->path, j->unique_offset,
2480 j->unique_field);
2481 return -EBADMSG;
2482 }
2483
3c1668da
LP
2484 /* OK, now let's see if we already returned this data
2485 * object by checking if it exists in the earlier
2486 * traversed files. */
2487 found = false;
c1f906bd 2488 ORDERED_HASHMAP_FOREACH(of, j->files, i) {
3c1668da
LP
2489 Object *oo;
2490 uint64_t op;
2491
2492 if (of == j->unique_file)
2493 break;
2494
2495 /* Skip this file it didn't have any fields
2496 * indexed */
2497 if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) &&
2498 le64toh(of->header->n_fields) <= 0)
2499 continue;
2500
2501 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op);
2502 if (r < 0)
2503 return r;
2504
2505 if (r > 0)
2506 found = true;
2507 }
2508
06cc69d4
JJ
2509 if (found)
2510 continue;
2511
93b73b06 2512 r = return_data(j, j->unique_file, o, data, l);
3c1668da
LP
2513 if (r < 0)
2514 return r;
2515
2516 return 1;
2517 }
2518}
2519
115646c7 2520_public_ void sd_journal_restart_unique(sd_journal *j) {
3c1668da
LP
2521 if (!j)
2522 return;
2523
2524 j->unique_file = NULL;
2525 j->unique_offset = 0;
360af4cf 2526 j->unique_file_lost = false;
3c1668da 2527}
85210bff
LP
2528
2529_public_ int sd_journal_reliable_fd(sd_journal *j) {
1ae464e0
TA
2530 assert_return(j, -EINVAL);
2531 assert_return(!journal_pid_changed(j), -ECHILD);
85210bff
LP
2532
2533 return !j->on_network;
2534}
d4205751
LP
2535
2536static char *lookup_field(const char *field, void *userdata) {
2537 sd_journal *j = userdata;
2538 const void *data;
2539 size_t size, d;
2540 int r;
2541
2542 assert(field);
2543 assert(j);
2544
2545 r = sd_journal_get_data(j, field, &data, &size);
2546 if (r < 0 ||
2547 size > REPLACE_VAR_MAX)
2548 return strdup(field);
2549
2550 d = strlen(field) + 1;
2551
2552 return strndup((const char*) data + d, size - d);
2553}
2554
2555_public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2556 const void *data;
2557 size_t size;
2558 sd_id128_t id;
2559 _cleanup_free_ char *text = NULL, *cid = NULL;
2560 char *t;
2561 int r;
2562
1ae464e0
TA
2563 assert_return(j, -EINVAL);
2564 assert_return(!journal_pid_changed(j), -ECHILD);
2565 assert_return(ret, -EINVAL);
d4205751
LP
2566
2567 r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2568 if (r < 0)
2569 return r;
2570
2571 cid = strndup((const char*) data + 11, size - 11);
2572 if (!cid)
2573 return -ENOMEM;
2574
2575 r = sd_id128_from_string(cid, &id);
2576 if (r < 0)
2577 return r;
2578
844ec79b 2579 r = catalog_get(CATALOG_DATABASE, id, &text);
d4205751
LP
2580 if (r < 0)
2581 return r;
2582
2583 t = replace_var(text, lookup_field, j);
2584 if (!t)
2585 return -ENOMEM;
2586
2587 *ret = t;
2588 return 0;
2589}
8f1e860f
LP
2590
2591_public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
1ae464e0 2592 assert_return(ret, -EINVAL);
8f1e860f 2593
844ec79b 2594 return catalog_get(CATALOG_DATABASE, id, ret);
8f1e860f 2595}
93b73b06
LP
2596
2597_public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
1ae464e0
TA
2598 assert_return(j, -EINVAL);
2599 assert_return(!journal_pid_changed(j), -ECHILD);
93b73b06
LP
2600
2601 j->data_threshold = sz;
2602 return 0;
2603}
2604
2605_public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
1ae464e0
TA
2606 assert_return(j, -EINVAL);
2607 assert_return(!journal_pid_changed(j), -ECHILD);
2608 assert_return(sz, -EINVAL);
93b73b06
LP
2609
2610 *sz = j->data_threshold;
2611 return 0;
2612}