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