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