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