LCOV - code coverage report
Current view: top level - journal - sd-journal.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 815 1724 47.3 %
Date: 2019-08-23 13:36:53 Functions: 58 99 58.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 631 1859 33.9 %

           Branch data     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                 :      48548 : static bool journal_pid_changed(sd_journal *j) {
      55         [ -  + ]:      48548 :         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                 :      48548 :         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                 :       1016 : static void detach_location(sd_journal *j) {
     106                 :            :         Iterator i;
     107                 :            :         JournalFile *f;
     108                 :            : 
     109         [ -  + ]:       1016 :         assert(j);
     110                 :            : 
     111                 :       1016 :         j->current_file = NULL;
     112                 :       1016 :         j->current_field = 0;
     113                 :            : 
     114         [ +  + ]:      48912 :         ORDERED_HASHMAP_FOREACH(f, j->files, i)
     115                 :      47896 :                 journal_file_reset_location(f);
     116                 :       1016 : }
     117                 :            : 
     118                 :         60 : static void reset_location(sd_journal *j) {
     119         [ -  + ]:         60 :         assert(j);
     120                 :            : 
     121                 :         60 :         detach_location(j);
     122         [ +  - ]:         60 :         zero(j->current_location);
     123                 :         60 : }
     124                 :            : 
     125                 :      41504 : static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
     126         [ -  + ]:      41504 :         assert(l);
     127   [ +  -  -  + ]:      41504 :         assert(IN_SET(type, LOCATION_DISCRETE, LOCATION_SEEK));
     128         [ -  + ]:      41504 :         assert(f);
     129         [ -  + ]:      41504 :         assert(o->object.type == OBJECT_ENTRY);
     130                 :            : 
     131                 :      41504 :         l->type = type;
     132                 :      41504 :         l->seqnum = le64toh(o->entry.seqnum);
     133                 :      41504 :         l->seqnum_id = f->header->seqnum_id;
     134                 :      41504 :         l->realtime = le64toh(o->entry.realtime);
     135                 :      41504 :         l->monotonic = le64toh(o->entry.monotonic);
     136                 :      41504 :         l->boot_id = o->entry.boot_id;
     137                 :      41504 :         l->xor_hash = le64toh(o->entry.xor_hash);
     138                 :            : 
     139                 :      41504 :         l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
     140                 :      41504 : }
     141                 :            : 
     142                 :      41504 : static void set_location(sd_journal *j, JournalFile *f, Object *o) {
     143         [ -  + ]:      41504 :         assert(j);
     144         [ -  + ]:      41504 :         assert(f);
     145         [ -  + ]:      41504 :         assert(o);
     146                 :            : 
     147                 :      41504 :         init_location(&j->current_location, LOCATION_DISCRETE, f, o);
     148                 :            : 
     149                 :      41504 :         j->current_file = f;
     150                 :      41504 :         j->current_field = 0;
     151                 :            : 
     152                 :            :         /* Let f know its candidate entry was picked. */
     153         [ -  + ]:      41504 :         assert(f->location_type == LOCATION_SEEK);
     154                 :      41504 :         f->location_type = LOCATION_DISCRETE;
     155                 :      41504 : }
     156                 :            : 
     157                 :        124 : static int match_is_valid(const void *data, size_t size) {
     158                 :            :         const char *b, *p;
     159                 :            : 
     160         [ -  + ]:        124 :         assert(data);
     161                 :            : 
     162         [ +  + ]:        124 :         if (size < 2)
     163                 :          8 :                 return false;
     164                 :            : 
     165         [ -  + ]:        116 :         if (startswith(data, "__"))
     166                 :          0 :                 return false;
     167                 :            : 
     168                 :        116 :         b = data;
     169         [ +  - ]:        548 :         for (p = b; p < b + size; p++) {
     170                 :            : 
     171         [ +  + ]:        548 :                 if (*p == '=')
     172                 :        108 :                         return p > b;
     173                 :            : 
     174         [ +  + ]:        440 :                 if (*p == '_')
     175                 :         24 :                         continue;
     176                 :            : 
     177   [ +  +  +  + ]:        416 :                 if (*p >= 'A' && *p <= 'Z')
     178                 :        368 :                         continue;
     179                 :            : 
     180   [ +  -  +  + ]:         48 :                 if (*p >= '0' && *p <= '9')
     181                 :         40 :                         continue;
     182                 :            : 
     183                 :          8 :                 return false;
     184                 :            :         }
     185                 :            : 
     186                 :          0 :         return false;
     187                 :            : }
     188                 :            : 
     189                 :        120 : static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
     190                 :        120 :         const uint8_t *a = _a, *b = _b;
     191                 :            :         size_t j;
     192                 :            : 
     193   [ +  -  +  - ]:        300 :         for (j = 0; j < s && j < t; j++) {
     194                 :            : 
     195         [ +  + ]:        300 :                 if (a[j] != b[j])
     196                 :         84 :                         return false;
     197                 :            : 
     198         [ +  + ]:        216 :                 if (a[j] == '=')
     199                 :         36 :                         return true;
     200                 :            :         }
     201                 :            : 
     202                 :          0 :         assert_not_reached("\"=\" not found");
     203                 :            : }
     204                 :            : 
     205                 :        240 : static Match *match_new(Match *p, MatchType t) {
     206                 :            :         Match *m;
     207                 :            : 
     208                 :        240 :         m = new0(Match, 1);
     209         [ -  + ]:        240 :         if (!m)
     210                 :          0 :                 return NULL;
     211                 :            : 
     212                 :        240 :         m->type = t;
     213                 :            : 
     214         [ +  + ]:        240 :         if (p) {
     215                 :        220 :                 m->parent = p;
     216   [ -  +  +  + ]:        220 :                 LIST_PREPEND(matches, p->matches, m);
     217                 :            :         }
     218                 :            : 
     219                 :        240 :         return m;
     220                 :            : }
     221                 :            : 
     222                 :        240 : static void match_free(Match *m) {
     223         [ -  + ]:        240 :         assert(m);
     224                 :            : 
     225         [ +  + ]:        460 :         while (m->matches)
     226                 :        220 :                 match_free(m->matches);
     227                 :            : 
     228         [ +  + ]:        240 :         if (m->parent)
     229   [ -  +  +  +  :        220 :                 LIST_REMOVE(matches, m->parent->matches, m);
             -  +  -  + ]
     230                 :            : 
     231                 :        240 :         free(m->data);
     232                 :        240 :         free(m);
     233                 :        240 : }
     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                 :        124 : _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
     243                 :        124 :         Match *l3, *l4, *add_here = NULL, *m;
     244                 :            :         le64_t le_hash;
     245                 :            : 
     246   [ -  +  -  + ]:        124 :         assert_return(j, -EINVAL);
     247   [ -  +  -  + ]:        124 :         assert_return(!journal_pid_changed(j), -ECHILD);
     248   [ -  +  -  + ]:        124 :         assert_return(data, -EINVAL);
     249                 :            : 
     250         [ +  + ]:        124 :         if (size == 0)
     251                 :        116 :                 size = strlen(data);
     252                 :            : 
     253   [ +  +  +  + ]:        124 :         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         [ +  + ]:        104 :         if (!j->level0) {
     262                 :         20 :                 j->level0 = match_new(NULL, MATCH_AND_TERM);
     263         [ -  + ]:         20 :                 if (!j->level0)
     264                 :          0 :                         return -ENOMEM;
     265                 :            :         }
     266                 :            : 
     267         [ +  + ]:        104 :         if (!j->level1) {
     268                 :         24 :                 j->level1 = match_new(j->level0, MATCH_OR_TERM);
     269         [ -  + ]:         24 :                 if (!j->level1)
     270                 :          0 :                         return -ENOMEM;
     271                 :            :         }
     272                 :            : 
     273         [ +  + ]:        104 :         if (!j->level2) {
     274                 :         32 :                 j->level2 = match_new(j->level1, MATCH_AND_TERM);
     275         [ -  + ]:         32 :                 if (!j->level2)
     276                 :          0 :                         return -ENOMEM;
     277                 :            :         }
     278                 :            : 
     279         [ -  + ]:        104 :         assert(j->level0->type == MATCH_AND_TERM);
     280         [ -  + ]:        104 :         assert(j->level1->type == MATCH_OR_TERM);
     281         [ -  + ]:        104 :         assert(j->level2->type == MATCH_AND_TERM);
     282                 :            : 
     283                 :        104 :         le_hash = htole64(hash64(data, size));
     284                 :            : 
     285         [ +  + ]:        164 :         LIST_FOREACH(matches, l3, j->level2->matches) {
     286         [ -  + ]:        100 :                 assert(l3->type == MATCH_OR_TERM);
     287                 :            : 
     288         [ +  + ]:        184 :                 LIST_FOREACH(matches, l4, l3->matches) {
     289         [ -  + ]:        124 :                         assert(l4->type == MATCH_DISCRETE);
     290                 :            : 
     291                 :            :                         /* Exactly the same match already? Then ignore
     292                 :            :                          * this addition */
     293         [ +  + ]:        124 :                         if (l4->le_hash == le_hash &&
     294         [ +  - ]:          4 :                             l4->size == size &&
     295         [ +  - ]:          4 :                             memcmp(l4->data, data, size) == 0)
     296                 :          4 :                                 return 0;
     297                 :            : 
     298                 :            :                         /* Same field? Then let's add this to this OR term */
     299         [ +  + ]:        120 :                         if (same_field(data, size, l4->data, l4->size)) {
     300                 :         36 :                                 add_here = l3;
     301                 :         36 :                                 break;
     302                 :            :                         }
     303                 :            :                 }
     304                 :            : 
     305         [ +  + ]:         96 :                 if (add_here)
     306                 :         36 :                         break;
     307                 :            :         }
     308                 :            : 
     309         [ +  + ]:        100 :         if (!add_here) {
     310                 :         64 :                 add_here = match_new(j->level2, MATCH_OR_TERM);
     311         [ -  + ]:         64 :                 if (!add_here)
     312                 :          0 :                         goto fail;
     313                 :            :         }
     314                 :            : 
     315                 :        100 :         m = match_new(add_here, MATCH_DISCRETE);
     316         [ -  + ]:        100 :         if (!m)
     317                 :          0 :                 goto fail;
     318                 :            : 
     319                 :        100 :         m->le_hash = le_hash;
     320                 :        100 :         m->size = size;
     321                 :        100 :         m->data = memdup(data, size);
     322         [ -  + ]:        100 :         if (!m->data)
     323                 :          0 :                 goto fail;
     324                 :            : 
     325                 :        100 :         detach_location(j);
     326                 :            : 
     327                 :        100 :         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                 :          4 : _public_ int sd_journal_add_conjunction(sd_journal *j) {
     339   [ -  +  -  + ]:          4 :         assert_return(j, -EINVAL);
     340   [ -  +  -  + ]:          4 :         assert_return(!journal_pid_changed(j), -ECHILD);
     341                 :            : 
     342         [ -  + ]:          4 :         if (!j->level0)
     343                 :          0 :                 return 0;
     344                 :            : 
     345         [ -  + ]:          4 :         if (!j->level1)
     346                 :          0 :                 return 0;
     347                 :            : 
     348         [ -  + ]:          4 :         if (!j->level1->matches)
     349                 :          0 :                 return 0;
     350                 :            : 
     351                 :          4 :         j->level1 = NULL;
     352                 :          4 :         j->level2 = NULL;
     353                 :            : 
     354                 :          4 :         return 0;
     355                 :            : }
     356                 :            : 
     357                 :          8 : _public_ int sd_journal_add_disjunction(sd_journal *j) {
     358   [ -  +  -  + ]:          8 :         assert_return(j, -EINVAL);
     359   [ -  +  -  + ]:          8 :         assert_return(!journal_pid_changed(j), -ECHILD);
     360                 :            : 
     361         [ -  + ]:          8 :         if (!j->level0)
     362                 :          0 :                 return 0;
     363                 :            : 
     364         [ -  + ]:          8 :         if (!j->level1)
     365                 :          0 :                 return 0;
     366                 :            : 
     367         [ -  + ]:          8 :         if (!j->level2)
     368                 :          0 :                 return 0;
     369                 :            : 
     370         [ -  + ]:          8 :         if (!j->level2->matches)
     371                 :          0 :                 return 0;
     372                 :            : 
     373                 :          8 :         j->level2 = NULL;
     374                 :          8 :         return 0;
     375                 :            : }
     376                 :            : 
     377                 :        192 : static char *match_make_string(Match *m) {
     378                 :        192 :         char *p = NULL, *r;
     379                 :            :         Match *i;
     380                 :        192 :         bool enclose = false;
     381                 :            : 
     382         [ -  + ]:        192 :         if (!m)
     383                 :          0 :                 return strdup("none");
     384                 :            : 
     385         [ +  + ]:        192 :         if (m->type == MATCH_DISCRETE)
     386                 :         88 :                 return cescape_length(m->data, m->size);
     387                 :            : 
     388         [ +  + ]:        284 :         LIST_FOREACH(matches, i, m->matches) {
     389                 :            :                 char *t, *k;
     390                 :            : 
     391                 :        180 :                 t = match_make_string(i);
     392         [ -  + ]:        180 :                 if (!t)
     393                 :          0 :                         return mfree(p);
     394                 :            : 
     395         [ +  + ]:        180 :                 if (p) {
     396         [ +  + ]:         76 :                         k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t);
     397                 :         76 :                         free(p);
     398                 :         76 :                         free(t);
     399                 :            : 
     400         [ -  + ]:         76 :                         if (!k)
     401                 :          0 :                                 return NULL;
     402                 :            : 
     403                 :         76 :                         p = k;
     404                 :            : 
     405                 :         76 :                         enclose = true;
     406                 :            :                 } else
     407                 :        104 :                         p = t;
     408                 :            :         }
     409                 :            : 
     410         [ +  + ]:        104 :         if (enclose) {
     411                 :         56 :                 r = strjoin("(", p, ")");
     412                 :         56 :                 free(p);
     413                 :         56 :                 return r;
     414                 :            :         }
     415                 :            : 
     416                 :         48 :         return p;
     417                 :            : }
     418                 :            : 
     419                 :         12 : char *journal_make_match_string(sd_journal *j) {
     420         [ -  + ]:         12 :         assert(j);
     421                 :            : 
     422                 :         12 :         return match_make_string(j->level0);
     423                 :            : }
     424                 :            : 
     425                 :        856 : _public_ void sd_journal_flush_matches(sd_journal *j) {
     426         [ -  + ]:        856 :         if (!j)
     427                 :          0 :                 return;
     428                 :            : 
     429         [ +  + ]:        856 :         if (j->level0)
     430                 :         20 :                 match_free(j->level0);
     431                 :            : 
     432                 :        856 :         j->level0 = j->level1 = j->level2 = NULL;
     433                 :            : 
     434                 :        856 :         detach_location(j);
     435                 :            : }
     436                 :            : 
     437                 :    4005732 : _pure_ static int compare_with_location(JournalFile *f, Location *l) {
     438                 :            :         int r;
     439                 :            : 
     440         [ -  + ]:    4005732 :         assert(f);
     441         [ -  + ]:    4005732 :         assert(l);
     442         [ -  + ]:    4005732 :         assert(f->location_type == LOCATION_SEEK);
     443   [ +  -  -  + ]:    4005732 :         assert(IN_SET(l->type, LOCATION_DISCRETE, LOCATION_SEEK));
     444                 :            : 
     445         [ +  - ]:    4005732 :         if (l->monotonic_set &&
     446         [ +  + ]:    4005732 :             sd_id128_equal(f->current_boot_id, l->boot_id) &&
     447         [ +  - ]:      84360 :             l->realtime_set &&
     448         [ +  + ]:      84360 :             f->current_realtime == l->realtime &&
     449         [ +  - ]:        440 :             l->xor_hash_set &&
     450         [ +  + ]:        440 :             f->current_xor_hash == l->xor_hash)
     451                 :        344 :                 return 0;
     452                 :            : 
     453         [ +  - ]:    4005388 :         if (l->seqnum_set &&
     454         [ +  + ]:    4005388 :             sd_id128_equal(f->header->seqnum_id, l->seqnum_id)) {
     455                 :            : 
     456         [ +  + ]:      82784 :                 r = CMP(f->current_seqnum, l->seqnum);
     457         [ +  - ]:      82784 :                 if (r != 0)
     458                 :      82784 :                         return r;
     459                 :            :         }
     460                 :            : 
     461         [ +  - ]:    3922604 :         if (l->monotonic_set &&
     462         [ +  + ]:    3922604 :             sd_id128_equal(f->current_boot_id, l->boot_id)) {
     463                 :            : 
     464         [ +  + ]:      42600 :                 r = CMP(f->current_monotonic, l->monotonic);
     465         [ +  - ]:      42600 :                 if (r != 0)
     466                 :      42600 :                         return r;
     467                 :            :         }
     468                 :            : 
     469         [ +  - ]:    3880004 :         if (l->realtime_set) {
     470                 :            : 
     471         [ +  + ]:    3880004 :                 r = CMP(f->current_realtime, l->realtime);
     472         [ +  - ]:    3880004 :                 if (r != 0)
     473                 :    3880004 :                         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                 :       6324 : 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                 :       6324 :         uint64_t np = 0;
     497                 :            :         Object *n;
     498                 :            : 
     499         [ -  + ]:       6324 :         assert(j);
     500         [ -  + ]:       6324 :         assert(m);
     501         [ -  + ]:       6324 :         assert(f);
     502                 :            : 
     503         [ +  + ]:       6324 :         if (m->type == MATCH_DISCRETE) {
     504                 :            :                 uint64_t dp;
     505                 :            : 
     506                 :       1776 :                 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
     507         [ +  + ]:       1776 :                 if (r <= 0)
     508                 :         40 :                         return r;
     509                 :            : 
     510                 :       1736 :                 return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset);
     511                 :            : 
     512         [ +  + ]:       4548 :         } else if (m->type == MATCH_OR_TERM) {
     513                 :            :                 Match *i;
     514                 :            : 
     515                 :            :                 /* Find the earliest match beyond after_offset */
     516                 :            : 
     517         [ +  + ]:       5216 :                 LIST_FOREACH(matches, i, m->matches) {
     518                 :            :                         uint64_t cp;
     519                 :            : 
     520                 :       2636 :                         r = next_for_match(j, i, f, after_offset, direction, NULL, &cp);
     521         [ -  + ]:       2636 :                         if (r < 0)
     522                 :          0 :                                 return r;
     523         [ +  + ]:       2636 :                         else if (r > 0) {
     524   [ +  +  +  -  :       2500 :                                 if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
             +  -  #  # ]
     525                 :       2500 :                                         np = cp;
     526                 :            :                         }
     527                 :            :                 }
     528                 :            : 
     529         [ +  + ]:       2580 :                 if (np == 0)
     530                 :         88 :                         return 0;
     531                 :            : 
     532         [ +  - ]:       1968 :         } 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         [ -  + ]:       1968 :                 if (!m->matches)
     540                 :          0 :                         return 0;
     541                 :            : 
     542                 :       1968 :                 r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
     543         [ +  + ]:       1968 :                 if (r <= 0)
     544                 :         88 :                         return r;
     545                 :            : 
     546   [ +  +  -  + ]:       1880 :                 assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
     547                 :       1880 :                 last_moved = m->matches;
     548                 :            : 
     549   [ +  +  +  +  :       2492 :                 LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
                   +  + ]
     550                 :            :                         uint64_t cp;
     551                 :            : 
     552                 :        612 :                         r = next_for_match(j, i, f, np, direction, NULL, &cp);
     553         [ -  + ]:        612 :                         if (r <= 0)
     554                 :          0 :                                 return r;
     555                 :            : 
     556   [ +  +  -  + ]:        612 :                         assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
     557   [ +  +  +  + ]:        612 :                         if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
     558                 :        148 :                                 np = cp;
     559                 :        148 :                                 last_moved = i;
     560                 :            :                         }
     561                 :            :                 }
     562                 :            :         }
     563                 :            : 
     564         [ -  + ]:       4372 :         assert(np > 0);
     565                 :            : 
     566                 :       4372 :         r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
     567         [ -  + ]:       4372 :         if (r < 0)
     568                 :          0 :                 return r;
     569                 :            : 
     570         [ +  + ]:       4372 :         if (ret)
     571                 :        816 :                 *ret = n;
     572         [ +  - ]:       4372 :         if (offset)
     573                 :       4372 :                 *offset = np;
     574                 :            : 
     575                 :       4372 :         return 1;
     576                 :            : }
     577                 :            : 
     578                 :       2596 : 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         [ -  + ]:       2596 :         assert(j);
     589         [ -  + ]:       2596 :         assert(m);
     590         [ -  + ]:       2596 :         assert(f);
     591                 :            : 
     592         [ +  + ]:       2596 :         if (m->type == MATCH_DISCRETE) {
     593                 :            :                 uint64_t dp;
     594                 :            : 
     595                 :        668 :                 r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp);
     596         [ +  + ]:        668 :                 if (r <= 0)
     597                 :        200 :                         return r;
     598                 :            : 
     599                 :            :                 /* FIXME: missing: find by monotonic */
     600                 :            : 
     601         [ +  + ]:        468 :                 if (j->current_location.type == LOCATION_HEAD)
     602                 :         48 :                         return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
     603         [ +  - ]:        420 :                 if (j->current_location.type == LOCATION_TAIL)
     604                 :        420 :                         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         [ +  + ]:       1928 :         } else if (m->type == MATCH_OR_TERM) {
     618                 :       1072 :                 uint64_t np = 0;
     619                 :            :                 Object *n;
     620                 :            :                 Match *i;
     621                 :            : 
     622                 :            :                 /* Find the earliest match */
     623                 :            : 
     624         [ +  + ]:       2168 :                 LIST_FOREACH(matches, i, m->matches) {
     625                 :            :                         uint64_t cp;
     626                 :            : 
     627                 :       1096 :                         r = find_location_for_match(j, i, f, direction, NULL, &cp);
     628         [ -  + ]:       1096 :                         if (r < 0)
     629                 :          0 :                                 return r;
     630         [ +  + ]:       1096 :                         else if (r > 0) {
     631   [ +  +  +  -  :        716 :                                 if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
             +  -  #  # ]
     632                 :        716 :                                         np = cp;
     633                 :            :                         }
     634                 :            :                 }
     635                 :            : 
     636         [ +  + ]:       1072 :                 if (np == 0)
     637                 :        360 :                         return 0;
     638                 :            : 
     639                 :        712 :                 r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
     640         [ -  + ]:        712 :                 if (r < 0)
     641                 :          0 :                         return r;
     642                 :            : 
     643         [ -  + ]:        712 :                 if (ret)
     644                 :          0 :                         *ret = n;
     645         [ +  - ]:        712 :                 if (offset)
     646                 :        712 :                         *offset = np;
     647                 :            : 
     648                 :        712 :                 return 1;
     649                 :            : 
     650                 :            :         } else {
     651                 :            :                 Match *i;
     652                 :        856 :                 uint64_t np = 0;
     653                 :            : 
     654         [ -  + ]:        856 :                 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         [ -  + ]:        856 :                 if (!m->matches)
     660                 :          0 :                         return 0;
     661                 :            : 
     662         [ +  + ]:       1568 :                 LIST_FOREACH(matches, i, m->matches) {
     663                 :            :                         uint64_t cp;
     664                 :            : 
     665                 :       1072 :                         r = find_location_for_match(j, i, f, direction, NULL, &cp);
     666         [ +  + ]:       1072 :                         if (r <= 0)
     667                 :        360 :                                 return r;
     668                 :            : 
     669   [ +  +  +  +  :        712 :                         if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
             -  +  +  + ]
     670                 :        664 :                                 np = cp;
     671                 :            :                 }
     672                 :            : 
     673                 :        496 :                 return next_for_match(j, m, f, np, direction, ret, offset);
     674                 :            :         }
     675                 :            : }
     676                 :            : 
     677                 :        940 : 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         [ -  + ]:        940 :         assert(j);
     687         [ -  + ]:        940 :         assert(f);
     688         [ -  + ]:        940 :         assert(ret);
     689         [ -  + ]:        940 :         assert(offset);
     690                 :            : 
     691         [ +  + ]:        940 :         if (!j->level0) {
     692                 :            :                 /* No matches is simple */
     693                 :            : 
     694         [ +  + ]:        512 :                 if (j->current_location.type == LOCATION_HEAD)
     695                 :        448 :                         return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset);
     696         [ +  + ]:         64 :                 if (j->current_location.type == LOCATION_TAIL)
     697                 :         32 :                         return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset);
     698   [ +  -  +  + ]:         32 :                 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
     699                 :         16 :                         return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
     700         [ +  - ]:         16 :                 if (j->current_location.monotonic_set) {
     701                 :         16 :                         r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset);
     702         [ -  + ]:         16 :                         if (r != -ENOENT)
     703                 :          0 :                                 return r;
     704                 :            :                 }
     705         [ +  - ]:         16 :                 if (j->current_location.realtime_set)
     706                 :         16 :                         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                 :        428 :                 return find_location_for_match(j, j->level0, f, direction, ret, offset);
     711                 :            : }
     712                 :            : 
     713                 :      41824 : 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         [ -  + ]:      41824 :         assert(j);
     721         [ -  + ]:      41824 :         assert(f);
     722         [ -  + ]:      41824 :         assert(ret);
     723         [ -  + ]:      41824 :         assert(offset);
     724                 :            : 
     725                 :            :         /* No matches is easy. We simple advance the file
     726                 :            :          * pointer by one. */
     727         [ +  + ]:      41824 :         if (!j->level0)
     728                 :      41212 :                 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         [ +  + ]:       1224 :         return next_for_match(j, j->level0, f,
     733                 :        388 :                               direction == DIRECTION_DOWN ? f->current_offset + 1
     734                 :        224 :                                                           : f->current_offset - 1,
     735                 :            :                               direction, ret, offset);
     736                 :            : }
     737                 :            : 
     738                 :    4048140 : 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         [ -  + ]:    4048140 :         assert(j);
     744         [ -  + ]:    4048140 :         assert(f);
     745                 :            : 
     746                 :    4048140 :         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   [ +  +  +  + ]:    4048140 :         if (f->last_direction == direction && f->location_type == LOCATION_TAIL &&
     751         [ +  - ]:      41708 :             n_entries == f->last_n_entries)
     752                 :      41708 :                 return 0;
     753                 :            : 
     754                 :    4006432 :         f->last_n_entries = n_entries;
     755                 :            : 
     756   [ +  +  +  + ]:    4006432 :         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         [ +  + ]:    4046856 :                 if (f->location_type != LOCATION_SEEK) {
     761                 :      41480 :                         r = next_with_matches(j, f, direction, &c, &cp);
     762         [ +  + ]:      41480 :                         if (r <= 0)
     763                 :        116 :                                 return r;
     764                 :            : 
     765                 :      41364 :                         journal_file_save_location(f, c, cp);
     766                 :            :                 }
     767                 :            :         } else {
     768                 :        940 :                 f->last_direction = direction;
     769                 :            : 
     770                 :        940 :                 r = find_location_with_matches(j, f, direction, &c, &cp);
     771         [ +  + ]:        940 :                 if (r <= 0)
     772                 :        184 :                         return r;
     773                 :            : 
     774                 :        756 :                 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                 :        324 :         for (;;) {
     784                 :            :                 bool found;
     785                 :            : 
     786         [ +  + ]:    4006456 :                 if (j->current_location.type == LOCATION_DISCRETE) {
     787                 :            :                         int k;
     788                 :            : 
     789                 :    4005732 :                         k = compare_with_location(f, &j->current_location);
     790                 :            : 
     791         [ +  + ]:    4005732 :                         found = direction == DIRECTION_DOWN ? k > 0 : k < 0;
     792                 :            :                 } else
     793                 :        724 :                         found = true;
     794                 :            : 
     795         [ +  + ]:    4006456 :                 if (found)
     796                 :    4006112 :                         return 1;
     797                 :            : 
     798                 :        344 :                 r = next_with_matches(j, f, direction, &c, &cp);
     799         [ +  + ]:        344 :                 if (r <= 0)
     800                 :         20 :                         return r;
     801                 :            : 
     802                 :        324 :                 journal_file_save_location(f, c, cp);
     803                 :            :         }
     804                 :            : }
     805                 :            : 
     806                 :      41556 : static int real_journal_next(sd_journal *j, direction_t direction) {
     807                 :      41556 :         JournalFile *new_file = NULL;
     808                 :            :         unsigned i, n_files;
     809                 :            :         const void **files;
     810                 :            :         Object *o;
     811                 :            :         int r;
     812                 :            : 
     813   [ -  +  -  + ]:      41556 :         assert_return(j, -EINVAL);
     814   [ -  +  -  + ]:      41556 :         assert_return(!journal_pid_changed(j), -ECHILD);
     815                 :            : 
     816                 :      41556 :         r = iterated_cache_get(j->files_cache, NULL, &files, &n_files);
     817         [ -  + ]:      41556 :         if (r < 0)
     818                 :          0 :                 return r;
     819                 :            : 
     820         [ +  + ]:    4089696 :         for (i = 0; i < n_files; i++) {
     821                 :    4048140 :                 JournalFile *f = (JournalFile *)files[i];
     822                 :            :                 bool found;
     823                 :            : 
     824                 :    4048140 :                 r = next_beyond_location(j, f, direction);
     825         [ -  + ]:    4048140 :                 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         [ +  + ]:    4048140 :                 } else if (r == 0) {
     830                 :      42028 :                         f->location_type = LOCATION_TAIL;
     831                 :      42028 :                         continue;
     832                 :            :                 }
     833                 :            : 
     834         [ +  + ]:    4006112 :                 if (!new_file)
     835                 :      41504 :                         found = true;
     836                 :            :                 else {
     837                 :            :                         int k;
     838                 :            : 
     839                 :    3964608 :                         k = journal_file_compare_locations(f, new_file);
     840                 :            : 
     841         [ +  + ]:    3964608 :                         found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
     842                 :            :                 }
     843                 :            : 
     844         [ +  + ]:    4006112 :                 if (found)
     845                 :     164044 :                         new_file = f;
     846                 :            :         }
     847                 :            : 
     848         [ +  + ]:      41556 :         if (!new_file)
     849                 :         52 :                 return 0;
     850                 :            : 
     851                 :      41504 :         r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o);
     852         [ -  + ]:      41504 :         if (r < 0)
     853                 :          0 :                 return r;
     854                 :            : 
     855                 :      41504 :         set_location(j, new_file, o);
     856                 :            : 
     857                 :      41504 :         return 1;
     858                 :            : }
     859                 :            : 
     860                 :      41216 : _public_ int sd_journal_next(sd_journal *j) {
     861                 :      41216 :         return real_journal_next(j, DIRECTION_DOWN);
     862                 :            : }
     863                 :            : 
     864                 :        276 : _public_ int sd_journal_previous(sd_journal *j) {
     865                 :        276 :         return real_journal_next(j, DIRECTION_UP);
     866                 :            : }
     867                 :            : 
     868                 :         16 : static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) {
     869                 :         16 :         int c = 0, r;
     870                 :            : 
     871   [ -  +  -  + ]:         16 :         assert_return(j, -EINVAL);
     872   [ -  +  -  + ]:         16 :         assert_return(!journal_pid_changed(j), -ECHILD);
     873                 :            : 
     874         [ -  + ]:         16 :         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                 :         64 :                 r = real_journal_next(j, direction);
     888         [ -  + ]:         64 :                 if (r < 0)
     889                 :          0 :                         return r;
     890                 :            : 
     891         [ -  + ]:         64 :                 if (r == 0)
     892                 :          0 :                         return c;
     893                 :            : 
     894                 :         64 :                 skip--;
     895                 :         64 :                 c++;
     896         [ +  + ]:         64 :         } while (skip > 0);
     897                 :            : 
     898                 :         16 :         return c;
     899                 :            : }
     900                 :            : 
     901                 :          8 : _public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
     902                 :          8 :         return real_journal_next_skip(j, DIRECTION_DOWN, skip);
     903                 :            : }
     904                 :            : 
     905                 :          8 : _public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
     906                 :          8 :         return real_journal_next_skip(j, DIRECTION_UP, skip);
     907                 :            : }
     908                 :            : 
     909                 :       2256 : _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   [ -  +  -  + ]:       2256 :         assert_return(j, -EINVAL);
     915   [ -  +  -  + ]:       2256 :         assert_return(!journal_pid_changed(j), -ECHILD);
     916   [ -  +  -  + ]:       2256 :         assert_return(cursor, -EINVAL);
     917                 :            : 
     918   [ +  -  -  + ]:       2256 :         if (!j->current_file || j->current_file->current_offset <= 0)
     919                 :          0 :                 return -EADDRNOTAVAIL;
     920                 :            : 
     921                 :       2256 :         r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
     922         [ -  + ]:       2256 :         if (r < 0)
     923                 :          0 :                 return r;
     924                 :            : 
     925                 :       2256 :         sd_id128_to_string(j->current_file->header->seqnum_id, sid);
     926                 :       2256 :         sd_id128_to_string(o->entry.boot_id, bid);
     927                 :            : 
     928         [ -  + ]:       2256 :         if (asprintf(cursor,
     929                 :            :                      "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
     930                 :       2256 :                      sid, le64toh(o->entry.seqnum),
     931                 :       2256 :                      bid, le64toh(o->entry.monotonic),
     932                 :       2256 :                      le64toh(o->entry.realtime),
     933                 :       2256 :                      le64toh(o->entry.xor_hash)) < 0)
     934                 :          0 :                 return -ENOMEM;
     935                 :            : 
     936                 :       2256 :         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                 :       1288 : _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
    1045                 :            :         int r;
    1046                 :            :         Object *o;
    1047                 :            : 
    1048   [ -  +  -  + ]:       1288 :         assert_return(j, -EINVAL);
    1049   [ -  +  -  + ]:       1288 :         assert_return(!journal_pid_changed(j), -ECHILD);
    1050   [ -  +  -  + ]:       1288 :         assert_return(!isempty(cursor), -EINVAL);
    1051                 :            : 
    1052   [ +  -  -  + ]:       1288 :         if (!j->current_file || j->current_file->current_offset <= 0)
    1053                 :          0 :                 return -EADDRNOTAVAIL;
    1054                 :            : 
    1055                 :       1288 :         r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o);
    1056         [ -  + ]:       1288 :         if (r < 0)
    1057                 :          0 :                 return r;
    1058                 :            : 
    1059                 :       7728 :         for (;;) {
    1060      [ +  -  + ]:       9016 :                 _cleanup_free_ char *item = NULL;
    1061                 :            :                 unsigned long long ll;
    1062                 :            :                 sd_id128_t id;
    1063                 :       9016 :                 int k = 0;
    1064                 :            : 
    1065                 :       9016 :                 r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
    1066         [ -  + ]:       9016 :                 if (r < 0)
    1067                 :          0 :                         return r;
    1068                 :            : 
    1069         [ +  + ]:       9016 :                 if (r == 0)
    1070                 :       1288 :                         break;
    1071                 :            : 
    1072   [ +  -  -  + ]:       7728 :                 if (strlen(item) < 2 || item[1] != '=')
    1073                 :          0 :                         return -EINVAL;
    1074                 :            : 
    1075   [ +  +  +  +  :       7728 :                 switch (item[0]) {
                +  +  - ]
    1076                 :            : 
    1077                 :       1288 :                 case 's':
    1078                 :       1288 :                         k = sd_id128_from_string(item+2, &id);
    1079         [ -  + ]:       1288 :                         if (k < 0)
    1080                 :          0 :                                 return k;
    1081         [ -  + ]:       1288 :                         if (!sd_id128_equal(id, j->current_file->header->seqnum_id))
    1082                 :          0 :                                 return 0;
    1083                 :       1288 :                         break;
    1084                 :            : 
    1085                 :       1288 :                 case 'i':
    1086         [ -  + ]:       1288 :                         if (sscanf(item+2, "%llx", &ll) != 1)
    1087                 :          0 :                                 return -EINVAL;
    1088         [ -  + ]:       1288 :                         if (ll != le64toh(o->entry.seqnum))
    1089                 :          0 :                                 return 0;
    1090                 :       1288 :                         break;
    1091                 :            : 
    1092                 :       1288 :                 case 'b':
    1093                 :       1288 :                         k = sd_id128_from_string(item+2, &id);
    1094         [ -  + ]:       1288 :                         if (k < 0)
    1095                 :          0 :                                 return k;
    1096         [ -  + ]:       1288 :                         if (!sd_id128_equal(id, o->entry.boot_id))
    1097                 :          0 :                                 return 0;
    1098                 :       1288 :                         break;
    1099                 :            : 
    1100                 :       1288 :                 case 'm':
    1101         [ -  + ]:       1288 :                         if (sscanf(item+2, "%llx", &ll) != 1)
    1102                 :          0 :                                 return -EINVAL;
    1103         [ -  + ]:       1288 :                         if (ll != le64toh(o->entry.monotonic))
    1104                 :          0 :                                 return 0;
    1105                 :       1288 :                         break;
    1106                 :            : 
    1107                 :       1288 :                 case 't':
    1108         [ -  + ]:       1288 :                         if (sscanf(item+2, "%llx", &ll) != 1)
    1109                 :          0 :                                 return -EINVAL;
    1110         [ -  + ]:       1288 :                         if (ll != le64toh(o->entry.realtime))
    1111                 :          0 :                                 return 0;
    1112                 :       1288 :                         break;
    1113                 :            : 
    1114                 :       1288 :                 case 'x':
    1115         [ -  + ]:       1288 :                         if (sscanf(item+2, "%llx", &ll) != 1)
    1116                 :          0 :                                 return -EINVAL;
    1117         [ -  + ]:       1288 :                         if (ll != le64toh(o->entry.xor_hash))
    1118                 :          0 :                                 return 0;
    1119                 :       1288 :                         break;
    1120                 :            :                 }
    1121                 :       7728 :         }
    1122                 :            : 
    1123                 :       1288 :         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                 :         36 : _public_ int sd_journal_seek_head(sd_journal *j) {
    1152   [ -  +  -  + ]:         36 :         assert_return(j, -EINVAL);
    1153   [ -  +  -  + ]:         36 :         assert_return(!journal_pid_changed(j), -ECHILD);
    1154                 :            : 
    1155                 :         36 :         reset_location(j);
    1156                 :         36 :         j->current_location.type = LOCATION_HEAD;
    1157                 :            : 
    1158                 :         36 :         return 0;
    1159                 :            : }
    1160                 :            : 
    1161                 :         24 : _public_ int sd_journal_seek_tail(sd_journal *j) {
    1162   [ -  +  -  + ]:         24 :         assert_return(j, -EINVAL);
    1163   [ -  +  -  + ]:         24 :         assert_return(!journal_pid_changed(j), -ECHILD);
    1164                 :            : 
    1165                 :         24 :         reset_location(j);
    1166                 :         24 :         j->current_location.type = LOCATION_TAIL;
    1167                 :            : 
    1168                 :         24 :         return 0;
    1169                 :            : }
    1170                 :            : 
    1171                 :      40620 : static void check_network(sd_journal *j, int fd) {
    1172         [ -  + ]:      40620 :         assert(j);
    1173                 :            : 
    1174         [ -  + ]:      40620 :         if (j->on_network)
    1175                 :          0 :                 return;
    1176                 :            : 
    1177                 :      40620 :         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                 :      39264 : static bool file_type_wanted(int flags, const char *filename) {
    1192         [ -  + ]:      39264 :         assert(filename);
    1193                 :            : 
    1194   [ +  +  -  + ]:      39264 :         if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
    1195                 :          0 :                 return false;
    1196                 :            : 
    1197                 :            :         /* no flags set → every type is OK */
    1198         [ +  - ]:      39264 :         if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
    1199                 :      39264 :                 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                 :      44560 : static bool path_has_prefix(sd_journal *j, const char *path, const char *prefix) {
    1217         [ -  + ]:      44560 :         assert(j);
    1218         [ -  + ]:      44560 :         assert(path);
    1219         [ -  + ]:      44560 :         assert(prefix);
    1220                 :            : 
    1221         [ -  + ]:      44560 :         if (j->toplevel_fd >= 0)
    1222                 :          0 :                 return false;
    1223                 :            : 
    1224                 :      44560 :         return path_startswith(path, prefix);
    1225                 :            : }
    1226                 :            : 
    1227                 :      39264 : static void track_file_disposition(sd_journal *j, JournalFile *f) {
    1228         [ -  + ]:      39264 :         assert(j);
    1229         [ -  + ]:      39264 :         assert(f);
    1230                 :            : 
    1231   [ +  -  -  + ]:      39264 :         if (!j->has_runtime_files && path_has_prefix(j, f->path, "/run"))
    1232                 :          0 :                 j->has_runtime_files = true;
    1233   [ +  +  +  - ]:      39264 :         else if (!j->has_persistent_files && path_has_prefix(j, f->path, "/var"))
    1234                 :        448 :                 j->has_persistent_files = true;
    1235                 :      39264 : }
    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                 :      39264 : static int add_any_file(
    1249                 :            :                 sd_journal *j,
    1250                 :            :                 int fd,
    1251                 :            :                 const char *path) {
    1252                 :            : 
    1253                 :      39264 :         bool close_fd = false;
    1254                 :            :         JournalFile *f;
    1255                 :            :         struct stat st;
    1256                 :            :         int r, k;
    1257                 :            : 
    1258         [ -  + ]:      39264 :         assert(j);
    1259   [ +  -  -  + ]:      39264 :         assert(fd >= 0 || path);
    1260                 :            : 
    1261         [ +  - ]:      39264 :         if (fd < 0) {
    1262         [ -  + ]:      39264 :                 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                 :      39264 :                         fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
    1269         [ -  + ]:      39264 :                 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                 :      39264 :                 close_fd = true;
    1275                 :            : 
    1276                 :      39264 :                 r = fd_nonblock(fd, false);
    1277         [ -  + ]:      39264 :                 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         [ -  + ]:      39264 :         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                 :      39264 :         r = stat_verify_regular(&st);
    1289         [ -  + ]:      39264 :         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                 :      39264 :         f = ordered_hashmap_get(j->files, path);
    1295         [ -  + ]:      39264 :         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         [ -  + ]:      39264 :         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                 :      39264 :         r = journal_file_open(fd, path, O_RDONLY, 0, false, 0, false, NULL, j->mmap, NULL, NULL, &f);
    1322         [ -  + ]:      39264 :         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                 :      39264 :         r = ordered_hashmap_put(j->files, f->path, f);
    1330         [ -  + ]:      39264 :         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                 :      39264 :         close_fd = false; /* the fd is now owned by the JournalFile object */
    1337                 :            : 
    1338                 :      39264 :         f->last_seen_generation = j->generation;
    1339                 :            : 
    1340                 :      39264 :         track_file_disposition(j, f);
    1341                 :      39264 :         check_network(j, f->fd);
    1342                 :            : 
    1343                 :      39264 :         j->current_invalidate_counter++;
    1344                 :            : 
    1345         [ +  + ]:      39264 :         log_debug("File %s added.", f->path);
    1346                 :            : 
    1347                 :      39264 :         r = 0;
    1348                 :            : 
    1349                 :      39264 : finish:
    1350         [ -  + ]:      39264 :         if (close_fd)
    1351                 :          0 :                 safe_close(fd);
    1352                 :            : 
    1353         [ -  + ]:      39264 :         if (r < 0) {
    1354                 :          0 :                 k = journal_put_error(j, r, path);
    1355         [ #  # ]:          0 :                 if (k < 0)
    1356                 :          0 :                         return k;
    1357                 :            :         }
    1358                 :            : 
    1359                 :      39264 :         return r;
    1360                 :            : }
    1361                 :            : 
    1362                 :      39264 : 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         [ -  + ]:      39264 :         assert(j);
    1370         [ -  + ]:      39264 :         assert(prefix);
    1371         [ -  + ]:      39264 :         assert(filename);
    1372                 :            : 
    1373         [ -  + ]:      39264 :         if (j->no_new_files)
    1374                 :          0 :                 return 0;
    1375                 :            : 
    1376         [ -  + ]:      39264 :         if (!file_type_wanted(j->flags, filename))
    1377                 :          0 :                 return 0;
    1378                 :            : 
    1379   [ -  +  #  #  :      39264 :         path = prefix_roota(prefix, filename);
          -  +  -  +  -  
          +  +  -  -  +  
                   +  - ]
    1380                 :      39264 :         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                 :       5252 : static int dirname_is_machine_id(const char *fn) {
    1437                 :            :         sd_id128_t id, machine;
    1438                 :            :         int r;
    1439                 :            : 
    1440                 :       5252 :         r = sd_id128_get_machine(&machine);
    1441         [ -  + ]:       5252 :         if (r < 0)
    1442                 :          0 :                 return r;
    1443                 :            : 
    1444                 :       5252 :         r = sd_id128_from_string(fn, &id);
    1445         [ -  + ]:       5252 :         if (r < 0)
    1446                 :          0 :                 return r;
    1447                 :            : 
    1448                 :       5252 :         return sd_id128_equal(id, machine);
    1449                 :            : }
    1450                 :            : 
    1451                 :      47332 : static bool dirent_is_journal_file(const struct dirent *de) {
    1452         [ -  + ]:      47332 :         assert(de);
    1453                 :            : 
    1454   [ +  +  +  + ]:      47332 :         if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN))
    1455                 :       8068 :                 return false;
    1456                 :            : 
    1457         [ +  + ]:      46268 :         return endswith(de->d_name, ".journal") ||
    1458         [ +  - ]:       7004 :                 endswith(de->d_name, ".journal~");
    1459                 :            : }
    1460                 :            : 
    1461                 :       7128 : static bool dirent_is_id128_subdir(const struct dirent *de) {
    1462         [ -  + ]:       7128 :         assert(de);
    1463                 :            : 
    1464   [ +  +  +  + ]:       7128 :         if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN))
    1465                 :         76 :                 return false;
    1466                 :            : 
    1467                 :       7052 :         return id128_is_valid(de->d_name);
    1468                 :            : }
    1469                 :            : 
    1470                 :       1776 : static int directory_open(sd_journal *j, const char *path, DIR **ret) {
    1471                 :            :         DIR *d;
    1472                 :            : 
    1473         [ -  + ]:       1776 :         assert(j);
    1474         [ -  + ]:       1776 :         assert(path);
    1475         [ -  + ]:       1776 :         assert(ret);
    1476                 :            : 
    1477         [ +  - ]:       1776 :         if (j->toplevel_fd < 0)
    1478                 :       1776 :                 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         [ +  + ]:       1776 :         if (!d)
    1484                 :        420 :                 return -errno;
    1485                 :            : 
    1486                 :       1356 :         *ret = d;
    1487                 :       1356 :         return 0;
    1488                 :            : }
    1489                 :            : 
    1490                 :            : static int add_directory(sd_journal *j, const char *prefix, const char *dirname);
    1491                 :            : 
    1492                 :       1356 : static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) {
    1493                 :            :         struct dirent *de;
    1494                 :            : 
    1495         [ -  + ]:       1356 :         assert(j);
    1496         [ -  + ]:       1356 :         assert(m);
    1497         [ -  + ]:       1356 :         assert(d);
    1498                 :            : 
    1499   [ +  +  -  + ]:      48688 :         FOREACH_DIRENT_ALL(de, d, goto fail) {
    1500                 :            : 
    1501         [ +  + ]:      47332 :                 if (dirent_is_journal_file(de))
    1502                 :      39264 :                         (void) add_file_by_name(j, m->path, de->d_name);
    1503                 :            : 
    1504   [ +  +  +  + ]:      47332 :                 if (m->is_root && dirent_is_id128_subdir(de))
    1505                 :       5356 :                         (void) add_directory(j, m->path, de->d_name);
    1506                 :            :         }
    1507                 :            : 
    1508                 :       1356 :         return;
    1509                 :            : 
    1510                 :          0 : fail:
    1511         [ #  # ]:          0 :         log_debug_errno(errno, "Failed to enumerate directory %s, ignoring: %m", m->path);
    1512                 :            : }
    1513                 :            : 
    1514                 :       1356 : static void directory_watch(sd_journal *j, Directory *m, int fd, uint32_t mask) {
    1515                 :            :         int r;
    1516                 :            : 
    1517         [ -  + ]:       1356 :         assert(j);
    1518         [ -  + ]:       1356 :         assert(m);
    1519         [ -  + ]:       1356 :         assert(fd >= 0);
    1520                 :            : 
    1521                 :            :         /* Watch this directory if that's enabled and if it not being watched yet. */
    1522                 :            : 
    1523         [ -  + ]:       1356 :         if (m->wd > 0) /* Already have a watch? */
    1524                 :          0 :                 return;
    1525         [ +  - ]:       1356 :         if (j->inotify_fd < 0) /* Not watching at all? */
    1526                 :       1356 :                 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                 :       5356 : static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
    1545                 :       5356 :         _cleanup_free_ char *path = NULL;
    1546                 :       5356 :         _cleanup_closedir_ DIR *d = NULL;
    1547                 :            :         Directory *m;
    1548                 :            :         int r, k;
    1549                 :            : 
    1550         [ -  + ]:       5356 :         assert(j);
    1551         [ -  + ]:       5356 :         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                 :       5356 :         path = path_join(prefix, dirname);
    1557         [ -  + ]:       5356 :         if (!path) {
    1558                 :          0 :                 r = -ENOMEM;
    1559                 :          0 :                 goto fail;
    1560                 :            :         }
    1561                 :            : 
    1562         [ +  + ]:       5356 :         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   [ +  +  +  - ]:       5356 :         if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
    1566   [ +  +  +  - ]:       5252 :             !((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
    1567                 :       4848 :                 return 0;
    1568                 :            : 
    1569                 :        508 :         r = directory_open(j, path, &d);
    1570         [ -  + ]:        508 :         if (r < 0) {
    1571         [ #  # ]:          0 :                 log_debug_errno(r, "Failed to open directory '%s': %m", path);
    1572                 :          0 :                 goto fail;
    1573                 :            :         }
    1574                 :            : 
    1575                 :        508 :         m = hashmap_get(j->directories_by_path, path);
    1576         [ +  - ]:        508 :         if (!m) {
    1577                 :        508 :                 m = new0(Directory, 1);
    1578         [ -  + ]:        508 :                 if (!m) {
    1579                 :          0 :                         r = -ENOMEM;
    1580                 :          0 :                         goto fail;
    1581                 :            :                 }
    1582                 :            : 
    1583                 :        508 :                 m->is_root = false;
    1584                 :        508 :                 m->path = path;
    1585                 :            : 
    1586         [ -  + ]:        508 :                 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                 :        508 :                 path = NULL; /* avoid freeing in cleanup */
    1593                 :        508 :                 j->current_invalidate_counter++;
    1594                 :            : 
    1595         [ +  + ]:        508 :                 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                 :        508 :         m->last_seen_generation = j->generation;
    1601                 :            : 
    1602                 :        508 :         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         [ +  - ]:        508 :         if (!j->no_new_files)
    1608                 :        508 :                 directory_enumerate(j, m, d);
    1609                 :            : 
    1610                 :        508 :         check_network(j, dirfd(d));
    1611                 :            : 
    1612                 :        508 :         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                 :       1268 : static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
    1623                 :            : 
    1624                 :       1268 :         _cleanup_closedir_ DIR *d = NULL;
    1625                 :            :         Directory *m;
    1626                 :            :         int r, k;
    1627                 :            : 
    1628         [ -  + ]:       1268 :         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         [ +  - ]:       1268 :         if (p) {
    1635                 :            :                 /* If there's a path specified, use it. */
    1636                 :            : 
    1637         [ +  + ]:       1268 :                 log_debug("Considering root directory '%s'.", p);
    1638                 :            : 
    1639         [ -  + ]:       1268 :                 if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
    1640         [ #  # ]:          0 :                     !path_has_prefix(j, p, "/run"))
    1641                 :          0 :                         return -EINVAL;
    1642                 :            : 
    1643         [ -  + ]:       1268 :                 if (j->prefix)
    1644   [ #  #  #  #  :          0 :                         p = strjoina(j->prefix, p);
          #  #  #  #  #  
                #  #  # ]
    1645                 :            : 
    1646                 :       1268 :                 r = directory_open(j, p, &d);
    1647   [ +  +  +  - ]:       1268 :                 if (r == -ENOENT && missing_ok)
    1648                 :        420 :                         return 0;
    1649         [ -  + ]:        848 :                 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                 :        848 :         m = hashmap_get(j->directories_by_path, p);
    1678         [ +  - ]:        848 :         if (!m) {
    1679                 :        848 :                 m = new0(Directory, 1);
    1680         [ -  + ]:        848 :                 if (!m) {
    1681                 :          0 :                         r = -ENOMEM;
    1682                 :          0 :                         goto fail;
    1683                 :            :                 }
    1684                 :            : 
    1685                 :        848 :                 m->is_root = true;
    1686                 :            : 
    1687                 :        848 :                 m->path = strdup(p);
    1688         [ -  + ]:        848 :                 if (!m->path) {
    1689                 :          0 :                         free(m);
    1690                 :          0 :                         r = -ENOMEM;
    1691                 :          0 :                         goto fail;
    1692                 :            :                 }
    1693                 :            : 
    1694         [ -  + ]:        848 :                 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                 :        848 :                 j->current_invalidate_counter++;
    1702                 :            : 
    1703         [ +  + ]:        848 :                 log_debug("Root directory %s added.", m->path);
    1704                 :            : 
    1705         [ #  # ]:          0 :         } else if (!m->is_root)
    1706                 :          0 :                 return 0;
    1707                 :            : 
    1708                 :        848 :         directory_watch(j, m, dirfd(d),
    1709                 :            :                         IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
    1710                 :            :                         IN_ONLYDIR);
    1711                 :            : 
    1712         [ +  - ]:        848 :         if (!j->no_new_files)
    1713                 :        848 :                 directory_enumerate(j, m, d);
    1714                 :            : 
    1715                 :        848 :         check_network(j, dirfd(d));
    1716                 :            : 
    1717                 :        848 :         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                 :       1356 : static void remove_directory(sd_journal *j, Directory *d) {
    1728         [ -  + ]:       1356 :         assert(j);
    1729                 :            : 
    1730         [ -  + ]:       1356 :         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                 :       1356 :         hashmap_remove(j->directories_by_path, d->path);
    1738                 :            : 
    1739         [ +  + ]:       1356 :         if (d->is_root)
    1740         [ +  + ]:        848 :                 log_debug("Root directory %s removed.", d->path);
    1741                 :            :         else
    1742         [ +  + ]:        508 :                 log_debug("Directory %s removed.", d->path);
    1743                 :            : 
    1744                 :       1356 :         free(d->path);
    1745                 :       1356 :         free(d);
    1746                 :       1356 : }
    1747                 :            : 
    1748                 :        412 : 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         [ -  + ]:        412 :         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   [ +  -  +  + ]:       1236 :         NULSTR_FOREACH(p, search_paths)
    1761                 :        824 :                 (void) add_root_directory(j, p, true);
    1762                 :            : 
    1763         [ +  + ]:        412 :         if (!(j->flags & SD_JOURNAL_LOCAL_ONLY))
    1764                 :          8 :                 (void) add_root_directory(j, "/var/log/journal/remote", true);
    1765                 :            : 
    1766                 :        412 :         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                 :        848 : static sd_journal *journal_new(int flags, const char *path) {
    1808                 :        848 :         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
    1809                 :            : 
    1810                 :        848 :         j = new0(sd_journal, 1);
    1811         [ -  + ]:        848 :         if (!j)
    1812                 :          0 :                 return NULL;
    1813                 :            : 
    1814                 :        848 :         j->original_pid = getpid_cached();
    1815                 :        848 :         j->toplevel_fd = -1;
    1816                 :        848 :         j->inotify_fd = -1;
    1817                 :        848 :         j->flags = flags;
    1818                 :        848 :         j->data_threshold = DEFAULT_DATA_THRESHOLD;
    1819                 :            : 
    1820         [ +  + ]:        848 :         if (path) {
    1821                 :            :                 char *t;
    1822                 :            : 
    1823                 :        436 :                 t = strdup(path);
    1824         [ -  + ]:        436 :                 if (!t)
    1825                 :          0 :                         return NULL;
    1826                 :            : 
    1827         [ -  + ]:        436 :                 if (flags & SD_JOURNAL_OS_ROOT)
    1828                 :          0 :                         j->prefix = t;
    1829                 :            :                 else
    1830                 :        436 :                         j->path = t;
    1831                 :            :         }
    1832                 :            : 
    1833                 :        848 :         j->files = ordered_hashmap_new(&path_hash_ops);
    1834         [ -  + ]:        848 :         if (!j->files)
    1835                 :          0 :                 return NULL;
    1836                 :            : 
    1837                 :        848 :         j->files_cache = ordered_hashmap_iterated_cache_new(j->files);
    1838                 :        848 :         j->directories_by_path = hashmap_new(&path_hash_ops);
    1839                 :        848 :         j->mmap = mmap_cache_new();
    1840   [ +  -  +  -  :        848 :         if (!j->files_cache || !j->directories_by_path || !j->mmap)
                   -  + ]
    1841                 :          0 :                 return NULL;
    1842                 :            : 
    1843                 :        848 :         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                 :        412 : _public_ int sd_journal_open(sd_journal **ret, int flags) {
    1852                 :        412 :         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
    1853                 :            :         int r;
    1854                 :            : 
    1855   [ -  +  -  + ]:        412 :         assert_return(ret, -EINVAL);
    1856   [ -  +  -  + ]:        412 :         assert_return((flags & ~OPEN_ALLOWED_FLAGS) == 0, -EINVAL);
    1857                 :            : 
    1858                 :        412 :         j = journal_new(flags, NULL);
    1859         [ -  + ]:        412 :         if (!j)
    1860                 :          0 :                 return -ENOMEM;
    1861                 :            : 
    1862                 :        412 :         r = add_search_paths(j);
    1863         [ -  + ]:        412 :         if (r < 0)
    1864                 :          0 :                 return r;
    1865                 :            : 
    1866                 :        412 :         *ret = TAKE_PTR(j);
    1867                 :        412 :         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                 :        836 : _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
    1918                 :        836 :         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
    1919                 :            :         int r;
    1920                 :            : 
    1921   [ -  +  -  + ]:        836 :         assert_return(ret, -EINVAL);
    1922   [ -  +  -  + ]:        836 :         assert_return(path, -EINVAL);
    1923   [ +  +  +  + ]:        836 :         assert_return((flags & ~OPEN_DIRECTORY_ALLOWED_FLAGS) == 0, -EINVAL);
    1924                 :            : 
    1925                 :        436 :         j = journal_new(flags, path);
    1926         [ -  + ]:        436 :         if (!j)
    1927                 :          0 :                 return -ENOMEM;
    1928                 :            : 
    1929         [ -  + ]:        436 :         if (flags & SD_JOURNAL_OS_ROOT)
    1930                 :          0 :                 r = add_search_paths(j);
    1931                 :            :         else
    1932                 :        436 :                 r = add_root_directory(j, path, false);
    1933         [ -  + ]:        436 :         if (r < 0)
    1934                 :          0 :                 return r;
    1935                 :            : 
    1936                 :        436 :         *ret = TAKE_PTR(j);
    1937                 :        436 :         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                 :        848 : _public_ void sd_journal_close(sd_journal *j) {
    2053                 :            :         Directory *d;
    2054                 :            : 
    2055         [ -  + ]:        848 :         if (!j)
    2056                 :          0 :                 return;
    2057                 :            : 
    2058                 :        848 :         sd_journal_flush_matches(j);
    2059                 :            : 
    2060         [ +  + ]:      40112 :         ordered_hashmap_free_with_destructor(j->files, journal_file_close);
    2061                 :        848 :         iterated_cache_free(j->files_cache);
    2062                 :            : 
    2063         [ +  + ]:       2204 :         while ((d = hashmap_first(j->directories_by_path)))
    2064                 :       1356 :                 remove_directory(j, d);
    2065                 :            : 
    2066         [ -  + ]:        848 :         while ((d = hashmap_first(j->directories_by_wd)))
    2067                 :          0 :                 remove_directory(j, d);
    2068                 :            : 
    2069                 :        848 :         hashmap_free(j->directories_by_path);
    2070                 :        848 :         hashmap_free(j->directories_by_wd);
    2071                 :            : 
    2072                 :        848 :         safe_close(j->inotify_fd);
    2073                 :            : 
    2074         [ +  - ]:        848 :         if (j->mmap) {
    2075         [ +  + ]:        848 :                 log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap));
    2076                 :        848 :                 mmap_cache_unref(j->mmap);
    2077                 :            :         }
    2078                 :            : 
    2079                 :        848 :         hashmap_free_free(j->errors);
    2080                 :            : 
    2081                 :        848 :         free(j->path);
    2082                 :        848 :         free(j->prefix);
    2083                 :        848 :         free(j->unique_field);
    2084                 :        848 :         free(j->fields_buffer);
    2085                 :        848 :         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                 :       2428 : static bool field_is_valid(const char *field) {
    2150                 :            :         const char *p;
    2151                 :            : 
    2152         [ -  + ]:       2428 :         assert(field);
    2153                 :            : 
    2154         [ -  + ]:       2428 :         if (isempty(field))
    2155                 :          0 :                 return false;
    2156                 :            : 
    2157         [ -  + ]:       2428 :         if (startswith(field, "__"))
    2158                 :          0 :                 return false;
    2159                 :            : 
    2160         [ +  + ]:      16068 :         for (p = field; *p; p++) {
    2161                 :            : 
    2162         [ -  + ]:      13640 :                 if (*p == '_')
    2163                 :          0 :                         continue;
    2164                 :            : 
    2165   [ +  -  +  - ]:      13640 :                 if (*p >= 'A' && *p <= 'Z')
    2166                 :      13640 :                         continue;
    2167                 :            : 
    2168   [ #  #  #  # ]:          0 :                 if (*p >= '0' && *p <= '9')
    2169                 :          0 :                         continue;
    2170                 :            : 
    2171                 :          0 :                 return false;
    2172                 :            :         }
    2173                 :            : 
    2174                 :       2428 :         return true;
    2175                 :            : }
    2176                 :            : 
    2177                 :       2424 : _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   [ -  +  -  + ]:       2424 :         assert_return(j, -EINVAL);
    2185   [ -  +  -  + ]:       2424 :         assert_return(!journal_pid_changed(j), -ECHILD);
    2186   [ -  +  -  + ]:       2424 :         assert_return(field, -EINVAL);
    2187   [ -  +  -  + ]:       2424 :         assert_return(data, -EINVAL);
    2188   [ -  +  -  + ]:       2424 :         assert_return(size, -EINVAL);
    2189   [ -  +  -  + ]:       2424 :         assert_return(field_is_valid(field), -EINVAL);
    2190                 :            : 
    2191                 :       2424 :         f = j->current_file;
    2192         [ -  + ]:       2424 :         if (!f)
    2193                 :          0 :                 return -EADDRNOTAVAIL;
    2194                 :            : 
    2195         [ -  + ]:       2424 :         if (f->current_offset <= 0)
    2196                 :          0 :                 return -EADDRNOTAVAIL;
    2197                 :            : 
    2198                 :       2424 :         r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
    2199         [ -  + ]:       2424 :         if (r < 0)
    2200                 :          0 :                 return r;
    2201                 :            : 
    2202                 :       2424 :         field_length = strlen(field);
    2203                 :            : 
    2204                 :       2424 :         n = journal_file_entry_n_items(o);
    2205         [ +  - ]:       4282 :         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                 :       4282 :                 p = le64toh(o->entry.items[i].object_offset);
    2212                 :       4282 :                 le_hash = o->entry.items[i].hash;
    2213                 :       4282 :                 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
    2214         [ -  + ]:       4282 :                 if (r < 0)
    2215                 :          0 :                         return r;
    2216                 :            : 
    2217         [ -  + ]:       4282 :                 if (le_hash != o->data.hash)
    2218                 :          0 :                         return -EBADMSG;
    2219                 :            : 
    2220                 :       4282 :                 l = le64toh(o->object.size) - offsetof(Object, data.payload);
    2221                 :            : 
    2222                 :       4282 :                 compression = o->object.flags & OBJECT_COMPRESSION_MASK;
    2223         [ -  + ]:       4282 :                 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         [ +  + ]:       4282 :                 } else if (l >= field_length+1 &&
    2252         [ +  + ]:       4227 :                            memcmp(o->data.payload, field, field_length) == 0 &&
    2253         [ +  - ]:       2424 :                            o->data.payload[field_length] == '=') {
    2254                 :            : 
    2255                 :       2424 :                         t = (size_t) l;
    2256                 :            : 
    2257         [ -  + ]:       2424 :                         if ((uint64_t) t != l)
    2258                 :          0 :                                 return -E2BIG;
    2259                 :            : 
    2260                 :       2424 :                         *data = o->data.payload;
    2261                 :       2424 :                         *size = t;
    2262                 :            : 
    2263                 :       2424 :                         return 0;
    2264                 :            :                 }
    2265                 :            : 
    2266                 :       1858 :                 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
    2267         [ -  + ]:       1858 :                 if (r < 0)
    2268                 :          0 :                         return r;
    2269                 :            :         }
    2270                 :            : 
    2271                 :          0 :         return -ENOENT;
    2272                 :            : }
    2273                 :            : 
    2274                 :       1840 : 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                 :       1840 :         l = le64toh(o->object.size) - offsetof(Object, data.payload);
    2280                 :       1840 :         t = (size_t) l;
    2281                 :            : 
    2282                 :            :         /* We can't read objects larger than 4G on a 32bit machine */
    2283         [ -  + ]:       1840 :         if ((uint64_t) t != l)
    2284                 :          0 :                 return -E2BIG;
    2285                 :            : 
    2286                 :       1840 :         compression = o->object.flags & OBJECT_COMPRESSION_MASK;
    2287         [ -  + ]:       1840 :         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                 :       1840 :                 *data = o->data.payload;
    2305                 :       1840 :                 *size = t;
    2306                 :            :         }
    2307                 :            : 
    2308                 :       1840 :         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                 :          4 : _public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
    2742                 :            :         char *f;
    2743                 :            : 
    2744   [ -  +  -  + ]:          4 :         assert_return(j, -EINVAL);
    2745   [ -  +  -  + ]:          4 :         assert_return(!journal_pid_changed(j), -ECHILD);
    2746   [ -  +  -  + ]:          4 :         assert_return(!isempty(field), -EINVAL);
    2747   [ -  +  -  + ]:          4 :         assert_return(field_is_valid(field), -EINVAL);
    2748                 :            : 
    2749                 :          4 :         f = strdup(field);
    2750         [ -  + ]:          4 :         if (!f)
    2751                 :          0 :                 return -ENOMEM;
    2752                 :            : 
    2753                 :          4 :         free(j->unique_field);
    2754                 :          4 :         j->unique_field = f;
    2755                 :          4 :         j->unique_file = NULL;
    2756                 :          4 :         j->unique_offset = 0;
    2757                 :          4 :         j->unique_file_lost = false;
    2758                 :            : 
    2759                 :          4 :         return 0;
    2760                 :            : }
    2761                 :            : 
    2762                 :        804 : _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
    2763                 :            :         size_t k;
    2764                 :            : 
    2765   [ -  +  -  + ]:        804 :         assert_return(j, -EINVAL);
    2766   [ -  +  -  + ]:        804 :         assert_return(!journal_pid_changed(j), -ECHILD);
    2767   [ -  +  -  + ]:        804 :         assert_return(data, -EINVAL);
    2768   [ -  +  -  + ]:        804 :         assert_return(l, -EINVAL);
    2769   [ -  +  -  + ]:        804 :         assert_return(j->unique_field, -EINVAL);
    2770                 :            : 
    2771                 :        804 :         k = strlen(j->unique_field);
    2772                 :            : 
    2773         [ +  + ]:        804 :         if (!j->unique_file) {
    2774         [ -  + ]:          4 :                 if (j->unique_file_lost)
    2775                 :          0 :                         return 0;
    2776                 :            : 
    2777                 :          4 :                 j->unique_file = ordered_hashmap_first(j->files);
    2778         [ -  + ]:          4 :                 if (!j->unique_file)
    2779                 :          0 :                         return 0;
    2780                 :            : 
    2781                 :          4 :                 j->unique_offset = 0;
    2782                 :            :         }
    2783                 :            : 
    2784                 :        248 :         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         [ +  + ]:       1052 :                 if (j->unique_offset == 0) {
    2795                 :         12 :                         r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL);
    2796         [ -  + ]:         12 :                         if (r < 0)
    2797                 :        804 :                                 return r;
    2798                 :            : 
    2799         [ +  - ]:         12 :                         j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0;
    2800                 :            :                 } else {
    2801                 :       1040 :                         r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o);
    2802         [ -  + ]:       1040 :                         if (r < 0)
    2803                 :          0 :                                 return r;
    2804                 :            : 
    2805                 :       1040 :                         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         [ +  + ]:       1052 :                 if (j->unique_offset == 0) {
    2810                 :         12 :                         j->unique_file = ordered_hashmap_next(j->files, j->unique_file->path);
    2811         [ +  + ]:         12 :                         if (!j->unique_file)
    2812                 :          4 :                                 return 0;
    2813                 :            : 
    2814                 :        248 :                         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                 :       1040 :                 r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o);
    2821         [ -  + ]:       1040 :                 if (r < 0)
    2822                 :          0 :                         return r;
    2823                 :            : 
    2824                 :            :                 /* Let's do the type check by hand, since we used 0 context above. */
    2825         [ -  + ]:       1040 :                 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                 :       1040 :                 r = return_data(j, j->unique_file, o, &odata, &ol);
    2833         [ -  + ]:       1040 :                 if (r < 0)
    2834                 :          0 :                         return r;
    2835                 :            : 
    2836                 :            :                 /* Check if we have at least the field name and "=". */
    2837         [ -  + ]:       1040 :                 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   [ +  -  -  + ]:       1040 :                 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                 :       1040 :                 found = false;
    2854         [ +  - ]:       2000 :                 ORDERED_HASHMAP_FOREACH(of, j->files, i) {
    2855         [ +  + ]:       2000 :                         if (of == j->unique_file)
    2856                 :        800 :                                 break;
    2857                 :            : 
    2858                 :            :                         /* Skip this file it didn't have any fields indexed */
    2859   [ +  -  -  + ]:       1200 :                         if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0)
    2860                 :          0 :                                 continue;
    2861                 :            : 
    2862                 :       1200 :                         r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), NULL, NULL);
    2863         [ -  + ]:       1200 :                         if (r < 0)
    2864                 :          0 :                                 return r;
    2865         [ +  + ]:       1200 :                         if (r > 0) {
    2866                 :        240 :                                 found = true;
    2867                 :        240 :                                 break;
    2868                 :            :                         }
    2869                 :            :                 }
    2870                 :            : 
    2871         [ +  + ]:       1040 :                 if (found)
    2872                 :        240 :                         continue;
    2873                 :            : 
    2874                 :        800 :                 r = return_data(j, j->unique_file, o, data, l);
    2875         [ -  + ]:        800 :                 if (r < 0)
    2876                 :          0 :                         return r;
    2877                 :            : 
    2878                 :        800 :                 return 1;
    2879                 :            :         }
    2880                 :            : }
    2881                 :            : 
    2882                 :          4 : _public_ void sd_journal_restart_unique(sd_journal *j) {
    2883         [ -  + ]:          4 :         if (!j)
    2884                 :          0 :                 return;
    2885                 :            : 
    2886                 :          4 :         j->unique_file = NULL;
    2887                 :          4 :         j->unique_offset = 0;
    2888                 :          4 :         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                 :          4 : _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) {
    3109   [ -  +  -  + ]:          4 :         assert_return(j, -EINVAL);
    3110   [ -  +  -  + ]:          4 :         assert_return(!journal_pid_changed(j), -ECHILD);
    3111                 :            : 
    3112                 :          4 :         j->data_threshold = sz;
    3113                 :          4 :         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