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