1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <inttypes.h>
6 #include <linux/magic.h>
7 #include <poll.h>
8 #include <stddef.h>
9 #include <sys/inotify.h>
10 #include <sys/vfs.h>
11 #include <unistd.h>
12 
13 #include "sd-journal.h"
14 
15 #include "alloc-util.h"
16 #include "catalog.h"
17 #include "compress.h"
18 #include "dirent-util.h"
19 #include "env-file.h"
20 #include "escape.h"
21 #include "fd-util.h"
22 #include "fileio.h"
23 #include "format-util.h"
24 #include "fs-util.h"
25 #include "hashmap.h"
26 #include "hostname-util.h"
27 #include "id128-util.h"
28 #include "inotify-util.h"
29 #include "io-util.h"
30 #include "journal-def.h"
31 #include "journal-file.h"
32 #include "journal-internal.h"
33 #include "list.h"
34 #include "lookup3.h"
35 #include "nulstr-util.h"
36 #include "path-util.h"
37 #include "process-util.h"
38 #include "replace-var.h"
39 #include "stat-util.h"
40 #include "stdio-util.h"
41 #include "string-util.h"
42 #include "strv.h"
43 #include "syslog-util.h"
44 
45 #define JOURNAL_FILES_MAX 7168
46 
47 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
48 
49 /* The maximum size of variable values we'll expand in catalog entries. We bind this to PATH_MAX for now, as
50  * we want to be able to show all officially valid paths at least */
51 #define REPLACE_VAR_MAX PATH_MAX
52 
53 #define DEFAULT_DATA_THRESHOLD (64*1024)
54 
55 static void remove_file_real(sd_journal *j, JournalFile *f);
56 
journal_pid_changed(sd_journal * j)57 static bool journal_pid_changed(sd_journal *j) {
58         assert(j);
59 
60         /* We don't support people creating a journal object and
61          * keeping it around over a fork(). Let's complain. */
62 
63         return j->original_pid != getpid_cached();
64 }
65 
journal_put_error(sd_journal * j,int r,const char * path)66 static int journal_put_error(sd_journal *j, int r, const char *path) {
67         _cleanup_free_ char *copy = NULL;
68         int k;
69 
70         /* Memorize an error we encountered, and store which
71          * file/directory it was generated from. Note that we store
72          * only *one* path per error code, as the error code is the
73          * key into the hashmap, and the path is the value. This means
74          * we keep track only of all error kinds, but not of all error
75          * locations. This has the benefit that the hashmap cannot
76          * grow beyond bounds.
77          *
78          * We return an error here only if we didn't manage to
79          * memorize the real error. */
80 
81         if (r >= 0)
82                 return r;
83 
84         if (path) {
85                 copy = strdup(path);
86                 if (!copy)
87                         return -ENOMEM;
88         }
89 
90         k = hashmap_ensure_put(&j->errors, NULL, INT_TO_PTR(r), copy);
91         if (k < 0) {
92                 if (k == -EEXIST)
93                         return 0;
94 
95                 return k;
96         }
97 
98         TAKE_PTR(copy);
99         return 0;
100 }
101 
detach_location(sd_journal * j)102 static void detach_location(sd_journal *j) {
103         JournalFile *f;
104 
105         assert(j);
106 
107         j->current_file = NULL;
108         j->current_field = 0;
109 
110         ORDERED_HASHMAP_FOREACH(f, j->files)
111                 journal_file_reset_location(f);
112 }
113 
init_location(Location * l,LocationType type,JournalFile * f,Object * o)114 static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
115         assert(l);
116         assert(IN_SET(type, LOCATION_DISCRETE, LOCATION_SEEK));
117         assert(f);
118 
119         *l = (Location) {
120                 .type = type,
121                 .seqnum = le64toh(o->entry.seqnum),
122                 .seqnum_id = f->header->seqnum_id,
123                 .realtime = le64toh(o->entry.realtime),
124                 .monotonic = le64toh(o->entry.monotonic),
125                 .boot_id = o->entry.boot_id,
126                 .xor_hash = le64toh(o->entry.xor_hash),
127                 .seqnum_set = true,
128                 .realtime_set = true,
129                 .monotonic_set = true,
130                 .xor_hash_set = true,
131         };
132 }
133 
set_location(sd_journal * j,JournalFile * f,Object * o)134 static void set_location(sd_journal *j, JournalFile *f, Object *o) {
135         assert(j);
136         assert(f);
137         assert(o);
138 
139         init_location(&j->current_location, LOCATION_DISCRETE, f, o);
140 
141         j->current_file = f;
142         j->current_field = 0;
143 
144         /* Let f know its candidate entry was picked. */
145         assert(f->location_type == LOCATION_SEEK);
146         f->location_type = LOCATION_DISCRETE;
147 }
148 
match_is_valid(const void * data,size_t size)149 static int match_is_valid(const void *data, size_t size) {
150         const char *b, *p;
151 
152         assert(data);
153 
154         if (size < 2)
155                 return false;
156 
157         if (((char*) data)[0] == '_' && ((char*) data)[1] == '_')
158                 return false;
159 
160         b = data;
161         for (p = b; p < b + size; p++) {
162 
163                 if (*p == '=')
164                         return p > b;
165 
166                 if (*p == '_')
167                         continue;
168 
169                 if (*p >= 'A' && *p <= 'Z')
170                         continue;
171 
172                 if (*p >= '0' && *p <= '9')
173                         continue;
174 
175                 return false;
176         }
177 
178         return false;
179 }
180 
same_field(const void * _a,size_t s,const void * _b,size_t t)181 static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
182         const uint8_t *a = _a, *b = _b;
183         size_t j;
184 
185         for (j = 0; j < s && j < t; j++) {
186 
187                 if (a[j] != b[j])
188                         return false;
189 
190                 if (a[j] == '=')
191                         return true;
192         }
193 
194         assert_not_reached();
195 }
196 
match_new(Match * p,MatchType t)197 static Match *match_new(Match *p, MatchType t) {
198         Match *m;
199 
200         m = new(Match, 1);
201         if (!m)
202                 return NULL;
203 
204         *m = (Match) {
205                 .type = t,
206                 .parent = p,
207         };
208 
209         if (p)
210                 LIST_PREPEND(matches, p->matches, m);
211 
212         return m;
213 }
214 
match_free(Match * m)215 static Match *match_free(Match *m) {
216         assert(m);
217 
218         while (m->matches)
219                 match_free(m->matches);
220 
221         if (m->parent)
222                 LIST_REMOVE(matches, m->parent->matches, m);
223 
224         free(m->data);
225         return mfree(m);
226 }
227 
match_free_if_empty(Match * m)228 static Match *match_free_if_empty(Match *m) {
229         if (!m || m->matches)
230                 return m;
231 
232         return match_free(m);
233 }
234 
sd_journal_add_match(sd_journal * j,const void * data,size_t size)235 _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
236         Match *add_here = NULL, *m = NULL;
237         uint64_t hash;
238 
239         assert_return(j, -EINVAL);
240         assert_return(!journal_pid_changed(j), -ECHILD);
241         assert_return(data, -EINVAL);
242 
243         if (size == 0)
244                 size = strlen(data);
245 
246         assert_return(match_is_valid(data, size), -EINVAL);
247 
248         /* level 0: AND term
249          * level 1: OR terms
250          * level 2: AND terms
251          * level 3: OR terms
252          * level 4: concrete matches */
253 
254         if (!j->level0) {
255                 j->level0 = match_new(NULL, MATCH_AND_TERM);
256                 if (!j->level0)
257                         return -ENOMEM;
258         }
259 
260         if (!j->level1) {
261                 j->level1 = match_new(j->level0, MATCH_OR_TERM);
262                 if (!j->level1)
263                         return -ENOMEM;
264         }
265 
266         if (!j->level2) {
267                 j->level2 = match_new(j->level1, MATCH_AND_TERM);
268                 if (!j->level2)
269                         return -ENOMEM;
270         }
271 
272         assert(j->level0->type == MATCH_AND_TERM);
273         assert(j->level1->type == MATCH_OR_TERM);
274         assert(j->level2->type == MATCH_AND_TERM);
275 
276         /* Old-style Jenkins (unkeyed) hashing only here. We do not cover new-style siphash (keyed) hashing
277          * here, since it's different for each file, and thus can't be pre-calculated in the Match object. */
278         hash = jenkins_hash64(data, size);
279 
280         LIST_FOREACH(matches, l3, j->level2->matches) {
281                 assert(l3->type == MATCH_OR_TERM);
282 
283                 LIST_FOREACH(matches, l4, l3->matches) {
284                         assert(l4->type == MATCH_DISCRETE);
285 
286                         /* Exactly the same match already? Then ignore
287                          * this addition */
288                         if (l4->hash == hash &&
289                             l4->size == size &&
290                             memcmp(l4->data, data, size) == 0)
291                                 return 0;
292 
293                         /* Same field? Then let's add this to this OR term */
294                         if (same_field(data, size, l4->data, l4->size)) {
295                                 add_here = l3;
296                                 break;
297                         }
298                 }
299 
300                 if (add_here)
301                         break;
302         }
303 
304         if (!add_here) {
305                 add_here = match_new(j->level2, MATCH_OR_TERM);
306                 if (!add_here)
307                         goto fail;
308         }
309 
310         m = match_new(add_here, MATCH_DISCRETE);
311         if (!m)
312                 goto fail;
313 
314         m->hash = hash;
315         m->size = size;
316         m->data = memdup(data, size);
317         if (!m->data)
318                 goto fail;
319 
320         detach_location(j);
321 
322         return 0;
323 
324 fail:
325         match_free(m);
326         match_free_if_empty(add_here);
327         j->level2 = match_free_if_empty(j->level2);
328         j->level1 = match_free_if_empty(j->level1);
329         j->level0 = match_free_if_empty(j->level0);
330 
331         return -ENOMEM;
332 }
333 
sd_journal_add_conjunction(sd_journal * j)334 _public_ int sd_journal_add_conjunction(sd_journal *j) {
335         assert_return(j, -EINVAL);
336         assert_return(!journal_pid_changed(j), -ECHILD);
337 
338         if (!j->level0)
339                 return 0;
340 
341         if (!j->level1)
342                 return 0;
343 
344         if (!j->level1->matches)
345                 return 0;
346 
347         j->level1 = NULL;
348         j->level2 = NULL;
349 
350         return 0;
351 }
352 
sd_journal_add_disjunction(sd_journal * j)353 _public_ int sd_journal_add_disjunction(sd_journal *j) {
354         assert_return(j, -EINVAL);
355         assert_return(!journal_pid_changed(j), -ECHILD);
356 
357         if (!j->level0)
358                 return 0;
359 
360         if (!j->level1)
361                 return 0;
362 
363         if (!j->level2)
364                 return 0;
365 
366         if (!j->level2->matches)
367                 return 0;
368 
369         j->level2 = NULL;
370         return 0;
371 }
372 
match_make_string(Match * m)373 static char *match_make_string(Match *m) {
374         char *p = NULL, *r;
375         bool enclose = false;
376 
377         if (!m)
378                 return strdup("none");
379 
380         if (m->type == MATCH_DISCRETE)
381                 return cescape_length(m->data, m->size);
382 
383         LIST_FOREACH(matches, i, m->matches) {
384                 char *t, *k;
385 
386                 t = match_make_string(i);
387                 if (!t)
388                         return mfree(p);
389 
390                 if (p) {
391                         k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t);
392                         free(p);
393                         free(t);
394 
395                         if (!k)
396                                 return NULL;
397 
398                         p = k;
399 
400                         enclose = true;
401                 } else
402                         p = t;
403         }
404 
405         if (enclose) {
406                 r = strjoin("(", p, ")");
407                 free(p);
408                 return r;
409         }
410 
411         return p;
412 }
413 
journal_make_match_string(sd_journal * j)414 char *journal_make_match_string(sd_journal *j) {
415         assert(j);
416 
417         return match_make_string(j->level0);
418 }
419 
sd_journal_flush_matches(sd_journal * j)420 _public_ void sd_journal_flush_matches(sd_journal *j) {
421         if (!j)
422                 return;
423 
424         if (j->level0)
425                 match_free(j->level0);
426 
427         j->level0 = j->level1 = j->level2 = NULL;
428 
429         detach_location(j);
430 }
431 
compare_with_location(const JournalFile * f,const Location * l,const JournalFile * current_file)432 _pure_ static int compare_with_location(const JournalFile *f, const Location *l, const JournalFile *current_file) {
433         int r;
434 
435         assert(f);
436         assert(l);
437         assert(f->location_type == LOCATION_SEEK);
438         assert(IN_SET(l->type, LOCATION_DISCRETE, LOCATION_SEEK));
439 
440         if (l->monotonic_set &&
441             sd_id128_equal(f->current_boot_id, l->boot_id) &&
442             l->realtime_set &&
443             f->current_realtime == l->realtime &&
444             l->xor_hash_set &&
445             f->current_xor_hash == l->xor_hash &&
446             l->seqnum_set &&
447             sd_id128_equal(f->header->seqnum_id, l->seqnum_id) &&
448             f->current_seqnum == l->seqnum &&
449             f != current_file)
450                 return 0;
451 
452         if (l->seqnum_set &&
453             sd_id128_equal(f->header->seqnum_id, l->seqnum_id)) {
454 
455                 r = CMP(f->current_seqnum, l->seqnum);
456                 if (r != 0)
457                         return r;
458         }
459 
460         if (l->monotonic_set &&
461             sd_id128_equal(f->current_boot_id, l->boot_id)) {
462 
463                 r = CMP(f->current_monotonic, l->monotonic);
464                 if (r != 0)
465                         return r;
466         }
467 
468         if (l->realtime_set) {
469 
470                 r = CMP(f->current_realtime, l->realtime);
471                 if (r != 0)
472                         return r;
473         }
474 
475         if (l->xor_hash_set) {
476 
477                 r = CMP(f->current_xor_hash, l->xor_hash);
478                 if (r != 0)
479                         return r;
480         }
481 
482         return 0;
483 }
484 
next_for_match(sd_journal * j,Match * m,JournalFile * f,uint64_t after_offset,direction_t direction,Object ** ret,uint64_t * offset)485 static int next_for_match(
486                 sd_journal *j,
487                 Match *m,
488                 JournalFile *f,
489                 uint64_t after_offset,
490                 direction_t direction,
491                 Object **ret,
492                 uint64_t *offset) {
493 
494         int r;
495         uint64_t np = 0;
496 
497         assert(j);
498         assert(m);
499         assert(f);
500 
501         if (m->type == MATCH_DISCRETE) {
502                 Object *d;
503                 uint64_t hash;
504 
505                 /* If the keyed hash logic is used, we need to calculate the hash fresh per file. Otherwise
506                  * we can use what we pre-calculated. */
507                 if (JOURNAL_HEADER_KEYED_HASH(f->header))
508                         hash = journal_file_hash_data(f, m->data, m->size);
509                 else
510                         hash = m->hash;
511 
512                 r = journal_file_find_data_object_with_hash(f, m->data, m->size, hash, &d, NULL);
513                 if (r <= 0)
514                         return r;
515 
516                 return journal_file_move_to_entry_by_offset_for_data(f, d, after_offset, direction, ret, offset);
517 
518         } else if (m->type == MATCH_OR_TERM) {
519 
520                 /* Find the earliest match beyond after_offset */
521 
522                 LIST_FOREACH(matches, i, m->matches) {
523                         uint64_t cp;
524 
525                         r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
526                         if (r < 0)
527                                 return r;
528                         else if (r > 0) {
529                                 if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
530                                         np = cp;
531                         }
532                 }
533 
534                 if (np == 0)
535                         return 0;
536 
537         } else if (m->type == MATCH_AND_TERM) {
538                 Match *last_moved;
539 
540                 /* Always jump to the next matching entry and repeat
541                  * this until we find an offset that matches for all
542                  * matches. */
543 
544                 if (!m->matches)
545                         return 0;
546 
547                 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
548                 if (r <= 0)
549                         return r;
550 
551                 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
552                 last_moved = m->matches;
553 
554                 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
555                         uint64_t cp;
556 
557                         r = next_for_match(j, i, f, np, direction, NULL, &cp);
558                         if (r <= 0)
559                                 return r;
560 
561                         assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
562                         if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
563                                 np = cp;
564                                 last_moved = i;
565                         }
566                 }
567         }
568 
569         assert(np > 0);
570 
571         if (ret) {
572                 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, ret);
573                 if (r < 0)
574                         return r;
575         }
576 
577         if (offset)
578                 *offset = np;
579 
580         return 1;
581 }
582 
find_location_for_match(sd_journal * j,Match * m,JournalFile * f,direction_t direction,Object ** ret,uint64_t * offset)583 static int find_location_for_match(
584                 sd_journal *j,
585                 Match *m,
586                 JournalFile *f,
587                 direction_t direction,
588                 Object **ret,
589                 uint64_t *offset) {
590 
591         int r;
592 
593         assert(j);
594         assert(m);
595         assert(f);
596 
597         if (m->type == MATCH_DISCRETE) {
598                 Object *d;
599                 uint64_t dp, hash;
600 
601                 if (JOURNAL_HEADER_KEYED_HASH(f->header))
602                         hash = journal_file_hash_data(f, m->data, m->size);
603                 else
604                         hash = m->hash;
605 
606                 r = journal_file_find_data_object_with_hash(f, m->data, m->size, hash, &d, &dp);
607                 if (r <= 0)
608                         return r;
609 
610                 /* FIXME: missing: find by monotonic */
611 
612                 if (j->current_location.type == LOCATION_HEAD)
613                         return journal_file_next_entry_for_data(f, d, DIRECTION_DOWN, ret, offset);
614                 if (j->current_location.type == LOCATION_TAIL)
615                         return journal_file_next_entry_for_data(f, d, DIRECTION_UP, ret, offset);
616                 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
617                         return journal_file_move_to_entry_by_seqnum_for_data(f, d, j->current_location.seqnum, direction, ret, offset);
618                 if (j->current_location.monotonic_set) {
619                         r = journal_file_move_to_entry_by_monotonic_for_data(f, d, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
620                         if (r != -ENOENT)
621                                 return r;
622 
623                         /* The data object might have been invalidated. */
624                         r = journal_file_move_to_object(f, OBJECT_DATA, dp, &d);
625                         if (r < 0)
626                                 return r;
627                 }
628                 if (j->current_location.realtime_set)
629                         return journal_file_move_to_entry_by_realtime_for_data(f, d, j->current_location.realtime, direction, ret, offset);
630 
631                 return journal_file_next_entry_for_data(f, d, direction, ret, offset);
632 
633         } else if (m->type == MATCH_OR_TERM) {
634                 uint64_t np = 0;
635 
636                 /* Find the earliest match */
637 
638                 LIST_FOREACH(matches, i, m->matches) {
639                         uint64_t cp;
640 
641                         r = find_location_for_match(j, i, f, direction, NULL, &cp);
642                         if (r < 0)
643                                 return r;
644                         else if (r > 0) {
645                                 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
646                                         np = cp;
647                         }
648                 }
649 
650                 if (np == 0)
651                         return 0;
652 
653                 if (ret) {
654                         r = journal_file_move_to_object(f, OBJECT_ENTRY, np, ret);
655                         if (r < 0)
656                                 return r;
657                 }
658 
659                 if (offset)
660                         *offset = np;
661 
662                 return 1;
663 
664         } else {
665                 uint64_t np = 0;
666 
667                 assert(m->type == MATCH_AND_TERM);
668 
669                 /* First jump to the last match, and then find the
670                  * next one where all matches match */
671 
672                 if (!m->matches)
673                         return 0;
674 
675                 LIST_FOREACH(matches, i, m->matches) {
676                         uint64_t cp;
677 
678                         r = find_location_for_match(j, i, f, direction, NULL, &cp);
679                         if (r <= 0)
680                                 return r;
681 
682                         if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
683                                 np = cp;
684                 }
685 
686                 return next_for_match(j, m, f, np, direction, ret, offset);
687         }
688 }
689 
find_location_with_matches(sd_journal * j,JournalFile * f,direction_t direction,Object ** ret,uint64_t * offset)690 static int find_location_with_matches(
691                 sd_journal *j,
692                 JournalFile *f,
693                 direction_t direction,
694                 Object **ret,
695                 uint64_t *offset) {
696 
697         int r;
698 
699         assert(j);
700         assert(f);
701         assert(ret);
702         assert(offset);
703 
704         if (!j->level0) {
705                 /* No matches is simple */
706 
707                 if (j->current_location.type == LOCATION_HEAD)
708                         return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset);
709                 if (j->current_location.type == LOCATION_TAIL)
710                         return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset);
711                 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
712                         return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
713                 if (j->current_location.monotonic_set) {
714                         r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
715                         if (r != -ENOENT)
716                                 return r;
717                 }
718                 if (j->current_location.realtime_set)
719                         return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset);
720 
721                 return journal_file_next_entry(f, 0, direction, ret, offset);
722         } else
723                 return find_location_for_match(j, j->level0, f, direction, ret, offset);
724 }
725 
next_with_matches(sd_journal * j,JournalFile * f,direction_t direction,Object ** ret,uint64_t * offset)726 static int next_with_matches(
727                 sd_journal *j,
728                 JournalFile *f,
729                 direction_t direction,
730                 Object **ret,
731                 uint64_t *offset) {
732 
733         assert(j);
734         assert(f);
735         assert(ret);
736         assert(offset);
737 
738         /* No matches is easy. We simple advance the file
739          * pointer by one. */
740         if (!j->level0)
741                 return journal_file_next_entry(f, f->current_offset, direction, ret, offset);
742 
743         /* If we have a match then we look for the next matching entry
744          * with an offset at least one step larger */
745         return next_for_match(j, j->level0, f,
746                               direction == DIRECTION_DOWN ? f->current_offset + 1
747                                                           : f->current_offset - 1,
748                               direction, ret, offset);
749 }
750 
next_beyond_location(sd_journal * j,JournalFile * f,direction_t direction)751 static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) {
752         Object *c;
753         uint64_t cp, n_entries;
754         int r;
755 
756         assert(j);
757         assert(f);
758 
759         n_entries = le64toh(f->header->n_entries);
760 
761         /* If we hit EOF before, we don't need to look into this file again
762          * unless direction changed or new entries appeared. */
763         if (f->last_direction == direction && f->location_type == LOCATION_TAIL &&
764             n_entries == f->last_n_entries)
765                 return 0;
766 
767         f->last_n_entries = n_entries;
768 
769         if (f->last_direction == direction && f->current_offset > 0) {
770                 /* LOCATION_SEEK here means we did the work in a previous
771                  * iteration and the current location already points to a
772                  * candidate entry. */
773                 if (f->location_type != LOCATION_SEEK) {
774                         r = next_with_matches(j, f, direction, &c, &cp);
775                         if (r <= 0)
776                                 return r;
777 
778                         journal_file_save_location(f, c, cp);
779                 }
780         } else {
781                 f->last_direction = direction;
782 
783                 r = find_location_with_matches(j, f, direction, &c, &cp);
784                 if (r <= 0)
785                         return r;
786 
787                 journal_file_save_location(f, c, cp);
788         }
789 
790         /* OK, we found the spot, now let's advance until an entry
791          * that is actually different from what we were previously
792          * looking at. This is necessary to handle entries which exist
793          * in two (or more) journal files, and which shall all be
794          * suppressed but one. */
795 
796         for (;;) {
797                 bool found;
798 
799                 if (j->current_location.type == LOCATION_DISCRETE) {
800                         int k;
801 
802                         k = compare_with_location(f, &j->current_location, j->current_file);
803 
804                         found = direction == DIRECTION_DOWN ? k > 0 : k < 0;
805                 } else
806                         found = true;
807 
808                 if (found)
809                         return 1;
810 
811                 r = next_with_matches(j, f, direction, &c, &cp);
812                 if (r <= 0)
813                         return r;
814 
815                 journal_file_save_location(f, c, cp);
816         }
817 }
818 
real_journal_next(sd_journal * j,direction_t direction)819 static int real_journal_next(sd_journal *j, direction_t direction) {
820         JournalFile *new_file = NULL;
821         unsigned i, n_files;
822         const void **files;
823         Object *o;
824         int r;
825 
826         assert_return(j, -EINVAL);
827         assert_return(!journal_pid_changed(j), -ECHILD);
828 
829         r = iterated_cache_get(j->files_cache, NULL, &files, &n_files);
830         if (r < 0)
831                 return r;
832 
833         for (i = 0; i < n_files; i++) {
834                 JournalFile *f = (JournalFile *)files[i];
835                 bool found;
836 
837                 r = next_beyond_location(j, f, direction);
838                 if (r < 0) {
839                         log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path);
840                         remove_file_real(j, f);
841                         continue;
842                 } else if (r == 0) {
843                         f->location_type = LOCATION_TAIL;
844                         continue;
845                 }
846 
847                 if (!new_file)
848                         found = true;
849                 else {
850                         int k;
851 
852                         k = journal_file_compare_locations(f, new_file);
853 
854                         found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
855                 }
856 
857                 if (found)
858                         new_file = f;
859         }
860 
861         if (!new_file)
862                 return 0;
863 
864         r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o);
865         if (r < 0)
866                 return r;
867 
868         set_location(j, new_file, o);
869 
870         return 1;
871 }
872 
sd_journal_next(sd_journal * j)873 _public_ int sd_journal_next(sd_journal *j) {
874         return real_journal_next(j, DIRECTION_DOWN);
875 }
876 
sd_journal_previous(sd_journal * j)877 _public_ int sd_journal_previous(sd_journal *j) {
878         return real_journal_next(j, DIRECTION_UP);
879 }
880 
real_journal_next_skip(sd_journal * j,direction_t direction,uint64_t skip)881 static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
882         int c = 0, r;
883 
884         assert_return(j, -EINVAL);
885         assert_return(!journal_pid_changed(j), -ECHILD);
886         assert_return(skip <= INT_MAX, -ERANGE);
887 
888         if (skip == 0) {
889                 /* If this is not a discrete skip, then at least
890                  * resolve the current location */
891                 if (j->current_location.type != LOCATION_DISCRETE) {
892                         r = real_journal_next(j, direction);
893                         if (r < 0)
894                                 return r;
895                 }
896 
897                 return 0;
898         }
899 
900         do {
901                 r = real_journal_next(j, direction);
902                 if (r < 0)
903                         return r;
904 
905                 if (r == 0)
906                         return c;
907 
908                 skip--;
909                 c++;
910         } while (skip > 0);
911 
912         return c;
913 }
914 
sd_journal_next_skip(sd_journal * j,uint64_t skip)915 _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
916         return real_journal_next_skip(j, DIRECTION_DOWN, skip);
917 }
918 
sd_journal_previous_skip(sd_journal * j,uint64_t skip)919 _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
920         return real_journal_next_skip(j, DIRECTION_UP, skip);
921 }
922 
sd_journal_get_cursor(sd_journal * j,char ** cursor)923 _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
924         Object *o;
925         int r;
926 
927         assert_return(j, -EINVAL);
928         assert_return(!journal_pid_changed(j), -ECHILD);
929         assert_return(cursor, -EINVAL);
930 
931         if (!j->current_file || j->current_file->current_offset <= 0)
932                 return -EADDRNOTAVAIL;
933 
934         r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
935         if (r < 0)
936                 return r;
937 
938         if (asprintf(cursor,
939                      "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
940                      SD_ID128_TO_STRING(j->current_file->header->seqnum_id), le64toh(o->entry.seqnum),
941                      SD_ID128_TO_STRING(o->entry.boot_id), le64toh(o->entry.monotonic),
942                      le64toh(o->entry.realtime),
943                      le64toh(o->entry.xor_hash)) < 0)
944                 return -ENOMEM;
945 
946         return 0;
947 }
948 
sd_journal_seek_cursor(sd_journal * j,const char * cursor)949 _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
950         unsigned long long seqnum, monotonic, realtime, xor_hash;
951         bool seqnum_id_set = false,
952              seqnum_set = false,
953              boot_id_set = false,
954              monotonic_set = false,
955              realtime_set = false,
956              xor_hash_set = false;
957         sd_id128_t seqnum_id, boot_id;
958         int r;
959 
960         assert_return(j, -EINVAL);
961         assert_return(!journal_pid_changed(j), -ECHILD);
962         assert_return(!isempty(cursor), -EINVAL);
963 
964         for (const char *p = cursor;;) {
965                 _cleanup_free_ char *word = NULL;
966 
967                 r = extract_first_word(&p, &word, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
968                 if (r < 0)
969                         return r;
970                 if (r == 0)
971                         break;
972 
973                 if (word[0] == '\0' || word[1] != '=')
974                         return -EINVAL;
975 
976                 switch (word[0]) {
977                 case 's':
978                         seqnum_id_set = true;
979                         r = sd_id128_from_string(word + 2, &seqnum_id);
980                         if (r < 0)
981                                 return r;
982                         break;
983 
984                 case 'i':
985                         seqnum_set = true;
986                         if (sscanf(word + 2, "%llx", &seqnum) != 1)
987                                 return -EINVAL;
988                         break;
989 
990                 case 'b':
991                         boot_id_set = true;
992                         r = sd_id128_from_string(word + 2, &boot_id);
993                         break;
994 
995                 case 'm':
996                         monotonic_set = true;
997                         if (sscanf(word + 2, "%llx", &monotonic) != 1)
998                                 return -EINVAL;
999                         break;
1000 
1001                 case 't':
1002                         realtime_set = true;
1003                         if (sscanf(word + 2, "%llx", &realtime) != 1)
1004                                 return -EINVAL;
1005                         break;
1006 
1007                 case 'x':
1008                         xor_hash_set = true;
1009                         if (sscanf(word + 2, "%llx", &xor_hash) != 1)
1010                                 return -EINVAL;
1011                         break;
1012                 }
1013         }
1014 
1015         if ((!seqnum_set || !seqnum_id_set) &&
1016             (!monotonic_set || !boot_id_set) &&
1017             !realtime_set)
1018                 return -EINVAL;
1019 
1020         detach_location(j);
1021         j->current_location = (Location) {
1022                 .type = LOCATION_SEEK,
1023         };
1024 
1025         if (realtime_set) {
1026                 j->current_location.realtime = (uint64_t) realtime;
1027                 j->current_location.realtime_set = true;
1028         }
1029 
1030         if (seqnum_set && seqnum_id_set) {
1031                 j->current_location.seqnum = (uint64_t) seqnum;
1032                 j->current_location.seqnum_id = seqnum_id;
1033                 j->current_location.seqnum_set = true;
1034         }
1035 
1036         if (monotonic_set && boot_id_set) {
1037                 j->current_location.monotonic = (uint64_t) monotonic;
1038                 j->current_location.boot_id = boot_id;
1039                 j->current_location.monotonic_set = true;
1040         }
1041 
1042         if (xor_hash_set) {
1043                 j->current_location.xor_hash = (uint64_t) xor_hash;
1044                 j->current_location.xor_hash_set = true;
1045         }
1046 
1047         return 0;
1048 }
1049 
sd_journal_test_cursor(sd_journal * j,const char * cursor)1050 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
1051         int r;
1052         Object *o;
1053 
1054         assert_return(j, -EINVAL);
1055         assert_return(!journal_pid_changed(j), -ECHILD);
1056         assert_return(!isempty(cursor), -EINVAL);
1057 
1058         if (!j->current_file || j->current_file->current_offset <= 0)
1059                 return -EADDRNOTAVAIL;
1060 
1061         r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
1062         if (r < 0)
1063                 return r;
1064 
1065         for (;;) {
1066                 _cleanup_free_ char *item = NULL;
1067                 unsigned long long ll;
1068                 sd_id128_t id;
1069                 int k = 0;
1070 
1071                 r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
1072                 if (r < 0)
1073                         return r;
1074 
1075                 if (r == 0)
1076                         break;
1077 
1078                 if (strlen(item) < 2 || item[1] != '=')
1079                         return -EINVAL;
1080 
1081                 switch (item[0]) {
1082 
1083                 case 's':
1084                         k = sd_id128_from_string(item+2, &id);
1085                         if (k < 0)
1086                                 return k;
1087                         if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
1088                                 return 0;
1089                         break;
1090 
1091                 case 'i':
1092                         if (sscanf(item+2, "%llx", &ll) != 1)
1093                                 return -EINVAL;
1094                         if (ll != le64toh(o->entry.seqnum))
1095                                 return 0;
1096                         break;
1097 
1098                 case 'b':
1099                         k = sd_id128_from_string(item+2, &id);
1100                         if (k < 0)
1101                                 return k;
1102                         if (!sd_id128_equal(id, o->entry.boot_id))
1103                                 return 0;
1104                         break;
1105 
1106                 case 'm':
1107                         if (sscanf(item+2, "%llx", &ll) != 1)
1108                                 return -EINVAL;
1109                         if (ll != le64toh(o->entry.monotonic))
1110                                 return 0;
1111                         break;
1112 
1113                 case 't':
1114                         if (sscanf(item+2, "%llx", &ll) != 1)
1115                                 return -EINVAL;
1116                         if (ll != le64toh(o->entry.realtime))
1117                                 return 0;
1118                         break;
1119 
1120                 case 'x':
1121                         if (sscanf(item+2, "%llx", &ll) != 1)
1122                                 return -EINVAL;
1123                         if (ll != le64toh(o->entry.xor_hash))
1124                                 return 0;
1125                         break;
1126                 }
1127         }
1128 
1129         return 1;
1130 }
1131 
sd_journal_seek_monotonic_usec(sd_journal * j,sd_id128_t boot_id,uint64_t usec)1132 _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
1133         assert_return(j, -EINVAL);
1134         assert_return(!journal_pid_changed(j), -ECHILD);
1135 
1136         detach_location(j);
1137 
1138         j->current_location = (Location) {
1139                 .type = LOCATION_SEEK,
1140                 .boot_id = boot_id,
1141                 .monotonic = usec,
1142                 .monotonic_set = true,
1143         };
1144 
1145         return 0;
1146 }
1147 
sd_journal_seek_realtime_usec(sd_journal * j,uint64_t usec)1148 _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
1149         assert_return(j, -EINVAL);
1150         assert_return(!journal_pid_changed(j), -ECHILD);
1151 
1152         detach_location(j);
1153 
1154         j->current_location = (Location) {
1155                 .type = LOCATION_SEEK,
1156                 .realtime = usec,
1157                 .realtime_set = true,
1158         };
1159 
1160         return 0;
1161 }
1162 
sd_journal_seek_head(sd_journal * j)1163 _public_ int sd_journal_seek_head(sd_journal *j) {
1164         assert_return(j, -EINVAL);
1165         assert_return(!journal_pid_changed(j), -ECHILD);
1166 
1167         detach_location(j);
1168 
1169         j->current_location = (Location) {
1170                 .type = LOCATION_HEAD,
1171         };
1172 
1173         return 0;
1174 }
1175 
sd_journal_seek_tail(sd_journal * j)1176 _public_ int sd_journal_seek_tail(sd_journal *j) {
1177         assert_return(j, -EINVAL);
1178         assert_return(!journal_pid_changed(j), -ECHILD);
1179 
1180         detach_location(j);
1181 
1182         j->current_location = (Location) {
1183                 .type = LOCATION_TAIL,
1184         };
1185 
1186         return 0;
1187 }
1188 
check_network(sd_journal * j,int fd)1189 static void check_network(sd_journal *j, int fd) {
1190         assert(j);
1191 
1192         if (j->on_network)
1193                 return;
1194 
1195         j->on_network = fd_is_network_fs(fd);
1196 }
1197 
file_has_type_prefix(const char * prefix,const char * filename)1198 static bool file_has_type_prefix(const char *prefix, const char *filename) {
1199         const char *full, *tilded, *atted;
1200 
1201         full = strjoina(prefix, ".journal");
1202         tilded = strjoina(full, "~");
1203         atted = strjoina(prefix, "@");
1204 
1205         return STR_IN_SET(filename, full, tilded) ||
1206                startswith(filename, atted);
1207 }
1208 
file_type_wanted(int flags,const char * filename)1209 static bool file_type_wanted(int flags, const char *filename) {
1210         assert(filename);
1211 
1212         if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
1213                 return false;
1214 
1215         /* no flags set → every type is OK */
1216         if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
1217                 return true;
1218 
1219         if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
1220                 return true;
1221 
1222         if (flags & SD_JOURNAL_CURRENT_USER) {
1223                 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
1224 
1225                 xsprintf(prefix, "user-"UID_FMT, getuid());
1226 
1227                 if (file_has_type_prefix(prefix, filename))
1228                         return true;
1229         }
1230 
1231         return false;
1232 }
1233 
path_has_prefix(sd_journal * j,const char * path,const char * prefix)1234 static bool path_has_prefix(sd_journal *j, const char *path, const char *prefix) {
1235         assert(j);
1236         assert(path);
1237         assert(prefix);
1238 
1239         if (j->toplevel_fd >= 0)
1240                 return false;
1241 
1242         return path_startswith(path, prefix);
1243 }
1244 
track_file_disposition(sd_journal * j,JournalFile * f)1245 static void track_file_disposition(sd_journal *j, JournalFile *f) {
1246         assert(j);
1247         assert(f);
1248 
1249         if (!j->has_runtime_files && path_has_prefix(j, f->path, "/run"))
1250                 j->has_runtime_files = true;
1251         else if (!j->has_persistent_files && path_has_prefix(j, f->path, "/var"))
1252                 j->has_persistent_files = true;
1253 }
1254 
skip_slash(const char * p)1255 static const char *skip_slash(const char *p) {
1256 
1257         if (!p)
1258                 return NULL;
1259 
1260         while (*p == '/')
1261                 p++;
1262 
1263         return p;
1264 }
1265 
add_any_file(sd_journal * j,int fd,const char * path)1266 static int add_any_file(
1267                 sd_journal *j,
1268                 int fd,
1269                 const char *path) {
1270 
1271         bool close_fd = false;
1272         JournalFile *f;
1273         struct stat st;
1274         int r, k;
1275 
1276         assert(j);
1277         assert(fd >= 0 || path);
1278 
1279         if (fd < 0) {
1280                 if (j->toplevel_fd >= 0)
1281                         /* If there's a top-level fd defined make the path relative, explicitly, since otherwise
1282                          * openat() ignores the first argument. */
1283 
1284                         fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC|O_NONBLOCK);
1285                 else
1286                         fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
1287                 if (fd < 0) {
1288                         r = log_debug_errno(errno, "Failed to open journal file %s: %m", path);
1289                         goto finish;
1290                 }
1291 
1292                 close_fd = true;
1293 
1294                 r = fd_nonblock(fd, false);
1295                 if (r < 0) {
1296                         r = log_debug_errno(errno, "Failed to turn off O_NONBLOCK for %s: %m", path);
1297                         goto finish;
1298                 }
1299         }
1300 
1301         if (fstat(fd, &st) < 0) {
1302                 r = log_debug_errno(errno, "Failed to fstat file '%s': %m", path);
1303                 goto finish;
1304         }
1305 
1306         r = stat_verify_regular(&st);
1307         if (r < 0) {
1308                 log_debug_errno(r, "Refusing to open '%s', as it is not a regular file.", path);
1309                 goto finish;
1310         }
1311 
1312         f = ordered_hashmap_get(j->files, path);
1313         if (f) {
1314                 if (stat_inode_same(&f->last_stat, &st)) {
1315 
1316                         /* We already track this file, under the same path and with the same device/inode numbers, it's
1317                          * hence really the same. Mark this file as seen in this generation. This is used to GC old
1318                          * files in process_q_overflow() to detect journal files that are still there and discern them
1319                          * from those which are gone. */
1320 
1321                         f->last_seen_generation = j->generation;
1322                         r = 0;
1323                         goto finish;
1324                 }
1325 
1326                 /* So we tracked a file under this name, but it has a different inode/device. In that case, it got
1327                  * replaced (probably due to rotation?), let's drop it hence from our list. */
1328                 remove_file_real(j, f);
1329                 f = NULL;
1330         }
1331 
1332         if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
1333                 log_debug("Too many open journal files, not adding %s.", path);
1334                 r = -ETOOMANYREFS;
1335                 goto finish;
1336         }
1337 
1338         r = journal_file_open(fd, path, O_RDONLY, 0, 0, 0, NULL, j->mmap, NULL, &f);
1339         if (r < 0) {
1340                 log_debug_errno(r, "Failed to open journal file %s: %m", path);
1341                 goto finish;
1342         }
1343 
1344         /* journal_file_dump(f); */
1345 
1346         r = ordered_hashmap_put(j->files, f->path, f);
1347         if (r < 0) {
1348                 f->close_fd = false; /* make sure journal_file_close() doesn't close the caller's fd (or our own). We'll let the caller do that, or ourselves */
1349                 (void) journal_file_close(f);
1350                 goto finish;
1351         }
1352 
1353         close_fd = false; /* the fd is now owned by the JournalFile object */
1354 
1355         f->last_seen_generation = j->generation;
1356 
1357         track_file_disposition(j, f);
1358         check_network(j, f->fd);
1359 
1360         j->current_invalidate_counter++;
1361 
1362         log_debug("File %s added.", f->path);
1363 
1364         r = 0;
1365 
1366 finish:
1367         if (close_fd)
1368                 safe_close(fd);
1369 
1370         if (r < 0) {
1371                 k = journal_put_error(j, r, path);
1372                 if (k < 0)
1373                         return k;
1374         }
1375 
1376         return r;
1377 }
1378 
add_file_by_name(sd_journal * j,const char * prefix,const char * filename)1379 static int add_file_by_name(
1380                 sd_journal *j,
1381                 const char *prefix,
1382                 const char *filename) {
1383 
1384         const char *path;
1385 
1386         assert(j);
1387         assert(prefix);
1388         assert(filename);
1389 
1390         if (j->no_new_files)
1391                 return 0;
1392 
1393         if (!file_type_wanted(j->flags, filename))
1394                 return 0;
1395 
1396         path = prefix_roota(prefix, filename);
1397         return add_any_file(j, -1, path);
1398 }
1399 
remove_file_by_name(sd_journal * j,const char * prefix,const char * filename)1400 static void remove_file_by_name(
1401                 sd_journal *j,
1402                 const char *prefix,
1403                 const char *filename) {
1404 
1405         const char *path;
1406         JournalFile *f;
1407 
1408         assert(j);
1409         assert(prefix);
1410         assert(filename);
1411 
1412         path = prefix_roota(prefix, filename);
1413         f = ordered_hashmap_get(j->files, path);
1414         if (!f)
1415                 return;
1416 
1417         remove_file_real(j, f);
1418 }
1419 
remove_file_real(sd_journal * j,JournalFile * f)1420 static void remove_file_real(sd_journal *j, JournalFile *f) {
1421         assert(j);
1422         assert(f);
1423 
1424         (void) ordered_hashmap_remove(j->files, f->path);
1425 
1426         log_debug("File %s removed.", f->path);
1427 
1428         if (j->current_file == f) {
1429                 j->current_file = NULL;
1430                 j->current_field = 0;
1431         }
1432 
1433         if (j->unique_file == f) {
1434                 /* Jump to the next unique_file or NULL if that one was last */
1435                 j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
1436                 j->unique_offset = 0;
1437                 if (!j->unique_file)
1438                         j->unique_file_lost = true;
1439         }
1440 
1441         if (j->fields_file == f) {
1442                 j->fields_file = ordered_hashmap_next(j->files, j->fields_file->path);
1443                 j->fields_offset = 0;
1444                 if (!j->fields_file)
1445                         j->fields_file_lost = true;
1446         }
1447 
1448         (void) journal_file_close(f);
1449 
1450         j->current_invalidate_counter++;
1451 }
1452 
dirname_is_machine_id(const char * fn)1453 static int dirname_is_machine_id(const char *fn) {
1454         sd_id128_t id, machine;
1455         const char *e;
1456         int r;
1457 
1458         /* Returns true if the specified directory name matches the local machine ID */
1459 
1460         r = sd_id128_get_machine(&machine);
1461         if (r < 0)
1462                 return r;
1463 
1464         e = strchr(fn, '.');
1465         if (e) {
1466                 const char *k;
1467 
1468                 /* Looks like it has a namespace suffix. Verify that. */
1469                 if (!log_namespace_name_valid(e + 1))
1470                         return false;
1471 
1472                 k = strndupa_safe(fn, e - fn);
1473                 r = sd_id128_from_string(k, &id);
1474         } else
1475                 r = sd_id128_from_string(fn, &id);
1476         if (r < 0)
1477                 return r;
1478 
1479         return sd_id128_equal(id, machine);
1480 }
1481 
dirname_has_namespace(const char * fn,const char * namespace)1482 static int dirname_has_namespace(const char *fn, const char *namespace) {
1483         const char *e;
1484 
1485         /* Returns true if the specified directory name matches the specified namespace */
1486 
1487         e = strchr(fn, '.');
1488         if (e) {
1489                 const char *k;
1490 
1491                 if (!namespace)
1492                         return false;
1493 
1494                 if (!streq(e + 1, namespace))
1495                         return false;
1496 
1497                 k = strndupa_safe(fn, e - fn);
1498                 return id128_is_valid(k);
1499         }
1500 
1501         if (namespace)
1502                 return false;
1503 
1504         return id128_is_valid(fn);
1505 }
1506 
dirent_is_journal_file(const struct dirent * de)1507 static bool dirent_is_journal_file(const struct dirent *de) {
1508         assert(de);
1509 
1510         /* Returns true if the specified directory entry looks like a journal file we might be interested in */
1511 
1512         if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN))
1513                 return false;
1514 
1515         return endswith(de->d_name, ".journal") ||
1516                 endswith(de->d_name, ".journal~");
1517 }
1518 
dirent_is_journal_subdir(const struct dirent * de)1519 static bool dirent_is_journal_subdir(const struct dirent *de) {
1520         const char *e, *n;
1521         assert(de);
1522 
1523         /* returns true if the specified directory entry looks like a directory that might contain journal
1524          * files we might be interested in, i.e. is either a 128bit ID or a 128bit ID suffixed by a
1525          * namespace. */
1526 
1527         if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN))
1528                 return false;
1529 
1530         e = strchr(de->d_name, '.');
1531         if (!e)
1532                 return id128_is_valid(de->d_name); /* No namespace */
1533 
1534         n = strndupa_safe(de->d_name, e - de->d_name);
1535         if (!id128_is_valid(n))
1536                 return false;
1537 
1538         return log_namespace_name_valid(e + 1);
1539 }
1540 
directory_open(sd_journal * j,const char * path,DIR ** ret)1541 static int directory_open(sd_journal *j, const char *path, DIR **ret) {
1542         DIR *d;
1543 
1544         assert(j);
1545         assert(path);
1546         assert(ret);
1547 
1548         if (j->toplevel_fd < 0)
1549                 d = opendir(path);
1550         else
1551                 /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
1552                  * relative, by dropping the initial slash */
1553                 d = xopendirat(j->toplevel_fd, skip_slash(path), 0);
1554         if (!d)
1555                 return -errno;
1556 
1557         *ret = d;
1558         return 0;
1559 }
1560 
1561 static int add_directory(sd_journal *j, const char *prefix, const char *dirname);
1562 
directory_enumerate(sd_journal * j,Directory * m,DIR * d)1563 static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) {
1564         assert(j);
1565         assert(m);
1566         assert(d);
1567 
1568         FOREACH_DIRENT_ALL(de, d, goto fail) {
1569                 if (dirent_is_journal_file(de))
1570                         (void) add_file_by_name(j, m->path, de->d_name);
1571 
1572                 if (m->is_root && dirent_is_journal_subdir(de))
1573                         (void) add_directory(j, m->path, de->d_name);
1574         }
1575 
1576         return;
1577 fail:
1578         log_debug_errno(errno, "Failed to enumerate directory %s, ignoring: %m", m->path);
1579 }
1580 
directory_watch(sd_journal * j,Directory * m,int fd,uint32_t mask)1581 static void directory_watch(sd_journal *j, Directory *m, int fd, uint32_t mask) {
1582         int r;
1583 
1584         assert(j);
1585         assert(m);
1586         assert(fd >= 0);
1587 
1588         /* Watch this directory if that's enabled and if it not being watched yet. */
1589 
1590         if (m->wd > 0) /* Already have a watch? */
1591                 return;
1592         if (j->inotify_fd < 0) /* Not watching at all? */
1593                 return;
1594 
1595         m->wd = inotify_add_watch_fd(j->inotify_fd, fd, mask);
1596         if (m->wd < 0) {
1597                 log_debug_errno(errno, "Failed to watch journal directory '%s', ignoring: %m", m->path);
1598                 return;
1599         }
1600 
1601         r = hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m);
1602         if (r == -EEXIST)
1603                 log_debug_errno(r, "Directory '%s' already being watched under a different path, ignoring: %m", m->path);
1604         if (r < 0) {
1605                 log_debug_errno(r, "Failed to add watch for journal directory '%s' to hashmap, ignoring: %m", m->path);
1606                 (void) inotify_rm_watch(j->inotify_fd, m->wd);
1607                 m->wd = -1;
1608         }
1609 }
1610 
add_directory(sd_journal * j,const char * prefix,const char * dirname)1611 static int add_directory(
1612                 sd_journal *j,
1613                 const char *prefix,
1614                 const char *dirname) {
1615 
1616         _cleanup_free_ char *path = NULL;
1617         _cleanup_closedir_ DIR *d = NULL;
1618         Directory *m;
1619         int r, k;
1620 
1621         assert(j);
1622         assert(prefix);
1623 
1624         /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
1625          * and reenumerates directory contents */
1626 
1627         path = path_join(prefix, dirname);
1628         if (!path) {
1629                 r = -ENOMEM;
1630                 goto fail;
1631         }
1632 
1633         log_debug("Considering directory '%s'.", path);
1634 
1635         /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
1636         if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
1637             !((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
1638                 return 0;
1639 
1640         if (dirname &&
1641             (!(FLAGS_SET(j->flags, SD_JOURNAL_ALL_NAMESPACES) ||
1642                dirname_has_namespace(dirname, j->namespace) > 0 ||
1643                (FLAGS_SET(j->flags, SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE) && dirname_has_namespace(dirname, NULL) > 0))))
1644                 return 0;
1645 
1646         r = directory_open(j, path, &d);
1647         if (r < 0) {
1648                 log_debug_errno(r, "Failed to open directory '%s': %m", path);
1649                 goto fail;
1650         }
1651 
1652         m = hashmap_get(j->directories_by_path, path);
1653         if (!m) {
1654                 m = new(Directory, 1);
1655                 if (!m) {
1656                         r = -ENOMEM;
1657                         goto fail;
1658                 }
1659 
1660                 *m = (Directory) {
1661                         .is_root = false,
1662                         .path = path,
1663                 };
1664 
1665                 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1666                         free(m);
1667                         r = -ENOMEM;
1668                         goto fail;
1669                 }
1670 
1671                 path = NULL; /* avoid freeing in cleanup */
1672                 j->current_invalidate_counter++;
1673 
1674                 log_debug("Directory %s added.", m->path);
1675 
1676         } else if (m->is_root)
1677                 return 0; /* Don't 'downgrade' from root directory */
1678 
1679         m->last_seen_generation = j->generation;
1680 
1681         directory_watch(j, m, dirfd(d),
1682                         IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1683                         IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
1684                         IN_ONLYDIR);
1685 
1686         if (!j->no_new_files)
1687                 directory_enumerate(j, m, d);
1688 
1689         check_network(j, dirfd(d));
1690 
1691         return 0;
1692 
1693 fail:
1694         k = journal_put_error(j, r, path ?: prefix);
1695         if (k < 0)
1696                 return k;
1697 
1698         return r;
1699 }
1700 
add_root_directory(sd_journal * j,const char * p,bool missing_ok)1701 static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
1702 
1703         _cleanup_closedir_ DIR *d = NULL;
1704         Directory *m;
1705         int r, k;
1706 
1707         assert(j);
1708 
1709         /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
1710          * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
1711          * populate the set, as well as to update it later. */
1712 
1713         if (p) {
1714                 /* If there's a path specified, use it. */
1715 
1716                 log_debug("Considering root directory '%s'.", p);
1717 
1718                 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
1719                     !path_has_prefix(j, p, "/run"))
1720                         return -EINVAL;
1721 
1722                 if (j->prefix)
1723                         p = strjoina(j->prefix, p);
1724 
1725                 r = directory_open(j, p, &d);
1726                 if (r == -ENOENT && missing_ok)
1727                         return 0;
1728                 if (r < 0) {
1729                         log_debug_errno(r, "Failed to open root directory %s: %m", p);
1730                         goto fail;
1731                 }
1732         } else {
1733                 _cleanup_close_ int dfd = -1;
1734 
1735                 /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
1736                  * opendir() will take possession of the fd, and close it, which we don't want. */
1737 
1738                 p = "."; /* store this as "." in the directories hashmap */
1739 
1740                 dfd = fcntl(j->toplevel_fd, F_DUPFD_CLOEXEC, 3);
1741                 if (dfd < 0) {
1742                         r = -errno;
1743                         goto fail;
1744                 }
1745 
1746                 d = take_fdopendir(&dfd);
1747                 if (!d) {
1748                         r = -errno;
1749                         goto fail;
1750                 }
1751 
1752                 rewinddir(d);
1753         }
1754 
1755         m = hashmap_get(j->directories_by_path, p);
1756         if (!m) {
1757                 m = new0(Directory, 1);
1758                 if (!m) {
1759                         r = -ENOMEM;
1760                         goto fail;
1761                 }
1762 
1763                 m->is_root = true;
1764 
1765                 m->path = strdup(p);
1766                 if (!m->path) {
1767                         free(m);
1768                         r = -ENOMEM;
1769                         goto fail;
1770                 }
1771 
1772                 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
1773                         free(m->path);
1774                         free(m);
1775                         r = -ENOMEM;
1776                         goto fail;
1777                 }
1778 
1779                 j->current_invalidate_counter++;
1780 
1781                 log_debug("Root directory %s added.", m->path);
1782 
1783         } else if (!m->is_root)
1784                 return 0;
1785 
1786         directory_watch(j, m, dirfd(d),
1787                         IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
1788                         IN_ONLYDIR);
1789 
1790         if (!j->no_new_files)
1791                 directory_enumerate(j, m, d);
1792 
1793         check_network(j, dirfd(d));
1794 
1795         return 0;
1796 
1797 fail:
1798         k = journal_put_error(j, r, p);
1799         if (k < 0)
1800                 return k;
1801 
1802         return r;
1803 }
1804 
remove_directory(sd_journal * j,Directory * d)1805 static void remove_directory(sd_journal *j, Directory *d) {
1806         assert(j);
1807 
1808         if (d->wd > 0) {
1809                 hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
1810 
1811                 if (j->inotify_fd >= 0)
1812                         (void) inotify_rm_watch(j->inotify_fd, d->wd);
1813         }
1814 
1815         hashmap_remove(j->directories_by_path, d->path);
1816 
1817         if (d->is_root)
1818                 log_debug("Root directory %s removed.", d->path);
1819         else
1820                 log_debug("Directory %s removed.", d->path);
1821 
1822         free(d->path);
1823         free(d);
1824 }
1825 
add_search_paths(sd_journal * j)1826 static int add_search_paths(sd_journal *j) {
1827 
1828         static const char search_paths[] =
1829                 "/run/log/journal\0"
1830                 "/var/log/journal\0";
1831         const char *p;
1832 
1833         assert(j);
1834 
1835         /* We ignore most errors here, since the idea is to only open
1836          * what's actually accessible, and ignore the rest. */
1837 
1838         NULSTR_FOREACH(p, search_paths)
1839                 (void) add_root_directory(j, p, true);
1840 
1841         if (!(j->flags & SD_JOURNAL_LOCAL_ONLY))
1842                 (void) add_root_directory(j, "/var/log/journal/remote", true);
1843 
1844         return 0;
1845 }
1846 
add_current_paths(sd_journal * j)1847 static int add_current_paths(sd_journal *j) {
1848         JournalFile *f;
1849 
1850         assert(j);
1851         assert(j->no_new_files);
1852 
1853         /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
1854          * treat them as fatal. */
1855 
1856         ORDERED_HASHMAP_FOREACH(f, j->files) {
1857                 _cleanup_free_ char *dir = NULL;
1858                 int r;
1859 
1860                 dir = dirname_malloc(f->path);
1861                 if (!dir)
1862                         return -ENOMEM;
1863 
1864                 r = add_directory(j, dir, NULL);
1865                 if (r < 0)
1866                         return r;
1867         }
1868 
1869         return 0;
1870 }
1871 
allocate_inotify(sd_journal * j)1872 static int allocate_inotify(sd_journal *j) {
1873         assert(j);
1874 
1875         if (j->inotify_fd < 0) {
1876                 j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1877                 if (j->inotify_fd < 0)
1878                         return -errno;
1879         }
1880 
1881         return hashmap_ensure_allocated(&j->directories_by_wd, NULL);
1882 }
1883 
journal_new(int flags,const char * path,const char * namespace)1884 static sd_journal *journal_new(int flags, const char *path, const char *namespace) {
1885         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
1886 
1887         j = new0(sd_journal, 1);
1888         if (!j)
1889                 return NULL;
1890 
1891         j->original_pid = getpid_cached();
1892         j->toplevel_fd = -1;
1893         j->inotify_fd = -1;
1894         j->flags = flags;
1895         j->data_threshold = DEFAULT_DATA_THRESHOLD;
1896 
1897         if (path) {
1898                 char *t;
1899 
1900                 t = strdup(path);
1901                 if (!t)
1902                         return NULL;
1903 
1904                 if (flags & SD_JOURNAL_OS_ROOT)
1905                         j->prefix = t;
1906                 else
1907                         j->path = t;
1908         }
1909 
1910         if (namespace) {
1911                 j->namespace = strdup(namespace);
1912                 if (!j->namespace)
1913                         return NULL;
1914         }
1915 
1916         j->files = ordered_hashmap_new(&path_hash_ops);
1917         if (!j->files)
1918                 return NULL;
1919 
1920         j->files_cache = ordered_hashmap_iterated_cache_new(j->files);
1921         j->directories_by_path = hashmap_new(&path_hash_ops);
1922         j->mmap = mmap_cache_new();
1923         if (!j->files_cache || !j->directories_by_path || !j->mmap)
1924                 return NULL;
1925 
1926         return TAKE_PTR(j);
1927 }
1928 
1929 #define OPEN_ALLOWED_FLAGS                              \
1930         (SD_JOURNAL_LOCAL_ONLY |                        \
1931          SD_JOURNAL_RUNTIME_ONLY |                      \
1932          SD_JOURNAL_SYSTEM |                            \
1933          SD_JOURNAL_CURRENT_USER |                      \
1934          SD_JOURNAL_ALL_NAMESPACES |                    \
1935          SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE)
1936 
sd_journal_open_namespace(sd_journal ** ret,const char * namespace,int flags)1937 _public_ int sd_journal_open_namespace(sd_journal **ret, const char *namespace, int flags) {
1938         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
1939         int r;
1940 
1941         assert_return(ret, -EINVAL);
1942         assert_return((flags & ~OPEN_ALLOWED_FLAGS) == 0, -EINVAL);
1943 
1944         j = journal_new(flags, NULL, namespace);
1945         if (!j)
1946                 return -ENOMEM;
1947 
1948         r = add_search_paths(j);
1949         if (r < 0)
1950                 return r;
1951 
1952         *ret = TAKE_PTR(j);
1953         return 0;
1954 }
1955 
sd_journal_open(sd_journal ** ret,int flags)1956 _public_ int sd_journal_open(sd_journal **ret, int flags) {
1957         return sd_journal_open_namespace(ret, NULL, flags);
1958 }
1959 
1960 #define OPEN_CONTAINER_ALLOWED_FLAGS                    \
1961         (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
1962 
sd_journal_open_container(sd_journal ** ret,const char * machine,int flags)1963 _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
1964         _cleanup_free_ char *root = NULL, *class = NULL;
1965         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
1966         char *p;
1967         int r;
1968 
1969         /* This is deprecated, people should use machined's OpenMachineRootDirectory() call instead in
1970          * combination with sd_journal_open_directory_fd(). */
1971 
1972         assert_return(machine, -EINVAL);
1973         assert_return(ret, -EINVAL);
1974         assert_return((flags & ~OPEN_CONTAINER_ALLOWED_FLAGS) == 0, -EINVAL);
1975         assert_return(hostname_is_valid(machine, 0), -EINVAL);
1976 
1977         p = strjoina("/run/systemd/machines/", machine);
1978         r = parse_env_file(NULL, p,
1979                            "ROOT", &root,
1980                            "CLASS", &class);
1981         if (r == -ENOENT)
1982                 return -EHOSTDOWN;
1983         if (r < 0)
1984                 return r;
1985         if (!root)
1986                 return -ENODATA;
1987 
1988         if (!streq_ptr(class, "container"))
1989                 return -EIO;
1990 
1991         j = journal_new(flags, root, NULL);
1992         if (!j)
1993                 return -ENOMEM;
1994 
1995         r = add_search_paths(j);
1996         if (r < 0)
1997                 return r;
1998 
1999         *ret = TAKE_PTR(j);
2000         return 0;
2001 }
2002 
2003 #define OPEN_DIRECTORY_ALLOWED_FLAGS                    \
2004         (SD_JOURNAL_OS_ROOT |                           \
2005          SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
2006 
sd_journal_open_directory(sd_journal ** ret,const char * path,int flags)2007 _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
2008         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
2009         int r;
2010 
2011         assert_return(ret, -EINVAL);
2012         assert_return(path, -EINVAL);
2013         assert_return((flags & ~OPEN_DIRECTORY_ALLOWED_FLAGS) == 0, -EINVAL);
2014 
2015         j = journal_new(flags, path, NULL);
2016         if (!j)
2017                 return -ENOMEM;
2018 
2019         if (flags & SD_JOURNAL_OS_ROOT)
2020                 r = add_search_paths(j);
2021         else
2022                 r = add_root_directory(j, path, false);
2023         if (r < 0)
2024                 return r;
2025 
2026         *ret = TAKE_PTR(j);
2027         return 0;
2028 }
2029 
sd_journal_open_files(sd_journal ** ret,const char ** paths,int flags)2030 _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
2031         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
2032         int r;
2033 
2034         assert_return(ret, -EINVAL);
2035         assert_return(flags == 0, -EINVAL);
2036 
2037         j = journal_new(flags, NULL, NULL);
2038         if (!j)
2039                 return -ENOMEM;
2040 
2041         STRV_FOREACH(path, paths) {
2042                 r = add_any_file(j, -1, *path);
2043                 if (r < 0)
2044                         return r;
2045         }
2046 
2047         j->no_new_files = true;
2048 
2049         *ret = TAKE_PTR(j);
2050         return 0;
2051 }
2052 
2053 #define OPEN_DIRECTORY_FD_ALLOWED_FLAGS         \
2054         (SD_JOURNAL_OS_ROOT |                           \
2055          SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
2056 
sd_journal_open_directory_fd(sd_journal ** ret,int fd,int flags)2057 _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
2058         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
2059         struct stat st;
2060         int r;
2061 
2062         assert_return(ret, -EINVAL);
2063         assert_return(fd >= 0, -EBADF);
2064         assert_return((flags & ~OPEN_DIRECTORY_FD_ALLOWED_FLAGS) == 0, -EINVAL);
2065 
2066         if (fstat(fd, &st) < 0)
2067                 return -errno;
2068 
2069         if (!S_ISDIR(st.st_mode))
2070                 return -EBADFD;
2071 
2072         j = journal_new(flags, NULL, NULL);
2073         if (!j)
2074                 return -ENOMEM;
2075 
2076         j->toplevel_fd = fd;
2077 
2078         if (flags & SD_JOURNAL_OS_ROOT)
2079                 r = add_search_paths(j);
2080         else
2081                 r = add_root_directory(j, NULL, false);
2082         if (r < 0)
2083                 return r;
2084 
2085         *ret = TAKE_PTR(j);
2086         return 0;
2087 }
2088 
sd_journal_open_files_fd(sd_journal ** ret,int fds[],unsigned n_fds,int flags)2089 _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags) {
2090         JournalFile *f;
2091         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
2092         unsigned i;
2093         int r;
2094 
2095         assert_return(ret, -EINVAL);
2096         assert_return(n_fds > 0, -EBADF);
2097         assert_return(flags == 0, -EINVAL);
2098 
2099         j = journal_new(flags, NULL, NULL);
2100         if (!j)
2101                 return -ENOMEM;
2102 
2103         for (i = 0; i < n_fds; i++) {
2104                 struct stat st;
2105 
2106                 if (fds[i] < 0) {
2107                         r = -EBADF;
2108                         goto fail;
2109                 }
2110 
2111                 if (fstat(fds[i], &st) < 0) {
2112                         r = -errno;
2113                         goto fail;
2114                 }
2115 
2116                 r = stat_verify_regular(&st);
2117                 if (r < 0)
2118                         goto fail;
2119 
2120                 r = add_any_file(j, fds[i], NULL);
2121                 if (r < 0)
2122                         goto fail;
2123         }
2124 
2125         j->no_new_files = true;
2126         j->no_inotify = true;
2127 
2128         *ret = TAKE_PTR(j);
2129         return 0;
2130 
2131 fail:
2132         /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
2133          * remain open */
2134         ORDERED_HASHMAP_FOREACH(f, j->files)
2135                 f->close_fd = false;
2136 
2137         return r;
2138 }
2139 
sd_journal_close(sd_journal * j)2140 _public_ void sd_journal_close(sd_journal *j) {
2141         Directory *d;
2142 
2143         if (!j)
2144                 return;
2145 
2146         sd_journal_flush_matches(j);
2147 
2148         ordered_hashmap_free_with_destructor(j->files, journal_file_close);
2149         iterated_cache_free(j->files_cache);
2150 
2151         while ((d = hashmap_first(j->directories_by_path)))
2152                 remove_directory(j, d);
2153 
2154         while ((d = hashmap_first(j->directories_by_wd)))
2155                 remove_directory(j, d);
2156 
2157         hashmap_free(j->directories_by_path);
2158         hashmap_free(j->directories_by_wd);
2159 
2160         safe_close(j->inotify_fd);
2161 
2162         if (j->mmap) {
2163                 mmap_cache_stats_log_debug(j->mmap);
2164                 mmap_cache_unref(j->mmap);
2165         }
2166 
2167         hashmap_free_free(j->errors);
2168 
2169         free(j->path);
2170         free(j->prefix);
2171         free(j->namespace);
2172         free(j->unique_field);
2173         free(j->fields_buffer);
2174         free(j);
2175 }
2176 
sd_journal_get_realtime_usec(sd_journal * j,uint64_t * ret)2177 _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
2178         Object *o;
2179         JournalFile *f;
2180         int r;
2181 
2182         assert_return(j, -EINVAL);
2183         assert_return(!journal_pid_changed(j), -ECHILD);
2184         assert_return(ret, -EINVAL);
2185 
2186         f = j->current_file;
2187         if (!f)
2188                 return -EADDRNOTAVAIL;
2189 
2190         if (f->current_offset <= 0)
2191                 return -EADDRNOTAVAIL;
2192 
2193         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2194         if (r < 0)
2195                 return r;
2196 
2197         *ret = le64toh(o->entry.realtime);
2198         return 0;
2199 }
2200 
sd_journal_get_monotonic_usec(sd_journal * j,uint64_t * ret,sd_id128_t * ret_boot_id)2201 _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
2202         Object *o;
2203         JournalFile *f;
2204         int r;
2205 
2206         assert_return(j, -EINVAL);
2207         assert_return(!journal_pid_changed(j), -ECHILD);
2208 
2209         f = j->current_file;
2210         if (!f)
2211                 return -EADDRNOTAVAIL;
2212 
2213         if (f->current_offset <= 0)
2214                 return -EADDRNOTAVAIL;
2215 
2216         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2217         if (r < 0)
2218                 return r;
2219 
2220         if (ret_boot_id)
2221                 *ret_boot_id = o->entry.boot_id;
2222         else {
2223                 sd_id128_t id;
2224 
2225                 r = sd_id128_get_boot(&id);
2226                 if (r < 0)
2227                         return r;
2228 
2229                 if (!sd_id128_equal(id, o->entry.boot_id))
2230                         return -ESTALE;
2231         }
2232 
2233         if (ret)
2234                 *ret = le64toh(o->entry.monotonic);
2235 
2236         return 0;
2237 }
2238 
field_is_valid(const char * field)2239 static bool field_is_valid(const char *field) {
2240         const char *p;
2241 
2242         assert(field);
2243 
2244         if (isempty(field))
2245                 return false;
2246 
2247         if (startswith(field, "__"))
2248                 return false;
2249 
2250         for (p = field; *p; p++) {
2251 
2252                 if (*p == '_')
2253                         continue;
2254 
2255                 if (*p >= 'A' && *p <= 'Z')
2256                         continue;
2257 
2258                 if (*p >= '0' && *p <= '9')
2259                         continue;
2260 
2261                 return false;
2262         }
2263 
2264         return true;
2265 }
2266 
sd_journal_get_data(sd_journal * j,const char * field,const void ** data,size_t * size)2267 _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
2268         JournalFile *f;
2269         uint64_t i, n;
2270         size_t field_length;
2271         int r;
2272         Object *o;
2273 
2274         assert_return(j, -EINVAL);
2275         assert_return(!journal_pid_changed(j), -ECHILD);
2276         assert_return(field, -EINVAL);
2277         assert_return(data, -EINVAL);
2278         assert_return(size, -EINVAL);
2279         assert_return(field_is_valid(field), -EINVAL);
2280 
2281         f = j->current_file;
2282         if (!f)
2283                 return -EADDRNOTAVAIL;
2284 
2285         if (f->current_offset <= 0)
2286                 return -EADDRNOTAVAIL;
2287 
2288         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2289         if (r < 0)
2290                 return r;
2291 
2292         field_length = strlen(field);
2293 
2294         n = journal_file_entry_n_items(o);
2295         for (i = 0; i < n; i++) {
2296                 Object *d;
2297                 uint64_t p, l;
2298                 size_t t;
2299                 Compression c;
2300 
2301                 p = le64toh(o->entry.items[i].object_offset);
2302                 r = journal_file_move_to_object(f, OBJECT_DATA, p, &d);
2303                 if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) {
2304                         log_debug_errno(r, "Entry item %"PRIu64" data object is bad, skipping over it: %m", i);
2305                         continue;
2306                 }
2307                 if (r < 0)
2308                         return r;
2309 
2310                 l = le64toh(d->object.size) - offsetof(Object, data.payload);
2311 
2312                 c = COMPRESSION_FROM_OBJECT(d);
2313                 if (c < 0)
2314                         return -EPROTONOSUPPORT;
2315                 if (c != COMPRESSION_NONE) {
2316 #if HAVE_COMPRESSION
2317                         r = decompress_startswith(
2318                                         c,
2319                                         d->data.payload, l,
2320                                         &f->compress_buffer,
2321                                         field, field_length, '=');
2322                         if (r < 0)
2323                                 log_debug_errno(r, "Cannot decompress %s object of length %"PRIu64" at offset "OFSfmt": %m",
2324                                                 compression_to_string(c), l, p);
2325                         else if (r > 0) {
2326 
2327                                 size_t rsize;
2328 
2329                                 r = decompress_blob(
2330                                                 c,
2331                                                 d->data.payload, l,
2332                                                 &f->compress_buffer, &rsize,
2333                                                 j->data_threshold);
2334                                 if (r < 0)
2335                                         return r;
2336 
2337                                 *data = f->compress_buffer;
2338                                 *size = (size_t) rsize;
2339 
2340                                 return 0;
2341                         }
2342 #else
2343                         return -EPROTONOSUPPORT;
2344 #endif
2345                 } else if (l >= field_length+1 &&
2346                            memcmp(d->data.payload, field, field_length) == 0 &&
2347                            d->data.payload[field_length] == '=') {
2348 
2349                         t = (size_t) l;
2350 
2351                         if ((uint64_t) t != l)
2352                                 return -E2BIG;
2353 
2354                         *data = d->data.payload;
2355                         *size = t;
2356 
2357                         return 0;
2358                 }
2359         }
2360 
2361         return -ENOENT;
2362 }
2363 
return_data(sd_journal * j,JournalFile * f,Object * o,const void ** ret_data,size_t * ret_size)2364 static int return_data(
2365                 sd_journal *j,
2366                 JournalFile *f,
2367                 Object *o,
2368                 const void **ret_data,
2369                 size_t *ret_size) {
2370 
2371         Compression c;
2372         uint64_t l;
2373         size_t t;
2374 
2375         assert(j);
2376         assert(f);
2377 
2378         l = le64toh(READ_NOW(o->object.size));
2379         if (l < offsetof(Object, data.payload))
2380                 return -EBADMSG;
2381         l -= offsetof(Object, data.payload);
2382 
2383         /* We can't read objects larger than 4G on a 32bit machine */
2384         t = (size_t) l;
2385         if ((uint64_t) t != l)
2386                 return -E2BIG;
2387 
2388         c = COMPRESSION_FROM_OBJECT(o);
2389         if (c < 0)
2390                 return -EPROTONOSUPPORT;
2391         if (c != COMPRESSION_NONE) {
2392 #if HAVE_COMPRESSION
2393                 size_t rsize;
2394                 int r;
2395 
2396                 r = decompress_blob(
2397                                 c,
2398                                 o->data.payload, l,
2399                                 &f->compress_buffer, &rsize,
2400                                 j->data_threshold);
2401                 if (r < 0)
2402                         return r;
2403 
2404                 if (ret_data)
2405                         *ret_data = f->compress_buffer;
2406                 if (ret_size)
2407                         *ret_size = (size_t) rsize;
2408 #else
2409                 return -EPROTONOSUPPORT;
2410 #endif
2411         } else {
2412                 if (ret_data)
2413                         *ret_data = o->data.payload;
2414                 if (ret_size)
2415                         *ret_size = t;
2416         }
2417 
2418         return 0;
2419 }
2420 
sd_journal_enumerate_data(sd_journal * j,const void ** data,size_t * size)2421 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
2422         JournalFile *f;
2423         Object *o;
2424         int r;
2425 
2426         assert_return(j, -EINVAL);
2427         assert_return(!journal_pid_changed(j), -ECHILD);
2428         assert_return(data, -EINVAL);
2429         assert_return(size, -EINVAL);
2430 
2431         f = j->current_file;
2432         if (!f)
2433                 return -EADDRNOTAVAIL;
2434 
2435         if (f->current_offset <= 0)
2436                 return -EADDRNOTAVAIL;
2437 
2438         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
2439         if (r < 0)
2440                 return r;
2441 
2442         for (uint64_t n = journal_file_entry_n_items(o); j->current_field < n; j->current_field++) {
2443                 uint64_t p;
2444 
2445                 p = le64toh(o->entry.items[j->current_field].object_offset);
2446                 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
2447                 if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) {
2448                         log_debug_errno(r, "Entry item %"PRIu64" data object is bad, skipping over it: %m", j->current_field);
2449                         continue;
2450                 }
2451                 if (r < 0)
2452                         return r;
2453 
2454                 r = return_data(j, f, o, data, size);
2455                 if (r == -EBADMSG) {
2456                         log_debug("Entry item %"PRIu64" data payload is bad, skipping over it.", j->current_field);
2457                         continue;
2458                 }
2459                 if (r < 0)
2460                         return r;
2461 
2462                 j->current_field++;
2463 
2464                 return 1;
2465         }
2466 
2467         return 0;
2468 }
2469 
sd_journal_enumerate_available_data(sd_journal * j,const void ** data,size_t * size)2470 _public_ int sd_journal_enumerate_available_data(sd_journal *j, const void **data, size_t *size) {
2471         for (;;) {
2472                 int r;
2473 
2474                 r = sd_journal_enumerate_data(j, data, size);
2475                 if (r >= 0)
2476                         return r;
2477                 if (!JOURNAL_ERRNO_IS_UNAVAILABLE_FIELD(r))
2478                         return r;
2479                 j->current_field++; /* Try with the next field */
2480         }
2481 }
2482 
sd_journal_restart_data(sd_journal * j)2483 _public_ void sd_journal_restart_data(sd_journal *j) {
2484         if (!j)
2485                 return;
2486 
2487         j->current_field = 0;
2488 }
2489 
reiterate_all_paths(sd_journal * j)2490 static int reiterate_all_paths(sd_journal *j) {
2491         assert(j);
2492 
2493         if (j->no_new_files)
2494                 return add_current_paths(j);
2495 
2496         if (j->flags & SD_JOURNAL_OS_ROOT)
2497                 return add_search_paths(j);
2498 
2499         if (j->toplevel_fd >= 0)
2500                 return add_root_directory(j, NULL, false);
2501 
2502         if (j->path)
2503                 return add_root_directory(j, j->path, true);
2504 
2505         return add_search_paths(j);
2506 }
2507 
sd_journal_get_fd(sd_journal * j)2508 _public_ int sd_journal_get_fd(sd_journal *j) {
2509         int r;
2510 
2511         assert_return(j, -EINVAL);
2512         assert_return(!journal_pid_changed(j), -ECHILD);
2513 
2514         if (j->no_inotify)
2515                 return -EMEDIUMTYPE;
2516 
2517         if (j->inotify_fd >= 0)
2518                 return j->inotify_fd;
2519 
2520         r = allocate_inotify(j);
2521         if (r < 0)
2522                 return r;
2523 
2524         log_debug("Reiterating files to get inotify watches established.");
2525 
2526         /* Iterate through all dirs again, to add them to the inotify */
2527         r = reiterate_all_paths(j);
2528         if (r < 0)
2529                 return r;
2530 
2531         return j->inotify_fd;
2532 }
2533 
sd_journal_get_events(sd_journal * j)2534 _public_ int sd_journal_get_events(sd_journal *j) {
2535         int fd;
2536 
2537         assert_return(j, -EINVAL);
2538         assert_return(!journal_pid_changed(j), -ECHILD);
2539 
2540         fd = sd_journal_get_fd(j);
2541         if (fd < 0)
2542                 return fd;
2543 
2544         return POLLIN;
2545 }
2546 
sd_journal_get_timeout(sd_journal * j,uint64_t * timeout_usec)2547 _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
2548         int fd;
2549 
2550         assert_return(j, -EINVAL);
2551         assert_return(!journal_pid_changed(j), -ECHILD);
2552         assert_return(timeout_usec, -EINVAL);
2553 
2554         fd = sd_journal_get_fd(j);
2555         if (fd < 0)
2556                 return fd;
2557 
2558         if (!j->on_network) {
2559                 *timeout_usec = UINT64_MAX;
2560                 return 0;
2561         }
2562 
2563         /* If we are on the network we need to regularly check for
2564          * changes manually */
2565 
2566         *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC;
2567         return 1;
2568 }
2569 
process_q_overflow(sd_journal * j)2570 static void process_q_overflow(sd_journal *j) {
2571         JournalFile *f;
2572         Directory *m;
2573 
2574         assert(j);
2575 
2576         /* When the inotify queue overruns we need to enumerate and re-validate all journal files to bring our list
2577          * back in sync with what's on disk. For this we pick a new generation counter value. It'll be assigned to all
2578          * journal files we encounter. All journal files and all directories that don't carry it after reenumeration
2579          * are subject for unloading. */
2580 
2581         log_debug("Inotify queue overrun, reiterating everything.");
2582 
2583         j->generation++;
2584         (void) reiterate_all_paths(j);
2585 
2586         ORDERED_HASHMAP_FOREACH(f, j->files) {
2587 
2588                 if (f->last_seen_generation == j->generation)
2589                         continue;
2590 
2591                 log_debug("File '%s' hasn't been seen in this enumeration, removing.", f->path);
2592                 remove_file_real(j, f);
2593         }
2594 
2595         HASHMAP_FOREACH(m, j->directories_by_path) {
2596 
2597                 if (m->last_seen_generation == j->generation)
2598                         continue;
2599 
2600                 if (m->is_root) /* Never GC root directories */
2601                         continue;
2602 
2603                 log_debug("Directory '%s' hasn't been seen in this enumeration, removing.", f->path);
2604                 remove_directory(j, m);
2605         }
2606 
2607         log_debug("Reiteration complete.");
2608 }
2609 
process_inotify_event(sd_journal * j,const struct inotify_event * e)2610 static void process_inotify_event(sd_journal *j, const struct inotify_event *e) {
2611         Directory *d;
2612 
2613         assert(j);
2614         assert(e);
2615 
2616         if (e->mask & IN_Q_OVERFLOW) {
2617                 process_q_overflow(j);
2618                 return;
2619         }
2620 
2621         /* Is this a subdirectory we watch? */
2622         d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
2623         if (d) {
2624                 if (!(e->mask & IN_ISDIR) && e->len > 0 &&
2625                     (endswith(e->name, ".journal") ||
2626                      endswith(e->name, ".journal~"))) {
2627 
2628                         /* Event for a journal file */
2629 
2630                         if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
2631                                 (void) add_file_by_name(j, d->path, e->name);
2632                         else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT))
2633                                 remove_file_by_name(j, d->path, e->name);
2634 
2635                 } else if (!d->is_root && e->len == 0) {
2636 
2637                         /* Event for a subdirectory */
2638 
2639                         if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT))
2640                                 remove_directory(j, d);
2641 
2642                 } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && id128_is_valid(e->name)) {
2643 
2644                         /* Event for root directory */
2645 
2646                         if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
2647                                 (void) add_directory(j, d->path, e->name);
2648                 }
2649 
2650                 return;
2651         }
2652 
2653         if (e->mask & IN_IGNORED)
2654                 return;
2655 
2656         log_debug("Unexpected inotify event.");
2657 }
2658 
determine_change(sd_journal * j)2659 static int determine_change(sd_journal *j) {
2660         bool b;
2661 
2662         assert(j);
2663 
2664         b = j->current_invalidate_counter != j->last_invalidate_counter;
2665         j->last_invalidate_counter = j->current_invalidate_counter;
2666 
2667         return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
2668 }
2669 
sd_journal_process(sd_journal * j)2670 _public_ int sd_journal_process(sd_journal *j) {
2671         bool got_something = false;
2672 
2673         assert_return(j, -EINVAL);
2674         assert_return(!journal_pid_changed(j), -ECHILD);
2675 
2676         if (j->inotify_fd < 0) /* We have no inotify fd yet? Then there's noting to process. */
2677                 return 0;
2678 
2679         j->last_process_usec = now(CLOCK_MONOTONIC);
2680         j->last_invalidate_counter = j->current_invalidate_counter;
2681 
2682         for (;;) {
2683                 union inotify_event_buffer buffer;
2684                 ssize_t l;
2685 
2686                 l = read(j->inotify_fd, &buffer, sizeof(buffer));
2687                 if (l < 0) {
2688                         if (ERRNO_IS_TRANSIENT(errno))
2689                                 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
2690 
2691                         return -errno;
2692                 }
2693 
2694                 got_something = true;
2695 
2696                 FOREACH_INOTIFY_EVENT(e, buffer, l)
2697                         process_inotify_event(j, e);
2698         }
2699 }
2700 
sd_journal_wait(sd_journal * j,uint64_t timeout_usec)2701 _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
2702         int r;
2703         uint64_t t;
2704 
2705         assert_return(j, -EINVAL);
2706         assert_return(!journal_pid_changed(j), -ECHILD);
2707 
2708         if (j->inotify_fd < 0) {
2709                 JournalFile *f;
2710 
2711                 /* This is the first invocation, hence create the
2712                  * inotify watch */
2713                 r = sd_journal_get_fd(j);
2714                 if (r < 0)
2715                         return r;
2716 
2717                 /* Server might have done some vacuuming while we weren't watching.
2718                    Get rid of the deleted files now so they don't stay around indefinitely. */
2719                 ORDERED_HASHMAP_FOREACH(f, j->files) {
2720                         r = journal_file_fstat(f);
2721                         if (r == -EIDRM)
2722                                 remove_file_real(j, f);
2723                         else if (r < 0) {
2724                                 log_debug_errno(r,"Failed to fstat() journal file '%s' : %m", f->path);
2725                                 continue;
2726                         }
2727                 }
2728 
2729                 /* The journal might have changed since the context
2730                  * object was created and we weren't watching before,
2731                  * hence don't wait for anything, and return
2732                  * immediately. */
2733                 return determine_change(j);
2734         }
2735 
2736         r = sd_journal_get_timeout(j, &t);
2737         if (r < 0)
2738                 return r;
2739 
2740         if (t != UINT64_MAX) {
2741                 t = usec_sub_unsigned(t, now(CLOCK_MONOTONIC));
2742 
2743                 if (timeout_usec == UINT64_MAX || timeout_usec > t)
2744                         timeout_usec = t;
2745         }
2746 
2747         do {
2748                 r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
2749         } while (r == -EINTR);
2750 
2751         if (r < 0)
2752                 return r;
2753 
2754         return sd_journal_process(j);
2755 }
2756 
sd_journal_get_cutoff_realtime_usec(sd_journal * j,uint64_t * from,uint64_t * to)2757 _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
2758         JournalFile *f;
2759         bool first = true;
2760         uint64_t fmin = 0, tmax = 0;
2761         int r;
2762 
2763         assert_return(j, -EINVAL);
2764         assert_return(!journal_pid_changed(j), -ECHILD);
2765         assert_return(from || to, -EINVAL);
2766         assert_return(from != to, -EINVAL);
2767 
2768         ORDERED_HASHMAP_FOREACH(f, j->files) {
2769                 usec_t fr, t;
2770 
2771                 r = journal_file_get_cutoff_realtime_usec(f, &fr, &t);
2772                 if (r == -ENOENT)
2773                         continue;
2774                 if (r < 0)
2775                         return r;
2776                 if (r == 0)
2777                         continue;
2778 
2779                 if (first) {
2780                         fmin = fr;
2781                         tmax = t;
2782                         first = false;
2783                 } else {
2784                         fmin = MIN(fr, fmin);
2785                         tmax = MAX(t, tmax);
2786                 }
2787         }
2788 
2789         if (from)
2790                 *from = fmin;
2791         if (to)
2792                 *to = tmax;
2793 
2794         return first ? 0 : 1;
2795 }
2796 
sd_journal_get_cutoff_monotonic_usec(sd_journal * j,sd_id128_t boot_id,uint64_t * ret_from,uint64_t * ret_to)2797 _public_ int sd_journal_get_cutoff_monotonic_usec(
2798                 sd_journal *j,
2799                 sd_id128_t boot_id,
2800                 uint64_t *ret_from,
2801                 uint64_t *ret_to) {
2802 
2803         uint64_t from = UINT64_MAX, to = UINT64_MAX;
2804         bool found = false;
2805         JournalFile *f;
2806         int r;
2807 
2808         assert_return(j, -EINVAL);
2809         assert_return(!journal_pid_changed(j), -ECHILD);
2810         assert_return(ret_from != ret_to, -EINVAL);
2811 
2812         ORDERED_HASHMAP_FOREACH(f, j->files) {
2813                 usec_t ff, tt;
2814 
2815                 r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &ff, &tt);
2816                 if (r == -ENOENT)
2817                         continue;
2818                 if (r < 0)
2819                         return r;
2820                 if (r == 0)
2821                         continue;
2822 
2823                 if (found) {
2824                         from = MIN(ff, from);
2825                         to = MAX(tt, to);
2826                 } else {
2827                         from = ff;
2828                         to = tt;
2829                         found = true;
2830                 }
2831         }
2832 
2833         if (ret_from)
2834                 *ret_from = from;
2835         if (ret_to)
2836                 *ret_to = to;
2837 
2838         return found;
2839 }
2840 
journal_print_header(sd_journal * j)2841 void journal_print_header(sd_journal *j) {
2842         JournalFile *f;
2843         bool newline = false;
2844 
2845         assert(j);
2846 
2847         ORDERED_HASHMAP_FOREACH(f, j->files) {
2848                 if (newline)
2849                         putchar('\n');
2850                 else
2851                         newline = true;
2852 
2853                 journal_file_print_header(f);
2854         }
2855 }
2856 
sd_journal_get_usage(sd_journal * j,uint64_t * ret)2857 _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *ret) {
2858         JournalFile *f;
2859         uint64_t sum = 0;
2860 
2861         assert_return(j, -EINVAL);
2862         assert_return(!journal_pid_changed(j), -ECHILD);
2863         assert_return(ret, -EINVAL);
2864 
2865         ORDERED_HASHMAP_FOREACH(f, j->files) {
2866                 struct stat st;
2867                 uint64_t b;
2868 
2869                 if (fstat(f->fd, &st) < 0)
2870                         return -errno;
2871 
2872                 b = (uint64_t) st.st_blocks;
2873                 if (b > UINT64_MAX / 512)
2874                         return -EOVERFLOW;
2875                 b *= 512;
2876 
2877                 if (sum > UINT64_MAX - b)
2878                         return -EOVERFLOW;
2879                 sum += b;
2880         }
2881 
2882         *ret = sum;
2883         return 0;
2884 }
2885 
sd_journal_query_unique(sd_journal * j,const char * field)2886 _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
2887         int r;
2888 
2889         assert_return(j, -EINVAL);
2890         assert_return(!journal_pid_changed(j), -ECHILD);
2891         assert_return(!isempty(field), -EINVAL);
2892         assert_return(field_is_valid(field), -EINVAL);
2893 
2894         r = free_and_strdup(&j->unique_field, field);
2895         if (r < 0)
2896                 return r;
2897 
2898         j->unique_file = NULL;
2899         j->unique_offset = 0;
2900         j->unique_file_lost = false;
2901 
2902         return 0;
2903 }
2904 
sd_journal_enumerate_unique(sd_journal * j,const void ** ret_data,size_t * ret_size)2905 _public_ int sd_journal_enumerate_unique(
2906                 sd_journal *j,
2907                 const void **ret_data,
2908                 size_t *ret_size) {
2909 
2910         size_t k;
2911 
2912         assert_return(j, -EINVAL);
2913         assert_return(!journal_pid_changed(j), -ECHILD);
2914         assert_return(j->unique_field, -EINVAL);
2915 
2916         k = strlen(j->unique_field);
2917 
2918         if (!j->unique_file) {
2919                 if (j->unique_file_lost)
2920                         return 0;
2921 
2922                 j->unique_file = ordered_hashmap_first(j->files);
2923                 if (!j->unique_file)
2924                         return 0;
2925 
2926                 j->unique_offset = 0;
2927         }
2928 
2929         for (;;) {
2930                 JournalFile *of;
2931                 Object *o;
2932                 const void *odata;
2933                 size_t ol;
2934                 bool found;
2935                 int r;
2936 
2937                 /* Proceed to next data object in the field's linked list */
2938                 if (j->unique_offset == 0) {
2939                         r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
2940                         if (r < 0)
2941                                 return r;
2942 
2943                         j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
2944                 } else {
2945                         r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
2946                         if (r < 0)
2947                                 return r;
2948 
2949                         j->unique_offset = le64toh(o->data.next_field_offset);
2950                 }
2951 
2952                 /* We reached the end of the list? Then start again, with the next file */
2953                 if (j->unique_offset == 0) {
2954                         j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
2955                         if (!j->unique_file)
2956                                 return 0;
2957 
2958                         continue;
2959                 }
2960 
2961                 /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED
2962                  * instead, so that we can look at this data object at the same
2963                  * time as one on another file */
2964                 r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o);
2965                 if (r < 0)
2966                         return r;
2967 
2968                 /* Let's do the type check by hand, since we used 0 context above. */
2969                 if (o->object.type != OBJECT_DATA)
2970                         return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
2971                                                "%s:offset " OFSfmt ": object has type %d, expected %d",
2972                                                j->unique_file->path,
2973                                                j->unique_offset,
2974                                                o->object.type, OBJECT_DATA);
2975 
2976                 r = return_data(j, j->unique_file, o, &odata, &ol);
2977                 if (r < 0)
2978                         return r;
2979 
2980                 /* Check if we have at least the field name and "=". */
2981                 if (ol <= k)
2982                         return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
2983                                                "%s:offset " OFSfmt ": object has size %zu, expected at least %zu",
2984                                                j->unique_file->path,
2985                                                j->unique_offset, ol, k + 1);
2986 
2987                 if (memcmp(odata, j->unique_field, k) != 0 || ((const char*) odata)[k] != '=')
2988                         return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
2989                                                "%s:offset " OFSfmt ": object does not start with \"%s=\"",
2990                                                j->unique_file->path,
2991                                                j->unique_offset,
2992                                                j->unique_field);
2993 
2994                 /* OK, now let's see if we already returned this data object by checking if it exists in the
2995                  * earlier traversed files. */
2996                 found = false;
2997                 ORDERED_HASHMAP_FOREACH(of, j->files) {
2998                         if (of == j->unique_file)
2999                                 break;
3000 
3001                         /* Skip this file it didn't have any fields indexed */
3002                         if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0)
3003                                 continue;
3004 
3005                         /* We can reuse the hash from our current file only on old-style journal files
3006                          * without keyed hashes. On new-style files we have to calculate the hash anew, to
3007                          * take the per-file hash seed into consideration. */
3008                         if (!JOURNAL_HEADER_KEYED_HASH(j->unique_file->header) && !JOURNAL_HEADER_KEYED_HASH(of->header))
3009                                 r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), NULL, NULL);
3010                         else
3011                                 r = journal_file_find_data_object(of, odata, ol, NULL, NULL);
3012                         if (r < 0)
3013                                 return r;
3014                         if (r > 0) {
3015                                 found = true;
3016                                 break;
3017                         }
3018                 }
3019 
3020                 if (found)
3021                         continue;
3022 
3023                 r = return_data(j, j->unique_file, o, ret_data, ret_size);
3024                 if (r < 0)
3025                         return r;
3026 
3027                 return 1;
3028         }
3029 }
3030 
sd_journal_enumerate_available_unique(sd_journal * j,const void ** data,size_t * size)3031 _public_ int sd_journal_enumerate_available_unique(sd_journal *j, const void **data, size_t *size) {
3032         for (;;) {
3033                 int r;
3034 
3035                 r = sd_journal_enumerate_unique(j, data, size);
3036                 if (r >= 0)
3037                         return r;
3038                 if (!JOURNAL_ERRNO_IS_UNAVAILABLE_FIELD(r))
3039                         return r;
3040                 /* Try with the next field. sd_journal_enumerate_unique() modifies state, so on the next try
3041                  * we will access the next field. */
3042         }
3043 }
3044 
sd_journal_restart_unique(sd_journal * j)3045 _public_ void sd_journal_restart_unique(sd_journal *j) {
3046         if (!j)
3047                 return;
3048 
3049         j->unique_file = NULL;
3050         j->unique_offset = 0;
3051         j->unique_file_lost = false;
3052 }
3053 
sd_journal_enumerate_fields(sd_journal * j,const char ** field)3054 _public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) {
3055         int r;
3056 
3057         assert_return(j, -EINVAL);
3058         assert_return(!journal_pid_changed(j), -ECHILD);
3059         assert_return(field, -EINVAL);
3060 
3061         if (!j->fields_file) {
3062                 if (j->fields_file_lost)
3063                         return 0;
3064 
3065                 j->fields_file = ordered_hashmap_first(j->files);
3066                 if (!j->fields_file)
3067                         return 0;
3068 
3069                 j->fields_hash_table_index = 0;
3070                 j->fields_offset = 0;
3071         }
3072 
3073         for (;;) {
3074                 JournalFile *f, *of;
3075                 uint64_t m;
3076                 Object *o;
3077                 size_t sz;
3078                 bool found;
3079 
3080                 f = j->fields_file;
3081 
3082                 if (j->fields_offset == 0) {
3083                         bool eof = false;
3084 
3085                         /* We are not yet positioned at any field. Let's pick the first one */
3086                         r = journal_file_map_field_hash_table(f);
3087                         if (r < 0)
3088                                 return r;
3089 
3090                         m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
3091                         for (;;) {
3092                                 if (j->fields_hash_table_index >= m) {
3093                                         /* Reached the end of the hash table, go to the next file. */
3094                                         eof = true;
3095                                         break;
3096                                 }
3097 
3098                                 j->fields_offset = le64toh(f->field_hash_table[j->fields_hash_table_index].head_hash_offset);
3099 
3100                                 if (j->fields_offset != 0)
3101                                         break;
3102 
3103                                 /* Empty hash table bucket, go to next one */
3104                                 j->fields_hash_table_index++;
3105                         }
3106 
3107                         if (eof) {
3108                                 /* Proceed with next file */
3109                                 j->fields_file = ordered_hashmap_next(j->files, f->path);
3110                                 if (!j->fields_file) {
3111                                         *field = NULL;
3112                                         return 0;
3113                                 }
3114 
3115                                 j->fields_offset = 0;
3116                                 j->fields_hash_table_index = 0;
3117                                 continue;
3118                         }
3119 
3120                 } else {
3121                         /* We are already positioned at a field. If so, let's figure out the next field from it */
3122 
3123                         r = journal_file_move_to_object(f, OBJECT_FIELD, j->fields_offset, &o);
3124                         if (r < 0)
3125                                 return r;
3126 
3127                         j->fields_offset = le64toh(o->field.next_hash_offset);
3128                         if (j->fields_offset == 0) {
3129                                 /* Reached the end of the hash table chain */
3130                                 j->fields_hash_table_index++;
3131                                 continue;
3132                         }
3133                 }
3134 
3135                 /* We use OBJECT_UNUSED here, so that the iterator below doesn't remove our mmap window */
3136                 r = journal_file_move_to_object(f, OBJECT_UNUSED, j->fields_offset, &o);
3137                 if (r < 0)
3138                         return r;
3139 
3140                 /* Because we used OBJECT_UNUSED above, we need to do our type check manually */
3141                 if (o->object.type != OBJECT_FIELD)
3142                         return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
3143                                                "%s:offset " OFSfmt ": object has type %i, expected %i",
3144                                                f->path, j->fields_offset,
3145                                                o->object.type, OBJECT_FIELD);
3146 
3147                 sz = le64toh(o->object.size) - offsetof(Object, field.payload);
3148 
3149                 /* Let's see if we already returned this field name before. */
3150                 found = false;
3151                 ORDERED_HASHMAP_FOREACH(of, j->files) {
3152                         if (of == f)
3153                                 break;
3154 
3155                         /* Skip this file it didn't have any fields indexed */
3156                         if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0)
3157                                 continue;
3158 
3159                         if (!JOURNAL_HEADER_KEYED_HASH(f->header) && !JOURNAL_HEADER_KEYED_HASH(of->header))
3160                                 r = journal_file_find_field_object_with_hash(of, o->field.payload, sz,
3161                                                                              le64toh(o->field.hash), NULL, NULL);
3162                         else
3163                                 r = journal_file_find_field_object(of, o->field.payload, sz, NULL, NULL);
3164                         if (r < 0)
3165                                 return r;
3166                         if (r > 0) {
3167                                 found = true;
3168                                 break;
3169                         }
3170                 }
3171 
3172                 if (found)
3173                         continue;
3174 
3175                 /* Check if this is really a valid string containing no NUL byte */
3176                 if (memchr(o->field.payload, 0, sz))
3177                         return -EBADMSG;
3178 
3179                 if (j->data_threshold > 0 && sz > j->data_threshold)
3180                         sz = j->data_threshold;
3181 
3182                 if (!GREEDY_REALLOC(j->fields_buffer, sz + 1))
3183                         return -ENOMEM;
3184 
3185                 memcpy(j->fields_buffer, o->field.payload, sz);
3186                 j->fields_buffer[sz] = 0;
3187 
3188                 if (!field_is_valid(j->fields_buffer))
3189                         return -EBADMSG;
3190 
3191                 *field = j->fields_buffer;
3192                 return 1;
3193         }
3194 }
3195 
sd_journal_restart_fields(sd_journal * j)3196 _public_ void sd_journal_restart_fields(sd_journal *j) {
3197         if (!j)
3198                 return;
3199 
3200         j->fields_file = NULL;
3201         j->fields_hash_table_index = 0;
3202         j->fields_offset = 0;
3203         j->fields_file_lost = false;
3204 }
3205 
sd_journal_reliable_fd(sd_journal * j)3206 _public_ int sd_journal_reliable_fd(sd_journal *j) {
3207         assert_return(j, -EINVAL);
3208         assert_return(!journal_pid_changed(j), -ECHILD);
3209 
3210         return !j->on_network;
3211 }
3212 
lookup_field(const char * field,void * userdata)3213 static char *lookup_field(const char *field, void *userdata) {
3214         sd_journal *j = userdata;
3215         const void *data;
3216         size_t size, d;
3217         int r;
3218 
3219         assert(field);
3220         assert(j);
3221 
3222         r = sd_journal_get_data(j, field, &data, &size);
3223         if (r < 0 ||
3224             size > REPLACE_VAR_MAX)
3225                 return strdup(field);
3226 
3227         d = strlen(field) + 1;
3228 
3229         return strndup((const char*) data + d, size - d);
3230 }
3231 
sd_journal_get_catalog(sd_journal * j,char ** ret)3232 _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) {
3233         const void *data;
3234         size_t size;
3235         sd_id128_t id;
3236         _cleanup_free_ char *text = NULL, *cid = NULL;
3237         char *t;
3238         int r;
3239 
3240         assert_return(j, -EINVAL);
3241         assert_return(!journal_pid_changed(j), -ECHILD);
3242         assert_return(ret, -EINVAL);
3243 
3244         r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size);
3245         if (r < 0)
3246                 return r;
3247 
3248         cid = strndup((const char*) data + 11, size - 11);
3249         if (!cid)
3250                 return -ENOMEM;
3251 
3252         r = sd_id128_from_string(cid, &id);
3253         if (r < 0)
3254                 return r;
3255 
3256         r = catalog_get(CATALOG_DATABASE, id, &text);
3257         if (r < 0)
3258                 return r;
3259 
3260         t = replace_var(text, lookup_field, j);
3261         if (!t)
3262                 return -ENOMEM;
3263 
3264         *ret = t;
3265         return 0;
3266 }
3267 
sd_journal_get_catalog_for_message_id(sd_id128_t id,char ** ret)3268 _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) {
3269         assert_return(ret, -EINVAL);
3270 
3271         return catalog_get(CATALOG_DATABASE, id, ret);
3272 }
3273 
sd_journal_set_data_threshold(sd_journal * j,size_t sz)3274 _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
3275         assert_return(j, -EINVAL);
3276         assert_return(!journal_pid_changed(j), -ECHILD);
3277 
3278         j->data_threshold = sz;
3279         return 0;
3280 }
3281 
sd_journal_get_data_threshold(sd_journal * j,size_t * sz)3282 _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) {
3283         assert_return(j, -EINVAL);
3284         assert_return(!journal_pid_changed(j), -ECHILD);
3285         assert_return(sz, -EINVAL);
3286 
3287         *sz = j->data_threshold;
3288         return 0;
3289 }
3290 
sd_journal_has_runtime_files(sd_journal * j)3291 _public_ int sd_journal_has_runtime_files(sd_journal *j) {
3292         assert_return(j, -EINVAL);
3293 
3294         return j->has_runtime_files;
3295 }
3296 
sd_journal_has_persistent_files(sd_journal * j)3297 _public_ int sd_journal_has_persistent_files(sd_journal *j) {
3298         assert_return(j, -EINVAL);
3299 
3300         return j->has_persistent_files;
3301 }
3302