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