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