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