LCOV - code coverage report
Current view: top level - journal - sd-journal.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 815 1724 47.3 %
Date: 2019-08-22 15:41:25 Functions: 58 99 58.6 %

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

Generated by: LCOV version 1.14