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