chiark / gitweb /
journal: use sd_journal_close on error in sd_journal_new
[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                         goto fail;
1573         }
1574
1575         j->files = hashmap_new(string_hash_func, string_compare_func);
1576         j->directories_by_path = hashmap_new(string_hash_func, string_compare_func);
1577         j->mmap = mmap_cache_new();
1578         if (!j->files || !j->directories_by_path || !j->mmap)
1579                 goto fail;
1580
1581         return j;
1582
1583 fail:
1584         sd_journal_close(j);
1585         return NULL;
1586 }
1587
1588 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1589         sd_journal *j;
1590         int r;
1591
1592         if (!ret)
1593                 return -EINVAL;
1594
1595         if (flags & ~(SD_JOURNAL_LOCAL_ONLY|
1596                       SD_JOURNAL_RUNTIME_ONLY|
1597                       SD_JOURNAL_SYSTEM_ONLY))
1598                 return -EINVAL;
1599
1600         j = journal_new(flags, NULL);
1601         if (!j)
1602                 return -ENOMEM;
1603
1604         r = add_search_paths(j);
1605         if (r < 0)
1606                 goto fail;
1607
1608         *ret = j;
1609         return 0;
1610
1611 fail:
1612         sd_journal_close(j);
1613
1614         return r;
1615 }
1616
1617 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
1618         sd_journal *j;
1619         int r;
1620
1621         if (!ret)
1622                 return -EINVAL;
1623
1624         if (!path || !path_is_absolute(path))
1625                 return -EINVAL;
1626
1627         if (flags != 0)
1628                 return -EINVAL;
1629
1630         j = journal_new(flags, path);
1631         if (!j)
1632                 return -ENOMEM;
1633
1634         r = add_root_directory(j, path);
1635         if (r < 0)
1636                 goto fail;
1637
1638         *ret = j;
1639         return 0;
1640
1641 fail:
1642         sd_journal_close(j);
1643
1644         return r;
1645 }
1646
1647 _public_ void sd_journal_close(sd_journal *j) {
1648         Directory *d;
1649         JournalFile *f;
1650
1651         if (!j)
1652                 return;
1653
1654         while ((f = hashmap_steal_first(j->files)))
1655                 journal_file_close(f);
1656
1657         hashmap_free(j->files);
1658
1659         while ((d = hashmap_first(j->directories_by_path)))
1660                 remove_directory(j, d);
1661
1662         while ((d = hashmap_first(j->directories_by_wd)))
1663                 remove_directory(j, d);
1664
1665         hashmap_free(j->directories_by_path);
1666         hashmap_free(j->directories_by_wd);
1667
1668         if (j->inotify_fd >= 0)
1669                 close_nointr_nofail(j->inotify_fd);
1670
1671         sd_journal_flush_matches(j);
1672
1673         if (j->mmap)
1674                 mmap_cache_unref(j->mmap);
1675
1676         free(j->path);
1677         free(j->unique_field);
1678         free(j);
1679 }
1680
1681 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
1682         Object *o;
1683         JournalFile *f;
1684         int r;
1685
1686         if (!j)
1687                 return -EINVAL;
1688         if (!ret)
1689                 return -EINVAL;
1690
1691         f = j->current_file;
1692         if (!f)
1693                 return -EADDRNOTAVAIL;
1694
1695         if (f->current_offset <= 0)
1696                 return -EADDRNOTAVAIL;
1697
1698         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1699         if (r < 0)
1700                 return r;
1701
1702         *ret = le64toh(o->entry.realtime);
1703         return 0;
1704 }
1705
1706 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
1707         Object *o;
1708         JournalFile *f;
1709         int r;
1710         sd_id128_t id;
1711
1712         if (!j)
1713                 return -EINVAL;
1714
1715         f = j->current_file;
1716         if (!f)
1717                 return -EADDRNOTAVAIL;
1718
1719         if (f->current_offset <= 0)
1720                 return -EADDRNOTAVAIL;
1721
1722         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1723         if (r < 0)
1724                 return r;
1725
1726         if (ret_boot_id)
1727                 *ret_boot_id = o->entry.boot_id;
1728         else {
1729                 r = sd_id128_get_boot(&id);
1730                 if (r < 0)
1731                         return r;
1732
1733                 if (!sd_id128_equal(id, o->entry.boot_id))
1734                         return -ESTALE;
1735         }
1736
1737         if (ret)
1738                 *ret = le64toh(o->entry.monotonic);
1739
1740         return 0;
1741 }
1742
1743 static bool field_is_valid(const char *field) {
1744         const char *p;
1745
1746         assert(field);
1747
1748         if (isempty(field))
1749                 return false;
1750
1751         if (startswith(field, "__"))
1752                 return false;
1753
1754         for (p = field; *p; p++) {
1755
1756                 if (*p == '_')
1757                         continue;
1758
1759                 if (*p >= 'A' && *p <= 'Z')
1760                         continue;
1761
1762                 if (*p >= '0' && *p <= '9')
1763                         continue;
1764
1765                 return false;
1766         }
1767
1768         return true;
1769 }
1770
1771 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
1772         JournalFile *f;
1773         uint64_t i, n;
1774         size_t field_length;
1775         int r;
1776         Object *o;
1777
1778         if (!j)
1779                 return -EINVAL;
1780         if (!field)
1781                 return -EINVAL;
1782         if (!data)
1783                 return -EINVAL;
1784         if (!size)
1785                 return -EINVAL;
1786
1787         if (!field_is_valid(field))
1788                 return -EINVAL;
1789
1790         f = j->current_file;
1791         if (!f)
1792                 return -EADDRNOTAVAIL;
1793
1794         if (f->current_offset <= 0)
1795                 return -EADDRNOTAVAIL;
1796
1797         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1798         if (r < 0)
1799                 return r;
1800
1801         field_length = strlen(field);
1802
1803         n = journal_file_entry_n_items(o);
1804         for (i = 0; i < n; i++) {
1805                 uint64_t p, l;
1806                 le64_t le_hash;
1807                 size_t t;
1808
1809                 p = le64toh(o->entry.items[i].object_offset);
1810                 le_hash = o->entry.items[i].hash;
1811                 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1812                 if (r < 0)
1813                         return r;
1814
1815                 if (le_hash != o->data.hash)
1816                         return -EBADMSG;
1817
1818                 l = le64toh(o->object.size) - offsetof(Object, data.payload);
1819
1820                 if (o->object.flags & OBJECT_COMPRESSED) {
1821
1822 #ifdef HAVE_XZ
1823                         if (uncompress_startswith(o->data.payload, l,
1824                                                   &f->compress_buffer, &f->compress_buffer_size,
1825                                                   field, field_length, '=')) {
1826
1827                                 uint64_t rsize;
1828
1829                                 if (!uncompress_blob(o->data.payload, l,
1830                                                      &f->compress_buffer, &f->compress_buffer_size, &rsize,
1831                                                      j->data_threshold))
1832                                         return -EBADMSG;
1833
1834                                 *data = f->compress_buffer;
1835                                 *size = (size_t) rsize;
1836
1837                                 return 0;
1838                         }
1839 #else
1840                         return -EPROTONOSUPPORT;
1841 #endif
1842
1843                 } else if (l >= field_length+1 &&
1844                            memcmp(o->data.payload, field, field_length) == 0 &&
1845                            o->data.payload[field_length] == '=') {
1846
1847                         t = (size_t) l;
1848
1849                         if ((uint64_t) t != l)
1850                                 return -E2BIG;
1851
1852                         *data = o->data.payload;
1853                         *size = t;
1854
1855                         return 0;
1856                 }
1857
1858                 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1859                 if (r < 0)
1860                         return r;
1861         }
1862
1863         return -ENOENT;
1864 }
1865
1866 static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) {
1867         size_t t;
1868         uint64_t l;
1869
1870         l = le64toh(o->object.size) - offsetof(Object, data.payload);
1871         t = (size_t) l;
1872
1873         /* We can't read objects larger than 4G on a 32bit machine */
1874         if ((uint64_t) t != l)
1875                 return -E2BIG;
1876
1877         if (o->object.flags & OBJECT_COMPRESSED) {
1878 #ifdef HAVE_XZ
1879                 uint64_t rsize;
1880
1881                 if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, j->data_threshold))
1882                         return -EBADMSG;
1883
1884                 *data = f->compress_buffer;
1885                 *size = (size_t) rsize;
1886 #else
1887                 return -EPROTONOSUPPORT;
1888 #endif
1889         } else {
1890                 *data = o->data.payload;
1891                 *size = t;
1892         }
1893
1894         return 0;
1895 }
1896
1897 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
1898         JournalFile *f;
1899         uint64_t p, n;
1900         le64_t le_hash;
1901         int r;
1902         Object *o;
1903
1904         if (!j)
1905                 return -EINVAL;
1906         if (!data)
1907                 return -EINVAL;
1908         if (!size)
1909                 return -EINVAL;
1910
1911         f = j->current_file;
1912         if (!f)
1913                 return -EADDRNOTAVAIL;
1914
1915         if (f->current_offset <= 0)
1916                 return -EADDRNOTAVAIL;
1917
1918         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
1919         if (r < 0)
1920                 return r;
1921
1922         n = journal_file_entry_n_items(o);
1923         if (j->current_field >= n)
1924                 return 0;
1925
1926         p = le64toh(o->entry.items[j->current_field].object_offset);
1927         le_hash = o->entry.items[j->current_field].hash;
1928         r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1929         if (r < 0)
1930                 return r;
1931
1932         if (le_hash != o->data.hash)
1933                 return -EBADMSG;
1934
1935         r = return_data(j, f, o, data, size);
1936         if (r < 0)
1937                 return r;
1938
1939         j->current_field ++;
1940
1941         return 1;
1942 }
1943
1944 _public_ void sd_journal_restart_data(sd_journal *j) {
1945         if (!j)
1946                 return;
1947
1948         j->current_field = 0;
1949 }
1950
1951 _public_ int sd_journal_get_fd(sd_journal *j) {
1952         int r;
1953
1954         if (!j)
1955                 return -EINVAL;
1956
1957         if (j->inotify_fd >= 0)
1958                 return j->inotify_fd;
1959
1960         r = allocate_inotify(j);
1961         if (r < 0)
1962                 return r;
1963
1964         /* Iterate through all dirs again, to add them to the
1965          * inotify */
1966         if (j->path)
1967                 r = add_root_directory(j, j->path);
1968         else
1969                 r = add_search_paths(j);
1970         if (r < 0)
1971                 return r;
1972
1973         return j->inotify_fd;
1974 }
1975
1976 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
1977         Directory *d;
1978         int r;
1979
1980         assert(j);
1981         assert(e);
1982
1983         /* Is this a subdirectory we watch? */
1984         d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
1985         if (d) {
1986                 sd_id128_t id;
1987
1988                 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
1989                     (endswith(e->name, ".journal") ||
1990                      endswith(e->name, ".journal~"))) {
1991
1992                         /* Event for a journal file */
1993
1994                         if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
1995                                 r = add_file(j, d->path, e->name);
1996                                 if (r < 0)
1997                                         log_debug("Failed to add file %s/%s: %s", d->path, e->name, strerror(-r));
1998
1999                         } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
2000
2001                                 r = remove_file(j, d->path, e->name);
2002                                 if (r < 0)
2003                                         log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r));
2004                         }
2005
2006                 } else if (!d->is_root && e->len == 0) {
2007
2008                         /* Event for a subdirectory */
2009
2010                         if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
2011                                 r = remove_directory(j, d);
2012                                 if (r < 0)
2013                                         log_debug("Failed to remove directory %s: %s", d->path, strerror(-r));
2014                         }
2015
2016
2017                 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
2018
2019                         /* Event for root directory */
2020
2021                         if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
2022                                 r = add_directory(j, d->path, e->name);
2023                                 if (r < 0)
2024                                         log_debug("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r));
2025                         }
2026                 }
2027
2028                 return;
2029         }
2030
2031         if (e->mask & IN_IGNORED)
2032                 return;
2033
2034         log_warning("Unknown inotify event.");
2035 }
2036
2037 static int determine_change(sd_journal *j) {
2038         bool b;
2039
2040         assert(j);
2041
2042         b = j->current_invalidate_counter != j->last_invalidate_counter;
2043         j->last_invalidate_counter = j->current_invalidate_counter;
2044
2045         return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2046 }
2047
2048 _public_ int sd_journal_process(sd_journal *j) {
2049         uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX] _alignas_(struct inotify_event);
2050         bool got_something = false;
2051
2052         if (!j)
2053                 return -EINVAL;
2054
2055         for (;;) {
2056                 struct inotify_event *e;
2057                 ssize_t l;
2058
2059                 l = read(j->inotify_fd, buffer, sizeof(buffer));
2060                 if (l < 0) {
2061                         if (errno == EAGAIN || errno == EINTR)
2062                                 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2063
2064                         return -errno;
2065                 }
2066
2067                 got_something = true;
2068
2069                 e = (struct inotify_event*) buffer;
2070                 while (l > 0) {
2071                         size_t step;
2072
2073                         process_inotify_event(j, e);
2074
2075                         step = sizeof(struct inotify_event) + e->len;
2076                         assert(step <= (size_t) l);
2077
2078                         e = (struct inotify_event*) ((uint8_t*) e + step);
2079                         l -= step;
2080                 }
2081         }
2082
2083         return determine_change(j);
2084 }
2085
2086 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2087         int r;
2088
2089         assert(j);
2090
2091         if (j->inotify_fd < 0) {
2092
2093                 /* This is the first invocation, hence create the
2094                  * inotify watch */
2095                 r = sd_journal_get_fd(j);
2096                 if (r < 0)
2097                         return r;
2098
2099                 /* The journal might have changed since the context
2100                  * object was created and we weren't watching before,
2101                  * hence don't wait for anything, and return
2102                  * immediately. */
2103                 return determine_change(j);
2104         }
2105
2106         if (j->on_network) {
2107                 /* If we are on the network we need to regularly check
2108                  * for changes manually */
2109
2110                 if (timeout_usec == (uint64_t) -1 || timeout_usec > JOURNAL_FILES_RECHECK_USEC)
2111                         timeout_usec = JOURNAL_FILES_RECHECK_USEC;
2112         }
2113
2114         do {
2115                 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2116         } while (r == -EINTR);
2117
2118         if (r < 0)
2119                 return r;
2120
2121         return sd_journal_process(j);
2122 }
2123
2124 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2125         Iterator i;
2126         JournalFile *f;
2127         bool first = true;
2128         int r;
2129
2130         if (!j)
2131                 return -EINVAL;
2132         if (!from && !to)
2133                 return -EINVAL;
2134
2135         HASHMAP_FOREACH(f, j->files, i) {
2136                 usec_t fr, t;
2137
2138                 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2139                 if (r == -ENOENT)
2140                         continue;
2141                 if (r < 0)
2142                         return r;
2143                 if (r == 0)
2144                         continue;
2145
2146                 if (first) {
2147                         if (from)
2148                                 *from = fr;
2149                         if (to)
2150                                 *to = t;
2151                         first = false;
2152                 } else {
2153                         if (from)
2154                                 *from = MIN(fr, *from);
2155                         if (to)
2156                                 *to = MAX(t, *to);
2157                 }
2158         }
2159
2160         return first ? 0 : 1;
2161 }
2162
2163 _public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) {
2164         Iterator i;
2165         JournalFile *f;
2166         bool first = true;
2167         int r;
2168
2169         if (!j)
2170                 return -EINVAL;
2171         if (!from && !to)
2172                 return -EINVAL;
2173
2174         HASHMAP_FOREACH(f, j->files, i) {
2175                 usec_t fr, t;
2176
2177                 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t);
2178                 if (r == -ENOENT)
2179                         continue;
2180                 if (r < 0)
2181                         return r;
2182                 if (r == 0)
2183                         continue;
2184
2185                 if (first) {
2186                         if (from)
2187                                 *from = fr;
2188                         if (to)
2189                                 *to = t;
2190                         first = false;
2191                 } else {
2192                         if (from)
2193                                 *from = MIN(fr, *from);
2194                         if (to)
2195                                 *to = MAX(t, *to);
2196                 }
2197         }
2198
2199         return first ? 0 : 1;
2200 }
2201
2202 void journal_print_header(sd_journal *j) {
2203         Iterator i;
2204         JournalFile *f;
2205         bool newline = false;
2206
2207         assert(j);
2208
2209         HASHMAP_FOREACH(f, j->files, i) {
2210                 if (newline)
2211                         putchar('\n');
2212                 else
2213                         newline = true;
2214
2215                 journal_file_print_header(f);
2216         }
2217 }
2218
2219 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) {
2220         Iterator i;
2221         JournalFile *f;
2222         uint64_t sum = 0;
2223
2224         if (!j)
2225                 return -EINVAL;
2226         if (!bytes)
2227                 return -EINVAL;
2228
2229         HASHMAP_FOREACH(f, j->files, i) {
2230                 struct stat st;
2231
2232                 if (fstat(f->fd, &st) < 0)
2233                         return -errno;
2234
2235                 sum += (uint64_t) st.st_blocks * 512ULL;
2236         }
2237
2238         *bytes = sum;
2239         return 0;
2240 }
2241
2242 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2243         char *f;
2244
2245         if (!j)
2246                 return -EINVAL;
2247         if (isempty(field))
2248                 return -EINVAL;
2249         if (!field_is_valid(field))
2250                 return -EINVAL;
2251
2252         f = strdup(field);
2253         if (!f)
2254                 return -ENOMEM;
2255
2256         free(j->unique_field);
2257         j->unique_field = f;
2258         j->unique_file = NULL;
2259         j->unique_offset = 0;
2260
2261         return 0;
2262 }
2263
2264 _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
2265         Object *o;
2266         size_t k;
2267         int r;
2268
2269         if (!j)
2270                 return -EINVAL;
2271         if (!data)
2272                 return -EINVAL;
2273         if (!l)
2274                 return -EINVAL;
2275         if (!j->unique_field)
2276                 return -EINVAL;
2277
2278         k = strlen(j->unique_field);
2279
2280         if (!j->unique_file) {
2281                 j->unique_file = hashmap_first(j->files);
2282                 if (!j->unique_file)
2283                         return 0;
2284                 j->unique_offset = 0;
2285         }
2286
2287         for (;;) {
2288                 JournalFile *of;
2289                 Iterator i;
2290                 const void *odata;
2291                 size_t ol;
2292                 bool found;
2293
2294                 /* Proceed to next data object in the field's linked list */
2295                 if (j->unique_offset == 0) {
2296                         r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2297                         if (r < 0)
2298                                 return r;
2299
2300                         j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2301                 } else {
2302                         r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2303                         if (r < 0)
2304                                 return r;
2305
2306                         j->unique_offset = le64toh(o->data.next_field_offset);
2307                 }
2308
2309                 /* We reached the end of the list? Then start again, with the next file */
2310                 if (j->unique_offset == 0) {
2311                         JournalFile *n;
2312
2313                         n = hashmap_next(j->files, j->unique_file->path);
2314                         if (!n)
2315                                 return 0;
2316
2317                         j->unique_file = n;
2318                         continue;
2319                 }
2320
2321                 /* We do not use the type context here, but 0 instead,
2322                  * so that we can look at this data object at the same
2323                  * time as one on another file */
2324                 r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o);
2325                 if (r < 0)
2326                         return r;
2327
2328                 /* Let's do the type check by hand, since we used 0 context above. */
2329                 if (o->object.type != OBJECT_DATA)
2330                         return -EBADMSG;
2331
2332                 r = return_data(j, j->unique_file, o, &odata, &ol);
2333                 if (r < 0)
2334                         return r;
2335
2336                 /* OK, now let's see if we already returned this data
2337                  * object by checking if it exists in the earlier
2338                  * traversed files. */
2339                 found = false;
2340                 HASHMAP_FOREACH(of, j->files, i) {
2341                         Object *oo;
2342                         uint64_t op;
2343
2344                         if (of == j->unique_file)
2345                                 break;
2346
2347                         /* Skip this file it didn't have any fields
2348                          * indexed */
2349                         if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) &&
2350                             le64toh(of->header->n_fields) <= 0)
2351                                 continue;
2352
2353                         r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op);
2354                         if (r < 0)
2355                                 return r;
2356
2357                         if (r > 0)
2358                                 found = true;
2359                 }
2360
2361                 if (found)
2362                         continue;
2363
2364                 r = return_data(j, j->unique_file, o, data, l);
2365                 if (r < 0)
2366                         return r;
2367
2368                 return 1;
2369         }
2370 }
2371
2372 _public_ void sd_journal_restart_unique(sd_journal *j) {
2373         if (!j)
2374                 return;
2375
2376         j->unique_file = NULL;
2377         j->unique_offset = 0;
2378 }
2379
2380 _public_ int sd_journal_reliable_fd(sd_journal *j) {
2381         if (!j)
2382                 return -EINVAL;
2383
2384         return !j->on_network;
2385 }
2386
2387 static char *lookup_field(const char *field, void *userdata) {
2388         sd_journal *j = userdata;
2389         const void *data;
2390         size_t size, d;
2391         int r;
2392
2393         assert(field);
2394         assert(j);
2395
2396         r = sd_journal_get_data(j, field, &data, &size);
2397         if (r < 0 ||
2398             size > REPLACE_VAR_MAX)
2399                 return strdup(field);
2400
2401         d = strlen(field) + 1;
2402
2403         return strndup((const char*) data + d, size - d);
2404 }
2405
2406 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
2407         const void *data;
2408         size_t size;
2409         sd_id128_t id;
2410         _cleanup_free_ char *text = NULL, *cid = NULL;
2411         char *t;
2412         int r;
2413
2414         if (!j)
2415                 return -EINVAL;
2416         if (!ret)
2417                 return -EINVAL;
2418
2419         r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
2420         if (r < 0)
2421                 return r;
2422
2423         cid = strndup((const char*) data + 11, size - 11);
2424         if (!cid)
2425                 return -ENOMEM;
2426
2427         r = sd_id128_from_string(cid, &id);
2428         if (r < 0)
2429                 return r;
2430
2431         r = catalog_get(id, &text);
2432         if (r < 0)
2433                 return r;
2434
2435         t = replace_var(text, lookup_field, j);
2436         if (!t)
2437                 return -ENOMEM;
2438
2439         *ret = t;
2440         return 0;
2441 }
2442
2443 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
2444         if (!ret)
2445                 return -EINVAL;
2446
2447         return catalog_get(id, ret);
2448 }
2449
2450 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
2451         if (!j)
2452                 return -EINVAL;
2453
2454         j->data_threshold = sz;
2455         return 0;
2456 }
2457
2458 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
2459         if (!j)
2460                 return -EINVAL;
2461         if (!sz)
2462                 return -EINVAL;
2463
2464         *sz = j->data_threshold;
2465         return 0;
2466 }