[systemd-commits] 17 commits - Makefile.am Makefile-man.am man/journalctl.xml man/sd_journal_open.xml shell-completion/bash shell-completion/systemd-zsh-completion.zsh src/core src/journal src/libudev src/login src/python-systemd src/shared src/systemd src/test TODO

Zbigniew Jędrzejewski-Szmek zbyszek at kemper.freedesktop.org
Mon Jun 10 07:18:59 PDT 2013


 Makefile-man.am                             |   15 +
 Makefile.am                                 |    9 
 TODO                                        |    5 
 man/journalctl.xml                          |   46 +++-
 man/sd_journal_open.xml                     |   52 ++++
 shell-completion/bash/journalctl            |    1 
 shell-completion/systemd-zsh-completion.zsh |    2 
 src/core/execute.c                          |    2 
 src/journal/journal-authenticate.c          |   10 
 src/journal/journal-file.c                  |  101 ++++-----
 src/journal/journal-file.h                  |   18 +
 src/journal/journal-gatewayd.c              |   14 -
 src/journal/journal-internal.h              |    1 
 src/journal/journal-qrcode.c                |    6 
 src/journal/journal-verify.c                |   94 ++++----
 src/journal/journalctl.c                    |   60 ++++-
 src/journal/journald-kmsg.c                 |    3 
 src/journal/journald-server.c               |   21 -
 src/journal/libsystemd-journal.sym          |    5 
 src/journal/sd-journal.c                    |  264 ++++++++++++++++--------
 src/journal/test-journal-interleaving.c     |  299 ++++++++++++++++++++++++++++
 src/journal/test-journal-verify.c           |    4 
 src/journal/test-journal.c                  |   60 +++++
 src/libudev/libudev-hwdb.c                  |   10 
 src/login/logind-session.c                  |   59 +----
 src/python-systemd/_reader.c                |    1 
 src/shared/list.h                           |    7 
 src/shared/logs-show.c                      |    2 
 src/shared/util.c                           |   52 +++-
 src/shared/util.h                           |    1 
 src/systemd/sd-journal.h                    |    5 
 src/test/test-util.c                        |   39 +++
 32 files changed, 948 insertions(+), 320 deletions(-)

New commits:
commit cbd671772c9ce053a7050ddd29de170eb9efac7e
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Jun 7 22:01:03 2013 -0400

    journal: letting (interleaved) seqnums go
    
    In the following scenario:
      server creates system.journal
      server creates user-1000.journal
    both journals share the same seqnum_id.
    Then
      server writes to user-1000.journal first,
      and server writes to system.journal a bit later,
    and everything is fine.
    The server then terminates (crash, reboot, rsyslog testing,
    whatever), and user-1000.journal has entries which end with
    a lower seqnum than system.journal. Now
      server is restarted
      server opens user-1000.journal and writes entries to it...
    BAM! duplicate seqnums for the same seqnum_id.
    
    Now, we usually don't see that happen, because system.journal
    is closed last, and opened first. Since usually at least one
    message is written during boot and lands in the system.journal,
    the seqnum is initialized from it, and is set to a number higher
    than than anything found in user journals. Nevertheless, if
    system.journal is corrupted and is rotated, it can happen that
    an entry is written to the user journal with a seqnum that is
    a duplicate with an entry found in the corrupted system.journal~.
    When browsing the journal, journalctl can fall into a loop
    where it tries to follow the seqnums, and tries to go the
    next location by seqnum, and is transported back in time to
    to the older duplicate seqnum. There is not way to find
    out the maximum seqnum used in a multiple files, without
    actually looking at all of them. But we don't want to do
    that because it would be slow, and actually it isn't really
    possible, because a file might e.g. be temporarily unaccessible.
    
    Fix the problem by using different seqnum series for user
    journals. Using the same seqnum series for rotated journals
    is still fine, because we know that nothing will write
    to the rotated journal anymore.
    
    Likely related:
    https://bugs.freedesktop.org/show_bug.cgi?id=64566
    https://bugs.freedesktop.org/show_bug.cgi?id=59856
    https://bugs.freedesktop.org/show_bug.cgi?id=64296
    https://bugs.archlinux.org/task/35581
    https://bugzilla.novell.com/show_bug.cgi?id=817778
    
    Possibly related:
    https://bugs.freedesktop.org/show_bug.cgi?id=64293

diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 6c99f4b..a2b5ac7 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -282,7 +282,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
                 journal_file_close(f);
         }
 
-        r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, s->system_journal, &f);
+        r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f);
         if (r < 0)
                 return s->system_journal;
 

commit 5cb24cd32bce87cc618b857c059f1187e03d2b24
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Fri Jun 7 21:54:20 2013 -0400

    tests: add testcase for duplicate seqnums

diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index c83a1ea..069d297 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -4,6 +4,7 @@
   This file is part of systemd.
 
   Copyright 2013 Marius Vollmer
+  Copyright 2013 Zbigniew Jędrzejewski-Szmek
 
   systemd is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
@@ -26,12 +27,15 @@
 
 #include "journal-file.h"
 #include "journal-internal.h"
+#include "journal-vacuum.h"
 #include "util.h"
 #include "log.h"
 
 /* This program tests skipping around in a multi-file journal.
  */
 
+static bool arg_keep = false;
+
 static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) {
         log_meta(LOG_CRIT, file, line, func,
                  "'%s' failed at %s:%u (%s): %s.",
@@ -49,7 +53,7 @@ static void log_assert_errno(const char *text, int eno, const char *file, int li
 static JournalFile *test_open (const char *name)
 {
         JournalFile *f;
-        assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f));
+        assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
         return f;
 }
 
@@ -58,7 +62,7 @@ static void test_close (JournalFile *f)
         journal_file_close (f);
 }
 
-static void test_append_number(JournalFile *f, int n)
+static void append_number(JournalFile *f, int n, uint64_t *seqnum)
 {
         char *p;
         dual_timestamp ts;
@@ -69,7 +73,7 @@ static void test_append_number(JournalFile *f, int n)
         assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
         iovec[0].iov_base = p;
         iovec[0].iov_len = strlen(p);
-        assert_ret(journal_file_append_entry(f, &ts, iovec, 1, NULL, NULL, NULL));
+        assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
         free (p);
 }
 
@@ -120,10 +124,10 @@ static void setup_sequential(void) {
         JournalFile *one, *two;
         one = test_open("one.journal");
         two = test_open("two.journal");
-        test_append_number(one, 1);
-        test_append_number(one, 2);
-        test_append_number(two, 3);
-        test_append_number(two, 4);
+        append_number(one, 1, NULL);
+        append_number(one, 2, NULL);
+        append_number(two, 3, NULL);
+        append_number(two, 4, NULL);
         test_close(one);
         test_close(two);
 }
@@ -132,10 +136,10 @@ static void setup_interleaved(void) {
         JournalFile *one, *two;
         one = test_open("one.journal");
         two = test_open("two.journal");
-        test_append_number(one, 1);
-        test_append_number(two, 2);
-        test_append_number(one, 3);
-        test_append_number(two, 4);
+        append_number(one, 1, NULL);
+        append_number(two, 2, NULL);
+        append_number(one, 3, NULL);
+        append_number(two, 4, NULL);
         test_close(one);
         test_close(two);
 }
@@ -146,8 +150,6 @@ static void test_skip(void (*setup)(void))
         sd_journal *j;
         int r;
 
-        log_set_max_level(LOG_DEBUG);
-
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
@@ -187,12 +189,111 @@ static void test_skip(void (*setup)(void))
         test_check_numbers_up(j, 4);
         sd_journal_close(j);
 
-        assert_ret(rm_rf_dangerous(t, false, true, false));
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL);
+
+                assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+        }
+
+        puts("------------------------------------------------------------");
+}
+
+static void test_sequence_numbers(void) {
+
+        char t[] = "/tmp/journal-seq-XXXXXX";
+        JournalFile *one, *two;
+        uint64_t seqnum = 0;
+        sd_id128_t seqnum_id;
+
+        assert_se(mkdtemp(t));
+        assert_se(chdir(t) >= 0);
+
+        assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
+                                    true, false, NULL, NULL, NULL, &one) == 0);
+
+        append_number(one, 1, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert(seqnum == 1);
+        append_number(one, 2, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert(seqnum == 2);
+
+        assert(one->header->state == STATE_ONLINE);
+        assert(!sd_id128_equal(one->header->file_id, one->header->machine_id));
+        assert(!sd_id128_equal(one->header->file_id, one->header->boot_id));
+        assert(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
+
+        memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
+
+        assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
+                                    true, false, NULL, NULL, one, &two) == 0);
+
+        assert(two->header->state == STATE_ONLINE);
+        assert(!sd_id128_equal(two->header->file_id, one->header->file_id));
+        assert(sd_id128_equal(one->header->machine_id, one->header->machine_id));
+        assert(sd_id128_equal(one->header->boot_id, one->header->boot_id));
+        assert(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
+
+        append_number(two, 3, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert(seqnum == 3);
+        append_number(two, 4, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert(seqnum == 4);
+
+        test_close(two);
+
+        append_number(one, 5, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert(seqnum == 5);
+
+        append_number(one, 6, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert(seqnum == 6);
+
+        test_close(one);
+
+        /* restart server */
+        seqnum = 0;
+
+        assert_se(journal_file_open("two.journal", O_RDWR, 0,
+                                    true, false, NULL, NULL, NULL, &two) == 0);
+
+        assert(sd_id128_equal(two->header->seqnum_id, seqnum_id));
+
+        append_number(two, 7, &seqnum);
+        printf("seqnum=%"PRIu64"\n", seqnum);
+        assert(seqnum == 5);
+
+        /* So..., here we have the same seqnum in two files with the
+         * same seqnum_id. */
+
+        test_close(two);
+
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL);
+
+                assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+        }
 }
 
 int main(int argc, char *argv[]) {
+        log_set_max_level(LOG_DEBUG);
+
+        arg_keep = argc > 1;
+
         test_skip(setup_sequential);
         test_skip(setup_interleaved);
 
+        test_sequence_numbers();
+
         return 0;
 }

commit 7a050b54b7c78717d5efb2e380623ccad2a70148
Author: Marius Vollmer <marius.vollmer at redhat.com>
Date:   Fri Jun 7 00:50:21 2013 -0400

    tests: add testcase for skipping-entries-on-direction-change-bug
    
    This test case failed until a3e6f050de8.
    
    Taken from https://bugs.freedesktop.org/show_bug.cgi?id=65255.

diff --git a/Makefile.am b/Makefile.am
index 70da1e4..28ae7ed 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2781,6 +2781,14 @@ test_journal_verify_LDADD = \
 	libsystemd-journal-internal.la \
 	libsystemd-id128-internal.la
 
+test_journal_interleaving_SOURCES = \
+	src/journal/test-journal-interleaving.c
+
+test_journal_interleaving_LDADD = \
+	libsystemd-shared.la \
+	libsystemd-journal-internal.la \
+	libsystemd-id128-internal.la
+
 test_mmap_cache_SOURCES = \
 	src/journal/test-mmap-cache.c
 
@@ -2956,6 +2964,7 @@ tests += \
 	test-journal-match \
 	test-journal-stream \
 	test-journal-verify \
+	test-journal-interleaving \
 	test-mmap-cache \
 	test-catalog
 
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
new file mode 100644
index 0000000..c83a1ea
--- /dev/null
+++ b/src/journal/test-journal-interleaving.c
@@ -0,0 +1,198 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Marius Vollmer
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <systemd/sd-journal.h>
+
+#include "journal-file.h"
+#include "journal-internal.h"
+#include "util.h"
+#include "log.h"
+
+/* This program tests skipping around in a multi-file journal.
+ */
+
+static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) {
+        log_meta(LOG_CRIT, file, line, func,
+                 "'%s' failed at %s:%u (%s): %s.",
+                 text, file, line, func, strerror(eno));
+        abort();
+}
+
+#define assert_ret(expr)                                                \
+        do {                                                            \
+                int _r_ = (expr);                                       \
+                if (_unlikely_(_r_ < 0))                                \
+                        log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+        } while (false)
+
+static JournalFile *test_open (const char *name)
+{
+        JournalFile *f;
+        assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f));
+        return f;
+}
+
+static void test_close (JournalFile *f)
+{
+        journal_file_close (f);
+}
+
+static void test_append_number(JournalFile *f, int n)
+{
+        char *p;
+        dual_timestamp ts;
+        struct iovec iovec[1];
+
+        dual_timestamp_get(&ts);
+
+        assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
+        iovec[0].iov_base = p;
+        iovec[0].iov_len = strlen(p);
+        assert_ret(journal_file_append_entry(f, &ts, iovec, 1, NULL, NULL, NULL));
+        free (p);
+}
+
+static void test_check_number (sd_journal *j, int n)
+{
+        const void *d;
+        char *k;
+        size_t l;
+        int x;
+
+        assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
+        assert_se(k = strndup(d, l));
+        printf("%s\n", k);
+
+        assert_se(safe_atoi(k + 7, &x) >= 0);
+        assert_se(n == x);
+}
+
+static void test_check_numbers_down (sd_journal *j, int count)
+{
+        for (int i = 1; i <= count; i++) {
+                int r;
+                test_check_number(j, i);
+                assert_ret(r = sd_journal_next(j));
+                if (i == count)
+                        assert_se(r == 0);
+                else
+                        assert_se(r == 1);
+        }
+
+}
+
+static void test_check_numbers_up (sd_journal *j, int count)
+{
+        for (int i = count; i >= 1; i--) {
+                int r;
+                test_check_number(j, i);
+                assert_ret(r = sd_journal_previous(j));
+                if (i == 1)
+                        assert_se(r == 0);
+                else
+                        assert_se(r == 1);
+        }
+
+}
+
+static void setup_sequential(void) {
+        JournalFile *one, *two;
+        one = test_open("one.journal");
+        two = test_open("two.journal");
+        test_append_number(one, 1);
+        test_append_number(one, 2);
+        test_append_number(two, 3);
+        test_append_number(two, 4);
+        test_close(one);
+        test_close(two);
+}
+
+static void setup_interleaved(void) {
+        JournalFile *one, *two;
+        one = test_open("one.journal");
+        two = test_open("two.journal");
+        test_append_number(one, 1);
+        test_append_number(two, 2);
+        test_append_number(one, 3);
+        test_append_number(two, 4);
+        test_close(one);
+        test_close(two);
+}
+
+static void test_skip(void (*setup)(void))
+{
+        char t[] = "/tmp/journal-skip-XXXXXX";
+        sd_journal *j;
+        int r;
+
+        log_set_max_level(LOG_DEBUG);
+
+        assert_se(mkdtemp(t));
+        assert_se(chdir(t) >= 0);
+
+        setup();
+
+        /* Seek to head, iterate down.
+         */
+        assert_ret(sd_journal_open_directory(&j, t, 0));
+        assert_ret(sd_journal_seek_head(j));
+        assert_ret(sd_journal_next(j));
+        test_check_numbers_down(j, 4);
+        sd_journal_close(j);
+
+        /* Seek to tail, iterate up.
+         */
+        assert_ret(sd_journal_open_directory(&j, t, 0));
+        assert_ret(sd_journal_seek_tail(j));
+        assert_ret(sd_journal_previous(j));
+        test_check_numbers_up(j, 4);
+        sd_journal_close(j);
+
+        /* Seek to tail, skip to head, iterate down.
+         */
+        assert_ret(sd_journal_open_directory(&j, t, 0));
+        assert_ret(sd_journal_seek_tail(j));
+        assert_ret(r = sd_journal_previous_skip(j, 4));
+        assert_se(r == 4);
+        test_check_numbers_down(j, 4);
+        sd_journal_close(j);
+
+        /* Seek to head, skip to tail, iterate up.
+         */
+        assert_ret(sd_journal_open_directory(&j, t, 0));
+        assert_ret(sd_journal_seek_head(j));
+        assert_ret(r = sd_journal_next_skip(j, 4));
+        assert_se(r == 4);
+        test_check_numbers_up(j, 4);
+        sd_journal_close(j);
+
+        assert_ret(rm_rf_dangerous(t, false, true, false));
+}
+
+int main(int argc, char *argv[]) {
+        test_skip(setup_sequential);
+        test_skip(setup_interleaved);
+
+        return 0;
+}

commit bc3029268ca0077f2e176724d7d124cec4265575
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jun 6 23:30:46 2013 -0400

    journal: change direction tests to use the same convention (cp </> np)
    
    The order was different in various places, which makes it harder to
    read to code. Also consistently use ternany for all direction checks.
    
    Remove one free(NULL).

diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 4c4cc2d..1e70739 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -163,7 +163,7 @@ static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
                         return true;
         }
 
-        return true;
+        assert_not_reached("\"=\" not found");
 }
 
 static Match *match_new(Match *p, MatchType t) {
@@ -371,10 +371,8 @@ static char *match_make_string(Match *m) {
                         p = k;
 
                         enclose = true;
-                } else {
-                        free(p);
+                } else
                         p = t;
-                }
         }
 
         if (enclose) {
@@ -587,11 +585,14 @@ static int next_for_match(
                         if (r < 0)
                                 return r;
                         else if (r > 0) {
-                                if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp))
+                                if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np))
                                         np = cp;
                         }
                 }
 
+                if (np == 0)
+                        return 0;
+
         } else if (m->type == MATCH_AND_TERM) {
                 Match *i, *last_moved;
 
@@ -624,8 +625,7 @@ static int next_for_match(
                 }
         }
 
-        if (np == 0)
-                return 0;
+        assert(np > 0);
 
         r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n);
         if (r < 0)
@@ -730,7 +730,7 @@ static int find_location_for_match(
                         if (r <= 0)
                                 return r;
 
-                        if (np == 0 || (direction == DIRECTION_DOWN ? np < cp : np > cp))
+                        if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))
                                 np = cp;
                 }
 
@@ -826,7 +826,7 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc
                         return r;
         }
 
-        /* OK, we found the spot, now let's advance until to an entry
+        /* OK, we found the spot, now let's advance until an entry
          * that is actually different from what we were previously
          * looking at. This is necessary to handle entries which exist
          * in two (or more) journal files, and which shall all be
@@ -888,10 +888,7 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
 
                         k = compare_entry_order(f, o, new_file, new_offset);
 
-                        if (direction == DIRECTION_DOWN)
-                                found = k < 0;
-                        else
-                                found = k > 0;
+                        found = direction == DIRECTION_DOWN ? k < 0 : k > 0;
                 }
 
                 if (found) {

commit 87011c25d96e9fbcd8a465ba758fa037c7d08203
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Thu Jun 6 22:28:05 2013 -0400

    journal: remember last direction of search and keep offset cache
    
    The fields in JournalFile are moved around to avoid wasting
    7 bytes because of alignment.

diff --git a/TODO b/TODO
index 0dd19a0..1dc585c 100644
--- a/TODO
+++ b/TODO
@@ -77,9 +77,6 @@ Features:
 
 * investigate endianess issues of UUID vs. GUID
 
-* see if we can fix https://bugs.freedesktop.org/show_bug.cgi?id=63672
-  without dropping the location cache entirely.
-
 * dbus: when a unit failed to load (i.e. is in UNIT_ERROR state), we
   should be able to safely try another attempt when the bus call LoadUnit() is invoked.
 
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 7b1cd42..5cc2c2d 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -42,10 +42,14 @@ typedef struct JournalMetrics {
         uint64_t keep_free;
 } JournalMetrics;
 
+typedef enum direction {
+        DIRECTION_UP,
+        DIRECTION_DOWN
+} direction_t;
+
 typedef struct JournalFile {
         int fd;
-        char *path;
-        struct stat last_stat;
+
         mode_t mode;
 
         int flags;
@@ -56,6 +60,11 @@ typedef struct JournalFile {
 
         bool tail_entry_monotonic_valid;
 
+        direction_t last_direction;
+
+        char *path;
+        struct stat last_stat;
+
         Header *header;
         HashItem *data_hash_table;
         HashItem *field_hash_table;
@@ -90,11 +99,6 @@ typedef struct JournalFile {
 #endif
 } JournalFile;
 
-typedef enum direction {
-        DIRECTION_UP,
-        DIRECTION_DOWN
-} direction_t;
-
 int journal_file_open(
                 const char *fname,
                 int flags,
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 3aa9ed4..4c4cc2d 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -102,7 +102,8 @@ static void init_location(Location *l, LocationType type, JournalFile *f, Object
         l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
 }
 
-static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o, uint64_t offset) {
+static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o,
+                         direction_t direction, uint64_t offset) {
         assert(j);
         assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
         assert(f);
@@ -110,12 +111,10 @@ static void set_location(sd_journal *j, LocationType type, JournalFile *f, Objec
 
         init_location(&j->current_location, type, f, o);
 
-        if (j->current_file)
-                j->current_file->current_offset = 0;
-
         j->current_file = f;
         j->current_field = 0;
 
+        f->last_direction = direction;
         f->current_offset = offset;
 }
 
@@ -811,7 +810,7 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc
         assert(j);
         assert(f);
 
-        if (f->current_offset > 0) {
+        if (f->last_direction == direction && f->current_offset > 0) {
                 cp = f->current_offset;
 
                 r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c);
@@ -908,7 +907,7 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
         if (r < 0)
                 return r;
 
-        set_location(j, LOCATION_DISCRETE, new_file, o, new_offset);
+        set_location(j, LOCATION_DISCRETE, new_file, o, direction, new_offset);
 
         return 1;
 }

commit 8d98da3f1107529d5ba49aea1fa285f7264b7cba
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 19:30:17 2013 -0400

    journalctl: allow the user to specify the file(s) to use
    
    This is useful for debugging and feels pretty natural. For example
    answering the question "is this big .journal file worth keeping?"
    is made easier.

diff --git a/man/journalctl.xml b/man/journalctl.xml
index 6610081..f399868 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -462,15 +462,29 @@
                         </varlistentry>
 
                         <varlistentry>
-                                <term><option>-D</option></term>
-                                <term><option>--directory=</option></term>
-
-                                <listitem><para>Takes a
-                                directory path as argument. If
-                                specified journalctl will operate on the
-                                specified journal directory instead of
-                                the default runtime and system journal
-                                paths.</para></listitem>
+                                <term><option>-D <replaceable>DIR</replaceable></option></term>
+                                <term><option>--directory=<replaceable>DIR</replaceable></option></term>
+
+                                <listitem><para>Takes a directory path
+                                as argument. If specified journalctl
+                                will operate on the specified journal
+                                directory
+                                <replaceable>DIR</replaceable> instead
+                                of the default runtime and system
+                                journal paths.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--file=<replaceable>GLOB</replaceable></option></term>
+
+                                <listitem><para>Takes a file glob as
+                                argument. If specified journalctl will
+                                operate on the specified journal files
+                                matching <replaceable>GLOB</replaceable>
+                                instead of the default runtime and
+                                system journal paths. May be specified
+                                multiple times, in which case files will
+                                be suitably interleaved.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index af0f4ba..1a441dd 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -74,6 +74,7 @@ static bool arg_this_boot = false;
 static bool arg_dmesg = false;
 static const char *arg_cursor = NULL;
 static const char *arg_directory = NULL;
+static char **arg_file = NULL;
 static int arg_priorities = 0xFF;
 static const char *arg_verify_key = NULL;
 #ifdef HAVE_GCRYPT
@@ -130,6 +131,7 @@ static int help(void) {
                "     --no-pager          Do not pipe output into a pager\n"
                "  -m --merge             Show entries from all available journals\n"
                "  -D --directory=PATH    Show journal files from directory\n"
+               "     --file=PATH         Show journal file\n"
                "     --root=ROOT         Operate on catalog files underneath the root ROOT\n"
 #ifdef HAVE_GCRYPT
                "     --interval=TIME     Time interval for changing the FSS sealing key\n"
@@ -167,6 +169,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_HEADER,
                 ARG_FULL,
                 ARG_SETUP_KEYS,
+                ARG_FILE,
                 ARG_INTERVAL,
                 ARG_VERIFY,
                 ARG_VERIFY_KEY,
@@ -198,6 +201,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "system",       no_argument,       NULL, ARG_SYSTEM       },
                 { "user",         no_argument,       NULL, ARG_USER         },
                 { "directory",    required_argument, NULL, 'D'              },
+                { "file",         required_argument, NULL, ARG_FILE         },
                 { "root",         required_argument, NULL, ARG_ROOT         },
                 { "header",       no_argument,       NULL, ARG_HEADER       },
                 { "priority",     required_argument, NULL, 'p'              },
@@ -343,6 +347,14 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_directory = optarg;
                         break;
 
+                case ARG_FILE:
+                        r = glob_extend(&arg_file, optarg);
+                        if (r < 0) {
+                                log_error("Failed to add paths: %s", strerror(-r));
+                                return r;
+                        };
+                        break;
+
                 case ARG_ROOT:
                         arg_root = optarg;
                         break;
@@ -506,6 +518,11 @@ static int parse_argv(int argc, char *argv[]) {
         if (arg_follow && !arg_no_tail && arg_lines < 0)
                 arg_lines = 10;
 
+        if (arg_directory && arg_file) {
+                log_error("Please specify either -D/--directory= or --file=, not both.");
+                return -EINVAL;
+        }
+
         if (arg_since_set && arg_until_set && arg_since > arg_until) {
                 log_error("--since= must be before --until=.");
                 return -EINVAL;
@@ -1110,10 +1127,14 @@ int main(int argc, char *argv[]) {
 
         if (arg_directory)
                 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
+        else if (arg_file)
+                r = sd_journal_open_files(&j, (const char**) arg_file, 0);
         else
                 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
         if (r < 0) {
-                log_error("Failed to open journal: %s", strerror(-r));
+                log_error("Failed to open %s: %s",
+                          arg_directory ? arg_directory : arg_file ? "files" : "journal",
+                          strerror(-r));
                 return EXIT_FAILURE;
         }
 
@@ -1167,10 +1188,7 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 return EXIT_FAILURE;
 
-        /* Opening the fd now means the first sd_journal_wait() will actually wait */
-        r = sd_journal_get_fd(j);
-        if (r < 0)
-                return EXIT_FAILURE;
+        log_debug("Journal filter: %s", j->level0 ? journal_make_match_string(j) : "none");
 
         if (arg_field) {
                 const void *data;
@@ -1206,6 +1224,13 @@ int main(int argc, char *argv[]) {
                 return EXIT_SUCCESS;
         }
 
+        /* Opening the fd now means the first sd_journal_wait() will actually wait */
+        if (arg_follow) {
+                r = sd_journal_get_fd(j);
+                if (r < 0)
+                        return EXIT_FAILURE;
+        }
+
         if (arg_cursor) {
                 r = sd_journal_seek_cursor(j, arg_cursor);
                 if (r < 0) {
diff --git a/src/shared/util.c b/src/shared/util.c
index 17928ec..04811ff 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -4353,7 +4353,7 @@ int in_group(const char *name) {
 
 int glob_exists(const char *path) {
         _cleanup_globfree_ glob_t g = {};
-        int r, k;
+        int k;
 
         assert(path);
 
@@ -4361,15 +4361,37 @@ int glob_exists(const char *path) {
         k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
 
         if (k == GLOB_NOMATCH)
-                r = 0;
+                return 0;
         else if (k == GLOB_NOSPACE)
-                r = -ENOMEM;
+                return -ENOMEM;
         else if (k == 0)
-                r = !strv_isempty(g.gl_pathv);
+                return !strv_isempty(g.gl_pathv);
         else
-                r = errno ? -errno : -EIO;
+                return errno ? -errno : -EIO;
+}
 
-        return r;
+int glob_extend(char ***strv, const char *path) {
+        _cleanup_globfree_ glob_t g = {};
+        int k;
+        char **p;
+
+        errno = 0;
+        k = glob(optarg, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+
+        if (k == GLOB_NOMATCH)
+                return -ENOENT;
+        else if (k == GLOB_NOSPACE)
+                return -ENOMEM;
+        else if (k != 0 || strv_isempty(g.gl_pathv))
+                return errno ? -errno : -EIO;
+
+        STRV_FOREACH(p, g.gl_pathv) {
+                k = strv_extend(strv, *p);
+                if (k < 0)
+                        break;
+        }
+
+        return k;
 }
 
 int dirent_ensure_type(DIR *d, struct dirent *de) {
diff --git a/src/shared/util.h b/src/shared/util.h
index e6f9312..ddb21b4 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -439,6 +439,7 @@ char* uid_to_name(uid_t uid);
 char* gid_to_name(gid_t gid);
 
 int glob_exists(const char *path);
+int glob_extend(char ***strv, const char *path);
 
 int dirent_ensure_type(DIR *d, struct dirent *de);
 

commit 5302ebe15ff3a11eceb75e095e5a09d2a676de2b
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 19:39:26 2013 -0400

    journal: add sd_journal_open_files
    
    This allows the caller to explicitly specify which journal files
    should be opened. The same functionality could be achieved before
    by creating a directory and playing around with symlinks. It
    is useful to debug stuff and explore the journal, and has been
    requested before.
    
    Waiting is supported, the journal will notice modifications on
    the files supplied when opening the journal, but will not add
    any new files.

diff --git a/Makefile-man.am b/Makefile-man.am
index a31427e..807ad78 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -148,6 +148,7 @@ MANPAGES_ALIAS += \
 	man/sd_journal_get_timeout.3 \
 	man/sd_journal_next_skip.3 \
 	man/sd_journal_open_directory.3 \
+	man/sd_journal_open_files.3 \
 	man/sd_journal_perror.3 \
 	man/sd_journal_previous.3 \
 	man/sd_journal_previous_skip.3 \
@@ -248,6 +249,7 @@ man/sd_journal_get_monotonic_usec.3: man/sd_journal_get_realtime_usec.3
 man/sd_journal_get_timeout.3: man/sd_journal_get_fd.3
 man/sd_journal_next_skip.3: man/sd_journal_next.3
 man/sd_journal_open_directory.3: man/sd_journal_open.3
+man/sd_journal_open_files.3: man/sd_journal_open.3
 man/sd_journal_perror.3: man/sd_journal_print.3
 man/sd_journal_previous.3: man/sd_journal_next.3
 man/sd_journal_previous_skip.3: man/sd_journal_next.3
@@ -452,6 +454,9 @@ man/sd_journal_next_skip.html: man/sd_journal_next.html
 man/sd_journal_open_directory.html: man/sd_journal_open.html
 	$(html-alias)
 
+man/sd_journal_open_files.html: man/sd_journal_open.html
+	$(html-alias)
+
 man/sd_journal_perror.html: man/sd_journal_print.html
 	$(html-alias)
 
diff --git a/man/sd_journal_open.xml b/man/sd_journal_open.xml
index dd2f32d..4ac94c4 100644
--- a/man/sd_journal_open.xml
+++ b/man/sd_journal_open.xml
@@ -45,6 +45,7 @@
         <refnamediv>
                 <refname>sd_journal_open</refname>
                 <refname>sd_journal_open_directory</refname>
+                <refname>sd_journal_open_files</refname>
                 <refname>sd_journal_close</refname>
                 <refname>sd_journal</refname>
                 <refname>SD_JOURNAL_LOCAL_ONLY</refname>
@@ -72,6 +73,13 @@
                         </funcprototype>
 
                         <funcprototype>
+                                <funcdef>int <function>sd_journal_open_files</function></funcdef>
+                                <paramdef>sd_journal** <parameter>ret</parameter></paramdef>
+                                <paramdef>const char** <parameter>paths</parameter></paramdef>
+                                <paramdef>int <parameter>flags</parameter></paramdef>
+                        </funcprototype>
+
+                        <funcprototype>
                                 <funcdef>void <function>sd_journal_close</function></funcdef>
                                 <paramdef>sd_journal* <parameter>j</parameter></paramdef>
                         </funcprototype>
@@ -111,6 +119,14 @@
                 flags argument, but it must be passed as 0 as no flags
                 are currently understood for this call.</para>
 
+                <para><function>sd_journal_open_files()</function>
+                is similar to <function>sd_journal_open()</function>
+                but takes a <literal>NULL</literal>-terminated list
+                of file paths to open. All files will be opened and
+                interleaved automatically. This call also takes a
+                flags argument, but it must be passed as 0 as no flags
+                are currently understood for this call.</para>
+
                 <para><function>sd_journal_close()</function> will
                 close the journal context allocated with
                 <function>sd_journal_open()</function> or
@@ -188,9 +204,10 @@
                 <para><function>sd_journal_open_directory()</function>
                 was added in systemd-187.</para>
 
-                <para><literal>SD_JOURNAL_SYSTEM</literal> and
-                <literal>SD_JOURNAL_CURRENT_USER</literal> were added
-                in systemd-205.
+                <para><literal>SD_JOURNAL_SYSTEM</literal>,
+                <literal>SD_JOURNAL_CURRENT_USER</literal>,
+                and <function>sd_journal_open_files()</function>
+                were added in systemd-205.
                 <literal>SD_JOURNAL_SYSTEM_ONLY</literal>
                 was deprecated.</para>
         </refsect1>
diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h
index f576a00..5b717f8 100644
--- a/src/journal/journal-internal.h
+++ b/src/journal/journal-internal.h
@@ -123,6 +123,7 @@ struct sd_journal {
         uint64_t unique_offset;
 
         bool on_network;
+        bool no_new_files;
 
         size_t data_threshold;
 
diff --git a/src/journal/libsystemd-journal.sym b/src/journal/libsystemd-journal.sym
index 449f37c..4eb1591 100644
--- a/src/journal/libsystemd-journal.sym
+++ b/src/journal/libsystemd-journal.sym
@@ -104,3 +104,8 @@ LIBSYSTEMD_JOURNAL_202 {
 global:
         sd_journal_add_conjunction;
 } LIBSYSTEMD_JOURNAL_201;
+
+LIBSYSTEMD_JOURNAL_205 {
+global:
+        sd_journal_open_files;
+} LIBSYSTEMD_JOURNAL_202;
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 8986763..3aa9ed4 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -33,6 +33,7 @@
 #include "journal-file.h"
 #include "hashmap.h"
 #include "list.h"
+#include "strv.h"
 #include "path-util.h"
 #include "lookup3.h"
 #include "compress.h"
@@ -1278,37 +1279,24 @@ static bool file_type_wanted(int flags, const char *filename) {
         return false;
 }
 
-static int add_file(sd_journal *j, const char *prefix, const char *filename) {
-        _cleanup_free_ char *path = NULL;
-        int r;
+static int add_any_file(sd_journal *j, const char *path) {
         JournalFile *f;
+        int r;
 
         assert(j);
-        assert(prefix);
-        assert(filename);
-
-        if (!file_type_wanted(j->flags, filename))
-                return 0;
-
-        path = strjoin(prefix, "/", filename, NULL);
-        if (!path)
-                return -ENOMEM;
+        assert(path);
 
         if (hashmap_get(j->files, path))
                 return 0;
 
         if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
-                log_debug("Too many open journal files, not adding %s, ignoring.", path);
+                log_warning("Too many open journal files, not adding %s.", path);
                 return set_put_error(j, -ETOOMANYREFS);
         }
 
         r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
-        if (r < 0) {
-                if (errno == ENOENT)
-                        return 0;
-
+        if (r < 0)
                 return r;
-        }
 
         /* journal_file_dump(f); */
 
@@ -1327,6 +1315,28 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
         return 0;
 }
 
+static int add_file(sd_journal *j, const char *prefix, const char *filename) {
+        _cleanup_free_ char *path = NULL;
+        int r;
+
+        assert(j);
+        assert(prefix);
+        assert(filename);
+
+        if (j->no_new_files ||
+            !file_type_wanted(j->flags, filename))
+                return 0;
+
+        path = strjoin(prefix, "/", filename, NULL);
+        if (!path)
+                return -ENOMEM;
+
+        r = add_any_file(j, path);
+        if (r == -ENOENT)
+                return 0;
+        return 0;
+}
+
 static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
         char *path;
         JournalFile *f;
@@ -1507,6 +1517,9 @@ static int add_root_directory(sd_journal *j, const char *p) {
                         inotify_rm_watch(j->inotify_fd, m->wd);
         }
 
+        if (j->no_new_files)
+                return 0;
+
         for (;;) {
                 struct dirent *de;
                 union dirent_storage buf;
@@ -1587,6 +1600,36 @@ static int add_search_paths(sd_journal *j) {
         return 0;
 }
 
+static int add_current_paths(sd_journal *j) {
+        Iterator i;
+        JournalFile *f;
+
+        assert(j);
+        assert(j->no_new_files);
+
+        /* Simply adds all directories for files we have open as
+         * "root" directories. We don't expect errors here, so we
+         * treat them as fatal. */
+
+        HASHMAP_FOREACH(f, j->files, i) {
+                int r;
+                _cleanup_free_ char *dir;
+
+                dir = dirname_malloc(f->path);
+                if (!dir)
+                        return -ENOMEM;
+
+                r = add_root_directory(j, dir);
+                if (r < 0) {
+                        set_put_error(j, r);
+                        return r;
+                }
+        }
+
+        return 0;
+}
+
+
 static int allocate_inotify(sd_journal *j) {
         assert(j);
 
@@ -1697,6 +1740,40 @@ fail:
         return r;
 }
 
+_public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
+        sd_journal *j;
+        const char **path;
+        int r;
+
+        if (!ret)
+                return -EINVAL;
+
+        if (flags != 0)
+                return -EINVAL;
+
+        j = journal_new(flags, NULL);
+        if (!j)
+                return -ENOMEM;
+
+        STRV_FOREACH(path, paths) {
+                r = add_any_file(j, *path);
+                if (r < 0) {
+                        log_error("Failed to open %s: %s", *path, strerror(-r));
+                        goto fail;
+                }
+        }
+
+        j->no_new_files = true;
+
+        *ret = j;
+        return 0;
+
+fail:
+        sd_journal_close(j);
+
+        return r;
+}
+
 _public_ void sd_journal_close(sd_journal *j) {
         Directory *d;
         JournalFile *f;
@@ -2017,7 +2094,9 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
 
         /* Iterate through all dirs again, to add them to the
          * inotify */
-        if (j->path)
+        if (j->no_new_files)
+                r = add_current_paths(j);
+        else if (j->path)
                 r = add_root_directory(j, j->path);
         else
                 r = add_search_paths(j);
diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h
index cf105cd..72ea328 100644
--- a/src/systemd/sd-journal.h
+++ b/src/systemd/sd-journal.h
@@ -100,6 +100,7 @@ enum {
 
 int sd_journal_open(sd_journal **ret, int flags);
 int sd_journal_open_directory(sd_journal **ret, const char *path, int flags);
+int sd_journal_open_files(sd_journal **ret, const char **paths, int flags);
 void sd_journal_close(sd_journal *j);
 
 int sd_journal_previous(sd_journal *j);

commit 6eb7a9a0010d035e5bdbbf70227088ce02b2120e
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 19:17:56 2013 -0400

    tests: add test for empty journal files
    
    The headers are currently not printed properly: some "(null)"s appear.

diff --git a/TODO b/TODO
index fc8044b..0dd19a0 100644
--- a/TODO
+++ b/TODO
@@ -11,6 +11,8 @@ Bugfixes:
 
 * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point.
 
+* fix --header to files without entries (see test-journal output).
+
 Fedora 19:
 
 * external: maybe it is time to patch procps so that "ps" links to
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index f4dc52c..534fd28 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -29,7 +29,9 @@
 #include "journal-authenticate.h"
 #include "journal-vacuum.h"
 
-int main(int argc, char *argv[]) {
+static bool arg_keep = false;
+
+static void test_non_empty(void) {
         dual_timestamp ts;
         JournalFile *f;
         struct iovec iovec;
@@ -119,11 +121,61 @@ int main(int argc, char *argv[]) {
 
         journal_file_close(f);
 
-        journal_directory_vacuum(".", 3000000, 0, 0, NULL);
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL);
+
+                assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+        }
+
+        puts("------------------------------------------------------------");
+}
+
+static void test_empty(void) {
+        JournalFile *f1, *f2, *f3, *f4;
+        char t[] = "/tmp/journal-XXXXXX";
+
+        log_set_max_level(LOG_DEBUG);
 
-        log_error("Exiting...");
+        assert_se(mkdtemp(t));
+        assert_se(chdir(t) >= 0);
+
+        assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, &f1) == 0);
+
+        assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f2) == 0);
+
+        assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, &f3) == 0);
+
+        assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f4) == 0);
+
+        journal_file_print_header(f1);
+        puts("");
+        journal_file_print_header(f2);
+        puts("");
+        journal_file_print_header(f3);
+        puts("");
+        journal_file_print_header(f4);
+        puts("");
+
+        log_info("Done...");
+
+        if (arg_keep)
+                log_info("Not removing %s", t);
+        else {
+                journal_directory_vacuum(".", 3000000, 0, 0, NULL);
+
+                assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+        }
+}
+
+int main(int argc, char *argv[]) {
+        arg_keep = argc > 1;
 
-        assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+        test_non_empty();
+        test_empty();
 
         return 0;
 }

commit ed375bebf46c1251f4baa170b39ee93761dbdb19
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 19:15:43 2013 -0400

    journalctl: print monotonic timestamp in --header

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 7f85574..ca217f9 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -2272,7 +2272,7 @@ fail:
 
 void journal_file_print_header(JournalFile *f) {
         char a[33], b[33], c[33], d[33];
-        char x[FORMAT_TIMESTAMP_MAX], y[FORMAT_TIMESTAMP_MAX];
+        char x[FORMAT_TIMESTAMP_MAX], y[FORMAT_TIMESTAMP_MAX], z[FORMAT_TIMESTAMP_MAX];
         struct stat st;
         char bytes[FORMAT_BYTES_MAX];
 
@@ -2295,6 +2295,7 @@ void journal_file_print_header(JournalFile *f) {
                "Tail Sequential Number: %"PRIu64"\n"
                "Head Realtime Timestamp: %s\n"
                "Tail Realtime Timestamp: %s\n"
+               "Tail Monotonic Timestamp: %s\n"
                "Objects: %"PRIu64"\n"
                "Entry Objects: %"PRIu64"\n",
                f->path,
@@ -2318,6 +2319,7 @@ void journal_file_print_header(JournalFile *f) {
                le64toh(f->header->tail_entry_seqnum),
                format_timestamp(x, sizeof(x), le64toh(f->header->head_entry_realtime)),
                format_timestamp(y, sizeof(y), le64toh(f->header->tail_entry_realtime)),
+               format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC),
                le64toh(f->header->n_objects),
                le64toh(f->header->n_entries));
 
@@ -2596,7 +2598,7 @@ int journal_file_open_reliably(
 
         int r;
         size_t l;
-        char *p;
+        _cleanup_free_ char *p = NULL;
 
         r = journal_file_open(fname, flags, mode, compress, seal,
                               metrics, mmap_cache, template, ret);
@@ -2627,7 +2629,6 @@ int journal_file_open_reliably(
                 return -ENOMEM;
 
         r = rename(fname, p);
-        free(p);
         if (r < 0)
                 return -errno;
 
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 0bf557c..6c99f4b 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -245,7 +245,7 @@ finish:
 }
 
 static JournalFile* find_journal(Server *s, uid_t uid) {
-        char *p;
+        _cleanup_free_ char *p = NULL;
         int r;
         JournalFile *f;
         sd_id128_t machine;
@@ -283,8 +283,6 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
         }
 
         r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, s->system_journal, &f);
-        free(p);
-
         if (r < 0)
                 return s->system_journal;
 
@@ -372,7 +370,6 @@ void server_sync(Server *s) {
 }
 
 void server_vacuum(Server *s) {
-        char *p;
         char ids[33];
         sd_id128_t machine;
         int r;
@@ -390,29 +387,19 @@ void server_vacuum(Server *s) {
         sd_id128_to_string(machine, ids);
 
         if (s->system_journal) {
-                p = strappend("/var/log/journal/", ids);
-                if (!p) {
-                        log_oom();
-                        return;
-                }
+                char *p = strappenda("/var/log/journal/", ids);
 
                 r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec);
                 if (r < 0 && r != -ENOENT)
                         log_error("Failed to vacuum %s: %s", p, strerror(-r));
-                free(p);
         }
 
         if (s->runtime_journal) {
-                p = strappend("/run/log/journal/", ids);
-                if (!p) {
-                        log_oom();
-                        return;
-                }
+                char *p = strappenda("/run/log/journal/", ids);
 
                 r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec);
                 if (r < 0 && r != -ENOENT)
                         log_error("Failed to vacuum %s: %s", p, strerror(-r));
-                free(p);
         }
 
         s->cached_available_space_timestamp = 0;

commit 2765b7bb6924e2c26c7bf60bd692a4bc121d9582
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 18:40:44 2013 -0400

    journalctl: print proper IDs with --header
    
    The same buffer was used for two different IDs, messing up
    the output.

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 3cb8f79..7f85574 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -2271,7 +2271,7 @@ fail:
 }
 
 void journal_file_print_header(JournalFile *f) {
-        char a[33], b[33], c[33];
+        char a[33], b[33], c[33], d[33];
         char x[FORMAT_TIMESTAMP_MAX], y[FORMAT_TIMESTAMP_MAX];
         struct stat st;
         char bytes[FORMAT_BYTES_MAX];
@@ -2301,7 +2301,7 @@ void journal_file_print_header(JournalFile *f) {
                sd_id128_to_string(f->header->file_id, a),
                sd_id128_to_string(f->header->machine_id, b),
                sd_id128_to_string(f->header->boot_id, c),
-               sd_id128_to_string(f->header->seqnum_id, c),
+               sd_id128_to_string(f->header->seqnum_id, d),
                f->header->state == STATE_OFFLINE ? "OFFLINE" :
                f->header->state == STATE_ONLINE ? "ONLINE" :
                f->header->state == STATE_ARCHIVED ? "ARCHIVED" : "UNKNOWN",

commit 507f22bd0172bff5e5d98145b1419bd472a2c57f
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 18:44:16 2013 -0400

    Use stdint.h macros instead of casts to print uint64_t values
    
    Casts are visually heavy, and can obscure unwanted truncations.

diff --git a/src/core/execute.c b/src/core/execute.c
index 3959ef9..9148d06 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1837,7 +1837,7 @@ static void strv_fprintf(FILE *f, char **l) {
 }
 
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
-        char ** e;
+        char **e;
         unsigned i;
 
         assert(c);
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index 64bf968..bd7100a 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -60,9 +60,9 @@ int journal_file_append_tag(JournalFile *f) {
         o->tag.seqnum = htole64(journal_file_tag_seqnum(f));
         o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state));
 
-        log_debug("Writing tag %llu for epoch %llu\n",
-                  (unsigned long long) le64toh(o->tag.seqnum),
-                  (unsigned long long) FSPRG_GetEpoch(f->fsprg_state));
+        log_debug("Writing tag %"PRIu64" for epoch %"PRIu64"\n",
+                  le64toh(o->tag.seqnum),
+                  FSPRG_GetEpoch(f->fsprg_state));
 
         /* Add the tag object itself, so that we can protect its
          * header. This will exclude the actual hash value in it */
@@ -152,7 +152,7 @@ int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) {
 
         epoch = FSPRG_GetEpoch(f->fsprg_state);
         if (epoch < goal)
-                log_debug("Evolving FSPRG key from epoch %llu to %llu.", (unsigned long long) epoch, (unsigned long long) goal);
+                log_debug("Evolving FSPRG key from epoch %"PRIu64" to %"PRIu64".", epoch, goal);
 
         for (;;) {
                 if (epoch > goal)
@@ -195,7 +195,7 @@ int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
                         return -ENOMEM;
         }
 
-        log_debug("Seeking FSPRG key to %llu.", (unsigned long long) goal);
+        log_debug("Seeking FSPRG key to %"PRIu64".", goal);
 
         msk = alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR));
         FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR);
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 38499a6..3cb8f79 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -549,7 +549,7 @@ static int journal_file_setup_data_hash_table(JournalFile *f) {
         if (s < DEFAULT_DATA_HASH_TABLE_SIZE)
                 s = DEFAULT_DATA_HASH_TABLE_SIZE;
 
-        log_debug("Reserving %llu entries in hash table.", (unsigned long long) (s / sizeof(HashItem)));
+        log_debug("Reserving %"PRIu64" entries in hash table.", s / sizeof(HashItem));
 
         r = journal_file_append_object(f,
                                        OBJECT_DATA_HASH_TABLE,
@@ -985,7 +985,7 @@ static int journal_file_append_data(
                         o->object.size = htole64(offsetof(Object, data.payload) + rsize);
                         o->object.flags |= OBJECT_COMPRESSED;
 
-                        log_debug("Compressed data object %lu -> %lu", (unsigned long) size, (unsigned long) rsize);
+                        log_debug("Compressed data object %"PRIu64" -> %"PRIu64, size, rsize);
                 }
         }
 #endif
@@ -1206,7 +1206,7 @@ static int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) {
         if (r < 0)
                 return r;
 
-        /* log_debug("=> %s seqnr=%lu n_entries=%lu", f->path, (unsigned long) o->entry.seqnum, (unsigned long) f->header->n_entries); */
+        /* log_debug("=> %s seqnr=%"PRIu64" n_entries=%"PRIu64, f->path, o->entry.seqnum, f->header->n_entries); */
 
         if (f->header->head_entry_realtime == 0)
                 f->header->head_entry_realtime = o->entry.realtime;
@@ -2227,10 +2227,10 @@ void journal_file_dump(JournalFile *f) {
                         break;
 
                 case OBJECT_ENTRY:
-                        printf("Type: OBJECT_ENTRY seqnum=%llu monotonic=%llu realtime=%llu\n",
-                               (unsigned long long) le64toh(o->entry.seqnum),
-                               (unsigned long long) le64toh(o->entry.monotonic),
-                               (unsigned long long) le64toh(o->entry.realtime));
+                        printf("Type: OBJECT_ENTRY seqnum=%"PRIu64" monotonic=%"PRIu64" realtime=%"PRIu64"\n",
+                               le64toh(o->entry.seqnum),
+                               le64toh(o->entry.monotonic),
+                               le64toh(o->entry.realtime));
                         break;
 
                 case OBJECT_FIELD_HASH_TABLE:
@@ -2246,9 +2246,9 @@ void journal_file_dump(JournalFile *f) {
                         break;
 
                 case OBJECT_TAG:
-                        printf("Type: OBJECT_TAG seqnum=%llu epoch=%llu\n",
-                               (unsigned long long) le64toh(o->tag.seqnum),
-                               (unsigned long long) le64toh(o->tag.epoch));
+                        printf("Type: OBJECT_TAG seqnum=%"PRIu64" epoch=%"PRIu64"\n",
+                               le64toh(o->tag.seqnum),
+                               le64toh(o->tag.epoch));
                         break;
 
                 default:
@@ -2286,17 +2286,17 @@ void journal_file_print_header(JournalFile *f) {
                "State: %s\n"
                "Compatible Flags:%s%s\n"
                "Incompatible Flags:%s%s\n"
-               "Header size: %llu\n"
-               "Arena size: %llu\n"
-               "Data Hash Table Size: %llu\n"
-               "Field Hash Table Size: %llu\n"
+               "Header size: %"PRIu64"\n"
+               "Arena size: %"PRIu64"\n"
+               "Data Hash Table Size: %"PRIu64"\n"
+               "Field Hash Table Size: %"PRIu64"\n"
                "Rotate Suggested: %s\n"
-               "Head Sequential Number: %llu\n"
-               "Tail Sequential Number: %llu\n"
+               "Head Sequential Number: %"PRIu64"\n"
+               "Tail Sequential Number: %"PRIu64"\n"
                "Head Realtime Timestamp: %s\n"
                "Tail Realtime Timestamp: %s\n"
-               "Objects: %llu\n"
-               "Entry Objects: %llu\n",
+               "Objects: %"PRIu64"\n"
+               "Entry Objects: %"PRIu64"\n",
                f->path,
                sd_id128_to_string(f->header->file_id, a),
                sd_id128_to_string(f->header->machine_id, b),
@@ -2309,36 +2309,36 @@ void journal_file_print_header(JournalFile *f) {
                (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) ? " ???" : "",
                JOURNAL_HEADER_COMPRESSED(f->header) ? " COMPRESSED" : "",
                (le32toh(f->header->incompatible_flags) & ~HEADER_INCOMPATIBLE_COMPRESSED) ? " ???" : "",
-               (unsigned long long) le64toh(f->header->header_size),
-               (unsigned long long) le64toh(f->header->arena_size),
-               (unsigned long long) le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
-               (unsigned long long) le64toh(f->header->field_hash_table_size) / sizeof(HashItem),
+               le64toh(f->header->header_size),
+               le64toh(f->header->arena_size),
+               le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
+               le64toh(f->header->field_hash_table_size) / sizeof(HashItem),
                yes_no(journal_file_rotate_suggested(f, 0)),
-               (unsigned long long) le64toh(f->header->head_entry_seqnum),
-               (unsigned long long) le64toh(f->header->tail_entry_seqnum),
+               le64toh(f->header->head_entry_seqnum),
+               le64toh(f->header->tail_entry_seqnum),
                format_timestamp(x, sizeof(x), le64toh(f->header->head_entry_realtime)),
                format_timestamp(y, sizeof(y), le64toh(f->header->tail_entry_realtime)),
-               (unsigned long long) le64toh(f->header->n_objects),
-               (unsigned long long) le64toh(f->header->n_entries));
+               le64toh(f->header->n_objects),
+               le64toh(f->header->n_entries));
 
         if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
-                printf("Data Objects: %llu\n"
+                printf("Data Objects: %"PRIu64"\n"
                        "Data Hash Table Fill: %.1f%%\n",
-                       (unsigned long long) le64toh(f->header->n_data),
+                       le64toh(f->header->n_data),
                        100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))));
 
         if (JOURNAL_HEADER_CONTAINS(f->header, n_fields))
-                printf("Field Objects: %llu\n"
+                printf("Field Objects: %"PRIu64"\n"
                        "Field Hash Table Fill: %.1f%%\n",
-                       (unsigned long long) le64toh(f->header->n_fields),
+                       le64toh(f->header->n_fields),
                        100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))));
 
         if (JOURNAL_HEADER_CONTAINS(f->header, n_tags))
-                printf("Tag Objects: %llu\n",
-                       (unsigned long long) le64toh(f->header->n_tags));
+                printf("Tag Objects: %"PRIu64"\n",
+                       le64toh(f->header->n_tags));
         if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
-                printf("Entry Array Objects: %llu\n",
-                       (unsigned long long) le64toh(f->header->n_entry_arrays));
+                printf("Entry Array Objects: %"PRIu64"\n",
+                       le64toh(f->header->n_entry_arrays));
 
         if (fstat(f->fd, &st) >= 0)
                 printf("Disk usage: %s\n", format_bytes(bytes, sizeof(bytes), (off_t) st.st_blocks * 512ULL));
@@ -2564,9 +2564,9 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
         p[l-8] = '@';
         sd_id128_to_string(old_file->header->seqnum_id, p + l - 8 + 1);
         snprintf(p + l - 8 + 1 + 32, 1 + 16 + 1 + 16 + 8 + 1,
-                 "-%016llx-%016llx.journal",
-                 (unsigned long long) le64toh((*f)->header->head_entry_seqnum),
-                 (unsigned long long) le64toh((*f)->header->head_entry_realtime));
+                 "-%016"PRIx64"-%016"PRIx64".journal",
+                 le64toh((*f)->header->head_entry_seqnum),
+                 le64toh((*f)->header->head_entry_realtime));
 
         r = rename(old_file->path, p);
         free(p);
@@ -2873,23 +2873,23 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec) {
 
         if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
                 if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL) {
-                        log_debug("Data hash table of %s has a fill level at %.1f (%llu of %llu items, %llu file size, %llu bytes per hash table item), suggesting rotation.",
+                        log_debug("Data hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items, %llu file size, %"PRIu64" bytes per hash table item), suggesting rotation.",
                                   f->path,
                                   100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))),
-                                  (unsigned long long) le64toh(f->header->n_data),
-                                  (unsigned long long) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)),
-                                  (unsigned long long) (f->last_stat.st_size),
-                                  (unsigned long long) (f->last_stat.st_size / le64toh(f->header->n_data)));
+                                  le64toh(f->header->n_data),
+                                  le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
+                                  (unsigned long long) f->last_stat.st_size,
+                                  f->last_stat.st_size / le64toh(f->header->n_data));
                         return true;
                 }
 
         if (JOURNAL_HEADER_CONTAINS(f->header, n_fields))
                 if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL) {
-                        log_debug("Field hash table of %s has a fill level at %.1f (%llu of %llu items), suggesting rotation.",
+                        log_debug("Field hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items), suggesting rotation.",
                                   f->path,
                                   100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))),
-                                  (unsigned long long) le64toh(f->header->n_fields),
-                                  (unsigned long long) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)));
+                                  le64toh(f->header->n_fields),
+                                  le64toh(f->header->field_hash_table_size) / sizeof(HashItem));
                         return true;
                 }
 
diff --git a/src/journal/journal-gatewayd.c b/src/journal/journal-gatewayd.c
index 86338c6..10224a1 100644
--- a/src/journal/journal-gatewayd.c
+++ b/src/journal/journal-gatewayd.c
@@ -834,17 +834,17 @@ static int request_handler_machine(
                      "\"hostname\" : \"%s\","
                      "\"os_pretty_name\" : \"%s\","
                      "\"virtualization\" : \"%s\","
-                     "\"usage\" : \"%llu\","
-                     "\"cutoff_from_realtime\" : \"%llu\","
-                     "\"cutoff_to_realtime\" : \"%llu\" }\n",
+                     "\"usage\" : \"%"PRIu64"\","
+                     "\"cutoff_from_realtime\" : \"%"PRIu64"\","
+                     "\"cutoff_to_realtime\" : \"%"PRIu64"\" }\n",
                      SD_ID128_FORMAT_VAL(mid),
                      SD_ID128_FORMAT_VAL(bid),
                      hostname_cleanup(hostname, false),
                      os_name ? os_name : "Linux",
                      v ? v : "bare",
-                     (unsigned long long) usage,
-                     (unsigned long long) cutoff_from,
-                     (unsigned long long) cutoff_to);
+                     usage,
+                     cutoff_from,
+                     cutoff_to);
 
         if (r < 0)
                 return respond_oom(connection);
diff --git a/src/journal/journal-qrcode.c b/src/journal/journal-qrcode.c
index 10a14e4..1db66e8 100644
--- a/src/journal/journal-qrcode.c
+++ b/src/journal/journal-qrcode.c
@@ -76,9 +76,9 @@ int print_qr_code(
                 fprintf(f, "%02x", ((uint8_t*) seed)[i]);
         }
 
-        fprintf(f, "/%llx-%llx?machine=" SD_ID128_FORMAT_STR,
-                (unsigned long long) start,
-                (unsigned long long) interval,
+        fprintf(f, "/%"PRIx64"-%"PRIx64"?machine=" SD_ID128_FORMAT_STR,
+                start,
+                interval,
                 SD_ID128_FORMAT_VAL(machine));
 
         if (hn)
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index ed28b45..01c89bc 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -203,7 +203,7 @@ static void draw_progress(uint64_t p, usec_t *last_usec) {
         for (i = 0; i < k; i++)
                 fputs("\xe2\x96\x91", stdout);
 
-        printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
+        printf(" %3"PRIu64"%%", 100U * p / 65535U);
 
         fputs("\r\x1B[?25h", stdout);
         fflush(stdout);
@@ -288,7 +288,7 @@ static int entry_points_to_data(
         assert(entry_fd >= 0);
 
         if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
-                log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
+                log_error("Data object references invalid entry at %"PRIu64, data_p);
                 return -EBADMSG;
         }
 
@@ -304,7 +304,7 @@ static int entry_points_to_data(
                 }
 
         if (!found) {
-                log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
+                log_error("Data object not referenced by linked entry at %"PRIu64, data_p);
                 return -EBADMSG;
         }
 
@@ -347,7 +347,7 @@ static int entry_points_to_data(
                                         x = z;
                         }
 
-                        log_error("Entry object doesn't exist in main entry array at %llu", (unsigned long long) entry_p);
+                        log_error("Entry object doesn't exist in main entry array at %"PRIu64, entry_p);
                         return -EBADMSG;
                 }
 
@@ -388,12 +388,12 @@ static int verify_data(
                 uint64_t next, m, j;
 
                 if (a == 0) {
-                        log_error("Array chain too short at %llu", (unsigned long long) p);
+                        log_error("Array chain too short at %"PRIu64, p);
                         return -EBADMSG;
                 }
 
                 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
-                        log_error("Invalid array at %llu", (unsigned long long) p);
+                        log_error("Invalid array at %"PRIu64, p);
                         return -EBADMSG;
                 }
 
@@ -403,7 +403,7 @@ static int verify_data(
 
                 next = le64toh(o->entry_array.next_entry_array_offset);
                 if (next != 0 && next <= a) {
-                        log_error("Array chain has cycle at %llu", (unsigned long long) p);
+                        log_error("Array chain has cycle at %"PRIu64, p);
                         return -EBADMSG;
                 }
 
@@ -412,7 +412,7 @@ static int verify_data(
 
                         q = le64toh(o->entry_array.items[j]);
                         if (q <= last) {
-                                log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
+                                log_error("Data object's entry array not sorted at %"PRIu64, p);
                                 return -EBADMSG;
                         }
                         last = q;
@@ -463,8 +463,8 @@ static int verify_hash_table(
                         uint64_t next;
 
                         if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
-                                log_error("Invalid data object at hash entry %llu of %llu",
-                                          (unsigned long long) i, (unsigned long long) n);
+                                log_error("Invalid data object at hash entry %"PRIu64" of %"PRIu64,
+                                          i, n);
                                 return -EBADMSG;
                         }
 
@@ -474,14 +474,14 @@ static int verify_hash_table(
 
                         next = le64toh(o->data.next_hash_offset);
                         if (next != 0 && next <= p) {
-                                log_error("Hash chain has a cycle in hash entry %llu of %llu",
-                                          (unsigned long long) i, (unsigned long long) n);
+                                log_error("Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64,
+                                          i, n);
                                 return -EBADMSG;
                         }
 
                         if (le64toh(o->data.hash) % n != i) {
-                                log_error("Hash value mismatch in hash entry %llu of %llu",
-                                          (unsigned long long) i, (unsigned long long) n);
+                                log_error("Hash value mismatch in hash entry %"PRIu64" of %"PRIu64,
+                                          i, n);
                                 return -EBADMSG;
                         }
 
@@ -548,8 +548,7 @@ static int verify_entry(
                 h = le64toh(o->entry.items[i].hash);
 
                 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
-                        log_error("Invalid data object at entry %llu",
-                                  (unsigned long long) p);
+                        log_error("Invalid data object at entry %"PRIu64, p);
                                 return -EBADMSG;
                         }
 
@@ -558,8 +557,7 @@ static int verify_entry(
                         return r;
 
                 if (le64toh(u->data.hash) != h) {
-                        log_error("Hash mismatch for data object at entry %llu",
-                                  (unsigned long long) p);
+                        log_error("Hash mismatch for data object at entry %"PRIu64, p);
                         return -EBADMSG;
                 }
 
@@ -567,8 +565,7 @@ static int verify_entry(
                 if (r < 0)
                         return r;
                 if (r == 0) {
-                        log_error("Data object missing from hash at entry %llu",
-                                  (unsigned long long) p);
+                        log_error("Data object missing from hash at entry %"PRIu64, p);
                         return -EBADMSG;
                 }
         }
@@ -603,14 +600,12 @@ static int verify_entry_array(
                         draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
 
                 if (a == 0) {
-                        log_error("Array chain too short at %llu of %llu",
-                                  (unsigned long long) i, (unsigned long long) n);
+                        log_error("Array chain too short at %"PRIu64" of %"PRIu64, i, n);
                         return -EBADMSG;
                 }
 
                 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
-                        log_error("Invalid array at %llu of %llu",
-                                  (unsigned long long) i, (unsigned long long) n);
+                        log_error("Invalid array at %"PRIu64" of %"PRIu64, i, n);
                         return -EBADMSG;
                 }
 
@@ -620,8 +615,7 @@ static int verify_entry_array(
 
                 next = le64toh(o->entry_array.next_entry_array_offset);
                 if (next != 0 && next <= a) {
-                        log_error("Array chain has cycle at %llu of %llu",
-                                  (unsigned long long) i, (unsigned long long) n);
+                        log_error("Array chain has cycle at %"PRIu64" of %"PRIu64, i, n);
                         return -EBADMSG;
                 }
 
@@ -631,15 +625,15 @@ static int verify_entry_array(
 
                         p = le64toh(o->entry_array.items[j]);
                         if (p <= last) {
-                                log_error("Entry array not sorted at %llu of %llu",
-                                          (unsigned long long) i, (unsigned long long) n);
+                                log_error("Entry array not sorted at %"PRIu64" of %"PRIu64,
+                                          i, n);
                                 return -EBADMSG;
                         }
                         last = p;
 
                         if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
-                                log_error("Invalid array entry at %llu of %llu",
-                                          (unsigned long long) i, (unsigned long long) n);
+                                log_error("Invalid array entry at %"PRIu64" of %"PRIu64,
+                                          i, n);
                                 return -EBADMSG;
                         }
 
@@ -753,7 +747,7 @@ int journal_file_verify(
 
                 r = journal_file_move_to_object(f, -1, p, &o);
                 if (r < 0) {
-                        log_error("Invalid object at %llu", (unsigned long long) p);
+                        log_error("Invalid object at %"PRIu64, p);
                         goto fail;
                 }
 
@@ -770,12 +764,12 @@ int journal_file_verify(
 
                 r = journal_file_object_verify(f, o);
                 if (r < 0) {
-                        log_error("Invalid object contents at %llu", (unsigned long long) p);
+                        log_error("Invalid object contents at %"PRIu64, p);
                         goto fail;
                 }
 
                 if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
-                        log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
+                        log_error("Compressed object in file without compression at %"PRIu64, p);
                         r = -EBADMSG;
                         goto fail;
                 }
@@ -796,7 +790,7 @@ int journal_file_verify(
 
                 case OBJECT_ENTRY:
                         if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
-                                log_error("First entry before first tag at %llu", (unsigned long long) p);
+                                log_error("First entry before first tag at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
@@ -806,21 +800,21 @@ int journal_file_verify(
                                 goto fail;
 
                         if (le64toh(o->entry.realtime) < last_tag_realtime) {
-                                log_error("Older entry after newer tag at %llu", (unsigned long long) p);
+                                log_error("Older entry after newer tag at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
 
                         if (!entry_seqnum_set &&
                             le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
-                                log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
+                                log_error("Head entry sequence number incorrect at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
 
                         if (entry_seqnum_set &&
                             entry_seqnum >= le64toh(o->entry.seqnum)) {
-                                log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
+                                log_error("Entry sequence number out of synchronization at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
@@ -831,7 +825,7 @@ int journal_file_verify(
                         if (entry_monotonic_set &&
                             sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
                             entry_monotonic > le64toh(o->entry.monotonic)) {
-                                log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
+                                log_error("Entry timestamp out of synchronization at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
@@ -855,7 +849,7 @@ int journal_file_verify(
 
                 case OBJECT_DATA_HASH_TABLE:
                         if (n_data_hash_tables > 1) {
-                                log_error("More than one data hash table at %llu", (unsigned long long) p);
+                                log_error("More than one data hash table at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
@@ -872,7 +866,7 @@ int journal_file_verify(
 
                 case OBJECT_FIELD_HASH_TABLE:
                         if (n_field_hash_tables > 1) {
-                                log_error("More than one field hash table at %llu", (unsigned long long) p);
+                                log_error("More than one field hash table at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
@@ -894,7 +888,7 @@ int journal_file_verify(
 
                         if (p == le64toh(f->header->entry_array_offset)) {
                                 if (found_main_entry_array) {
-                                        log_error("More than one main entry array at %llu", (unsigned long long) p);
+                                        log_error("More than one main entry array at %"PRIu64, p);
                                         r = -EBADMSG;
                                         goto fail;
                                 }
@@ -907,19 +901,19 @@ int journal_file_verify(
 
                 case OBJECT_TAG:
                         if (!JOURNAL_HEADER_SEALED(f->header)) {
-                                log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
+                                log_error("Tag object in file without sealing at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
 
                         if (le64toh(o->tag.seqnum) != n_tags + 1) {
-                                log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
+                                log_error("Tag sequence number out of synchronization at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
 
                         if (le64toh(o->tag.epoch) < last_epoch) {
-                                log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
+                                log_error("Epoch sequence out of synchronization at %"PRIu64, p);
                                 r = -EBADMSG;
                                 goto fail;
                         }
@@ -928,11 +922,11 @@ int journal_file_verify(
                         if (f->seal) {
                                 uint64_t q, rt;
 
-                                log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
+                                log_debug("Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
 
                                 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
                                 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
-                                        log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
+                                        log_error("Tag/entry realtime timestamp out of synchronization at %"PRIu64, p);
                                         r = -EBADMSG;
                                         goto fail;
                                 }
@@ -975,7 +969,7 @@ int journal_file_verify(
                                         goto fail;
 
                                 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
-                                        log_error("Tag failed verification at %llu", (unsigned long long) p);
+                                        log_error("Tag failed verification at %"PRIu64, p);
                                         r = -EBADMSG;
                                         goto fail;
                                 }
@@ -1138,11 +1132,11 @@ fail:
         if (show_progress)
                 flush_progress();
 
-        log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
+        log_error("File corruption detected at %s:%"PRIu64" (of %llu bytes, %"PRIu64"%%).",
                   f->path,
-                  (unsigned long long) p,
+                  p,
                   (unsigned long long) f->last_stat.st_size,
-                  (unsigned long long) (100 * p / f->last_stat.st_size));
+                  100 * p / f->last_stat.st_size);
 
         if (data_fd >= 0) {
                 mmap_cache_close_fd(f->mmap, data_fd);
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 2f53632..5fd87b8 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -151,7 +151,8 @@ static void dev_kmsg_record(Server *s, char *p, size_t l) {
 
                 /* Did we lose any? */
                 if (serial > *s->kernel_seqnum)
-                        server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, "Missed %llu kernel messages", (unsigned long long) serial - *s->kernel_seqnum - 1);
+                        server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, "Missed %"PRIu64" kernel messages",
+                                              serial - *s->kernel_seqnum - 1);
 
                 /* Make sure we never read this one again. Note that
                  * we always store the next message serial we expect
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 8b9a589..8986763 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -979,11 +979,11 @@ _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
         sd_id128_to_string(o->entry.boot_id, bid);
 
         if (asprintf(cursor,
-                     "s=%s;i=%llx;b=%s;m=%llx;t=%llx;x=%llx",
-                     sid, (unsigned long long) le64toh(o->entry.seqnum),
-                     bid, (unsigned long long) le64toh(o->entry.monotonic),
-                     (unsigned long long) le64toh(o->entry.realtime),
-                     (unsigned long long) le64toh(o->entry.xor_hash)) < 0)
+                     "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64,
+                     sid, le64toh(o->entry.seqnum),
+                     bid, le64toh(o->entry.monotonic),
+                     le64toh(o->entry.realtime),
+                     le64toh(o->entry.xor_hash)) < 0)
                 return -ENOMEM;
 
         return 0;
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index ad2e2d4..6b7414a 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -130,10 +130,10 @@ int main(int argc, char *argv[]) {
                 for (p = 38448*8+0; p < ((uint64_t) st.st_size * 8); p ++) {
                         bit_toggle("test.journal", p);
 
-                        log_info("[ %llu+%llu]", (unsigned long long) p / 8, (unsigned long long) p % 8);
+                        log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8);
 
                         if (raw_verify("test.journal", verification_key) >= 0)
-                                log_notice(ANSI_HIGHLIGHT_RED_ON ">>>> %llu (bit %llu) can be toggled without detection." ANSI_HIGHLIGHT_OFF, (unsigned long long) p / 8, (unsigned long long) p % 8);
+                                log_notice(ANSI_HIGHLIGHT_RED_ON ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_HIGHLIGHT_OFF, p / 8, p % 8);
 
                         bit_toggle("test.journal", p);
                 }
diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c
index 42ab6d9..a56ad75 100644
--- a/src/libudev/libudev-hwdb.c
+++ b/src/libudev/libudev-hwdb.c
@@ -300,11 +300,11 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
         }
 
         log_debug("=== trie on-disk ===\n");
-        log_debug("tool version:          %llu", (unsigned long long)le64toh(hwdb->head->tool_version));
-        log_debug("file size:        %8llu bytes\n", (unsigned long long)hwdb->st.st_size);
-        log_debug("header size       %8llu bytes\n", (unsigned long long)le64toh(hwdb->head->header_size));
-        log_debug("strings           %8llu bytes\n", (unsigned long long)le64toh(hwdb->head->strings_len));
-        log_debug("nodes             %8llu bytes\n", (unsigned long long)le64toh(hwdb->head->nodes_len));
+        log_debug("tool version:          %"PRIu64, le64toh(hwdb->head->tool_version));
+        log_debug("file size:        %8llu bytes\n", (unsigned long long) hwdb->st.st_size);
+        log_debug("header size       %8"PRIu64" bytes\n", le64toh(hwdb->head->header_size));
+        log_debug("strings           %8"PRIu64" bytes\n", le64toh(hwdb->head->strings_len));
+        log_debug("nodes             %8"PRIu64" bytes\n", le64toh(hwdb->head->nodes_len));
         return hwdb;
 }
 
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 662273b..4fd3985 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -108,9 +108,9 @@ void session_free(Session *s) {
 }
 
 int session_save(Session *s) {
-        FILE *f;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *temp_path = NULL;
         int r = 0;
-        char *temp_path;
 
         assert(s);
 
@@ -145,69 +145,43 @@ int session_save(Session *s) {
                 s->kill_processes);
 
         if (s->type >= 0)
-                fprintf(f,
-                        "TYPE=%s\n",
-                        session_type_to_string(s->type));
+                fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
 
         if (s->class >= 0)
-                fprintf(f,
-                        "CLASS=%s\n",
-                        session_class_to_string(s->class));
+                fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
 
         if (s->cgroup_path)
-                fprintf(f,
-                        "CGROUP=%s\n",
-                        s->cgroup_path);
+                fprintf(f, "CGROUP=%s\n", s->cgroup_path);
 
         if (s->fifo_path)
-                fprintf(f,
-                        "FIFO=%s\n",
-                        s->fifo_path);
+                fprintf(f, "FIFO=%s\n", s->fifo_path);
 
         if (s->seat)
-                fprintf(f,
-                        "SEAT=%s\n",
-                        s->seat->id);
+                fprintf(f, "SEAT=%s\n", s->seat->id);
 
         if (s->tty)
-                fprintf(f,
-                        "TTY=%s\n",
-                        s->tty);
+                fprintf(f, "TTY=%s\n", s->tty);
 
         if (s->display)
-                fprintf(f,
-                        "DISPLAY=%s\n",
-                        s->display);
+                fprintf(f, "DISPLAY=%s\n", s->display);
 
         if (s->remote_host)
-                fprintf(f,
-                        "REMOTE_HOST=%s\n",
-                        s->remote_host);
+                fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
 
         if (s->remote_user)
-                fprintf(f,
-                        "REMOTE_USER=%s\n",
-                        s->remote_user);
+                fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
 
         if (s->service)
-                fprintf(f,
-                        "SERVICE=%s\n",
-                        s->service);
+                fprintf(f, "SERVICE=%s\n", s->service);
 
         if (s->seat && seat_can_multi_session(s->seat))
-                fprintf(f,
-                        "VTNR=%i\n",
-                        s->vtnr);
+                fprintf(f, "VTNR=%i\n", s->vtnr);
 
         if (s->leader > 0)
-                fprintf(f,
-                        "LEADER=%lu\n",
-                        (unsigned long) s->leader);
+                fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
 
         if (s->audit_id > 0)
-                fprintf(f,
-                        "AUDIT=%llu\n",
-                        (unsigned long long) s->audit_id);
+                fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
 
         fflush(f);
 
@@ -217,9 +191,6 @@ int session_save(Session *s) {
                 unlink(temp_path);
         }
 
-        fclose(f);
-        free(temp_path);
-
 finish:
         if (r < 0)
                 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));

commit b32ff512191bf873266ee8067f6f6c8a30c96a5e
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 19:33:45 2013 -0400

    Properly check for overflow in offsets

diff --git a/src/shared/util.c b/src/shared/util.c
index d0bbf78..17928ec 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -2261,7 +2261,7 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
 int parse_bytes(const char *t, off_t *bytes) {
         static const struct {
                 const char *suffix;
-                off_t factor;
+                unsigned long long factor;
         } table[] = {
                 { "B", 1 },
                 { "K", 1024ULL },
@@ -2274,7 +2274,7 @@ int parse_bytes(const char *t, off_t *bytes) {
         };
 
         const char *p;
-        off_t r = 0;
+        unsigned long long r = 0;
 
         assert(t);
         assert(bytes);
@@ -2301,7 +2301,17 @@ int parse_bytes(const char *t, off_t *bytes) {
 
                 for (i = 0; i < ELEMENTSOF(table); i++)
                         if (startswith(e, table[i].suffix)) {
-                                r += (off_t) l * table[i].factor;
+                                unsigned long long tmp;
+                                if ((unsigned long long) l > ULLONG_MAX / table[i].factor)
+                                        return -ERANGE;
+                                tmp = l * table[i].factor;
+                                if (tmp > ULLONG_MAX - r)
+                                        return -ERANGE;
+
+                                r += tmp;
+                                if ((unsigned long long) (off_t) r != r)
+                                        return -ERANGE;
+
                                 p = e + strlen(table[i].suffix);
                                 break;
                         }
@@ -2309,7 +2319,7 @@ int parse_bytes(const char *t, off_t *bytes) {
                 if (i >= ELEMENTSOF(table))
                         return -EINVAL;
 
-        } while (*p != 0);
+        } while (*p);
 
         *bytes = r;
 
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 4c3a8a6..9396aeb 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -439,6 +439,44 @@ static void test_protect_errno(void) {
         assert(errno == 12);
 }
 
+static void test_parse_bytes(void) {
+        off_t bytes;
+
+        assert_se(parse_bytes("111", &bytes) == 0);
+        assert_se(bytes == 111);
+
+        assert_se(parse_bytes(" 112 B", &bytes) == 0);
+        assert_se(bytes == 112);
+
+        assert_se(parse_bytes("3 K", &bytes) == 0);
+        assert_se(bytes == 3*1024);
+
+        assert_se(parse_bytes(" 4 M 11K", &bytes) == 0);
+        assert_se(bytes == 4*1024*1024 + 11 * 1024);
+
+        assert_se(parse_bytes("3B3G", &bytes) == 0);
+        assert_se(bytes == 3ULL*1024*1024*1024 + 3);
+
+        assert_se(parse_bytes("3B3G4T", &bytes) == 0);
+        assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
+
+        assert_se(parse_bytes("12P", &bytes) == 0);
+        assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024);
+
+        assert_se(parse_bytes("3E 2P", &bytes) == 0);
+        assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024);
+
+        assert_se(parse_bytes("12X", &bytes) == -EINVAL);
+
+        assert_se(parse_bytes("1024E", &bytes) == -ERANGE);
+        assert_se(parse_bytes("-1", &bytes) == -ERANGE);
+        assert_se(parse_bytes("-1024E", &bytes) == -ERANGE);
+
+        assert_se(parse_bytes("-1024P", &bytes) == -ERANGE);
+
+        assert_se(parse_bytes("-10B 20K", &bytes) == -ERANGE);
+}
+
 int main(int argc, char *argv[]) {
         test_streq_ptr();
         test_first_word();
@@ -467,6 +505,7 @@ int main(int argc, char *argv[]) {
         test_u64log2();
         test_get_process_comm();
         test_protect_errno();
+        test_parse_bytes();
 
         return 0;
 }

commit 3001c74580c1713bd634990a0b2ab351fdec7a98
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 20:33:42 2013 -0400

    journalctl: no color for --reboot-- when not on tty

diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index f404e41..af0f4ba 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -1333,12 +1333,14 @@ int main(int argc, char *argv[]) {
 
                         if (!arg_merge) {
                                 sd_id128_t boot_id;
+                                const char *color_on = on_tty() ? ANSI_HIGHLIGHT_ON : "",
+                                           *color_off = on_tty() ? ANSI_HIGHLIGHT_OFF : "";
 
                                 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
                                 if (r >= 0) {
                                         if (previous_boot_id_valid &&
                                             !sd_id128_equal(boot_id, previous_boot_id))
-                                                printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
+                                                printf("%s-- Reboot --%s\n", color_on, color_off);
 
                                         previous_boot_id = boot_id;
                                         previous_boot_id_valid = true;

commit 2bc8ca0ca2fefcfb63a37723d7a9bbb9ae76ceb1
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Wed Jun 5 00:56:03 2013 -0400

    journal: loop less in MATCH_AND_TERM conditionals
    
    AND term usually don't have many subterms (4 seems to be the maximum
    sensible number, e.g. _BOOT_ID && _SYSTEMD_UNIT && _PID && MESSAGE_ID).
    Nevertheless, the cost of checking each subterm can be relatively
    high, especially when the nested terms are compound, and it
    makes sense to minimize the number of checks.
    
    Instead of looping to the end and then again over the whole list once
    again after at least one term changed the offset, start the loop at
    the term which caused the change. This way ½ terms in the AND match
    are not checked unnecessarily again.

diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 46511df..8b9a589 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -593,42 +593,35 @@ static int next_for_match(
                 }
 
         } else if (m->type == MATCH_AND_TERM) {
-                Match *i;
-                bool continue_looking;
+                Match *i, *last_moved;
 
                 /* Always jump to the next matching entry and repeat
-                 * this until we fine and offset that matches for all
+                 * this until we find an offset that matches for all
                  * matches. */
 
                 if (!m->matches)
                         return 0;
 
-                np = 0;
-                do {
-                        continue_looking = false;
+                r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np);
+                if (r <= 0)
+                        return r;
 
-                        LIST_FOREACH(matches, i, m->matches) {
-                                uint64_t cp, limit;
+                assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset);
+                last_moved = m->matches;
 
-                                if (np == 0)
-                                        limit = after_offset;
-                                else if (direction == DIRECTION_DOWN)
-                                        limit = MAX(np, after_offset);
-                                else
-                                        limit = MIN(np, after_offset);
+                LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) {
+                        uint64_t cp;
 
-                                r = next_for_match(j, i, f, limit, direction, NULL, &cp);
-                                if (r <= 0)
-                                        return r;
+                        r = next_for_match(j, i, f, np, direction, NULL, &cp);
+                        if (r <= 0)
+                                return r;
 
-                                if ((direction == DIRECTION_DOWN ? cp >= after_offset : cp <= after_offset) &&
-                                    (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np))) {
-                                        np = cp;
-                                        continue_looking = true;
-                                }
+                        assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np);
+                        if (direction == DIRECTION_DOWN ? cp > np : cp < np) {
+                                np = cp;
+                                last_moved = i;
                         }
-
-                } while (continue_looking);
+                }
         }
 
         if (np == 0)
diff --git a/src/shared/list.h b/src/shared/list.h
index 47f275a..96d6237 100644
--- a/src/shared/list.h
+++ b/src/shared/list.h
@@ -123,3 +123,10 @@
 
 #define LIST_FOREACH_AFTER(name,i,p)                                    \
         for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
+
+/* Loop starting from p->next until p->prev.
+   p can be adjusted meanwhile. */
+#define LIST_LOOP_BUT_ONE(name,i,head,p)                                \
+        for ((i) = (p)->name##_next ? (p)->name##_next : (head);        \
+             (i) != (p);                                                \
+             (i) = (i)->name##_next ? (i)->name##_next : (head))

commit 3f3a438f58d7b1d2ba2b44d6d356fb1eaa65b66a
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Tue Jun 4 19:33:34 2013 -0400

    journalctl: add --system/--user flags
    
    --user basically gives messages from your own systemd --user services.
    --system basically gives messages from PID 1, kernel, and --system
    services. Those two options are not exahustive, because a priviledged
    user might be able to see messages from other users, and they will not
    be shown with either or both of those flags.

diff --git a/man/journalctl.xml b/man/journalctl.xml
index d9ca0a6..6610081 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -448,6 +448,20 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><option>--system</option></term>
+                                <term><option>--user</option></term>
+
+                                <listitem><para>Show messages from
+                                system services and the kernel (with
+                                <option>--system</option>).  Show
+                                messages from service of current user
+                                (with <option>--user</option>).
+                                If neither is specified, show all
+                                messages that the user can see.
+                                </para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><option>-D</option></term>
                                 <term><option>--directory=</option></term>
 
diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl
index 19362ae..5ab59c9 100644
--- a/shell-completion/bash/journalctl
+++ b/shell-completion/bash/journalctl
@@ -38,6 +38,7 @@ _journalctl() {
         local field_vals= cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
         local -A OPTS=(
                 [STANDALONE]='-a --all --full
+                              --system --user
                               -b --this-boot --disk-usage -f --follow --header
                               -h --help -l --local --new-id128 -m --merge --no-pager
                               --no-tail -q --quiet --setup-keys --this-boot --verify
diff --git a/shell-completion/systemd-zsh-completion.zsh b/shell-completion/systemd-zsh-completion.zsh
index 411646e..6862891 100644
--- a/shell-completion/systemd-zsh-completion.zsh
+++ b/shell-completion/systemd-zsh-completion.zsh
@@ -71,6 +71,8 @@ _ctls()
                 '--since=[Start showing entries newer or of the specified date]:YYYY-MM-DD HH\:MM\:SS' \
                 '--until=[Stop showing entries older or of the specified date]:YYYY-MM-DD HH\:MM\:SS' \
                 {-c,--cursor=}'[Start showing entries from specified cursor]:cursors:_journal_fields __CURSORS' \
+                '--system[Show system and kernel messages]' \
+                '--user[Show messages from user services]' \
                 {-b,--this-boot}'[Show data only from current boot]' \
                 {-u,--unit=}'[Show data only from the specified unit]:units:_journal_fields _SYSTEMD_UNIT' \
                 '--user-unit[Show data only from the specified user session unit]:units:_journal_fields _SYSTEMD_USER_UNIT' \
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index de972a1..f404e41 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -86,6 +86,7 @@ static char **arg_user_units = NULL;
 static const char *arg_field = NULL;
 static bool arg_catalog = false;
 static bool arg_reverse = false;
+static int arg_journal_type = 0;
 static const char *arg_root = NULL;
 
 static enum {
@@ -105,6 +106,8 @@ static int help(void) {
         printf("%s [OPTIONS...] [MATCHES...]\n\n"
                "Query the journal.\n\n"
                "Flags:\n"
+               "     --system            Show only the system journal\n"
+               "     --user              Show only the user journal for current user\n"
                "     --since=DATE        Start showing entries newer or of the specified date\n"
                "     --until=DATE        Stop showing entries older or of the specified date\n"
                "  -c --cursor=CURSOR     Start showing entries from specified cursor\n"
@@ -158,6 +161,8 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_NO_PAGER,
                 ARG_NO_TAIL,
                 ARG_NEW_ID128,
+                ARG_USER,
+                ARG_SYSTEM,
                 ARG_ROOT,
                 ARG_HEADER,
                 ARG_FULL,
@@ -171,7 +176,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_USER_UNIT,
                 ARG_LIST_CATALOG,
                 ARG_DUMP_CATALOG,
-                ARG_UPDATE_CATALOG
+                ARG_UPDATE_CATALOG,
         };
 
         static const struct option options[] = {
@@ -190,6 +195,8 @@ static int parse_argv(int argc, char *argv[]) {
                 { "merge",        no_argument,       NULL, 'm'              },
                 { "this-boot",    no_argument,       NULL, 'b'              },
                 { "dmesg",        no_argument,       NULL, 'k'              },
+                { "system",       no_argument,       NULL, ARG_SYSTEM       },
+                { "user",         no_argument,       NULL, ARG_USER         },
                 { "directory",    required_argument, NULL, 'D'              },
                 { "root",         required_argument, NULL, ARG_ROOT         },
                 { "header",       no_argument,       NULL, ARG_HEADER       },
@@ -324,6 +331,14 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_this_boot = arg_dmesg = true;
                         break;
 
+                case ARG_SYSTEM:
+                        arg_journal_type |= SD_JOURNAL_SYSTEM;
+                        break;
+
+                case ARG_USER:
+                        arg_journal_type |= SD_JOURNAL_CURRENT_USER;
+                        break;
+
                 case 'D':
                         arg_directory = optarg;
                         break;
@@ -1094,9 +1109,9 @@ int main(int argc, char *argv[]) {
         }
 
         if (arg_directory)
-                r = sd_journal_open_directory(&j, arg_directory, 0);
+                r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
         else
-                r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
+                r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
         if (r < 0) {
                 log_error("Failed to open journal: %s", strerror(-r));
                 return EXIT_FAILURE;

commit a688baa8b71f9c74500f7883dfb137194874266a
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Tue Jun 4 22:31:05 2013 -0400

    journal: add ability to filter by current user
    
    This is the just the library part.
    
    SD_JOURNAL_CURRENT_USER flags is added to sd_j_open(), to open
    files from current user.
    
    SD_JOURNAL_SYSTEM_ONLY is renamed to SD_JOURNAL_SYSTEM,
    and changed to mean to (also) open system files. This way various
    flags can be combined, which gives them nicer semantics, especially
    if other ones are added later.
    
    Backwards compatibility is kept, because SD_JOURNAL_SYSTEM_ONLY
    is equivalent to SD_JOURNAL_SYSTEM if used alone, and before there
    we no other flags.

diff --git a/Makefile-man.am b/Makefile-man.am
index 5888158..a31427e 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -107,6 +107,7 @@ MANPAGES_ALIAS += \
 	man/SD_ID128_MAKE.3 \
 	man/SD_INFO.3 \
 	man/SD_JOURNAL_APPEND.3 \
+	man/SD_JOURNAL_CURRENT_USER.3 \
 	man/SD_JOURNAL_FOREACH.3 \
 	man/SD_JOURNAL_FOREACH_BACKWARDS.3 \
 	man/SD_JOURNAL_FOREACH_DATA.3 \
@@ -116,6 +117,7 @@ MANPAGES_ALIAS += \
 	man/SD_JOURNAL_NOP.3 \
 	man/SD_JOURNAL_RUNTIME_ONLY.3 \
 	man/SD_JOURNAL_SUPPRESS_LOCATION.3 \
+	man/SD_JOURNAL_SYSTEM.3 \
 	man/SD_JOURNAL_SYSTEM_ONLY.3 \
 	man/SD_LISTEN_FDS_START.3 \
 	man/SD_NOTICE.3 \
@@ -205,6 +207,7 @@ man/SD_ID128_FORMAT_VAL.3: man/sd-id128.3
 man/SD_ID128_MAKE.3: man/sd-id128.3
 man/SD_INFO.3: man/sd-daemon.3
 man/SD_JOURNAL_APPEND.3: man/sd_journal_get_fd.3
+man/SD_JOURNAL_CURRENT_USER.3: man/sd_journal_open.3
 man/SD_JOURNAL_FOREACH.3: man/sd_journal_next.3
 man/SD_JOURNAL_FOREACH_BACKWARDS.3: man/sd_journal_next.3
 man/SD_JOURNAL_FOREACH_DATA.3: man/sd_journal_get_data.3
@@ -214,6 +217,7 @@ man/SD_JOURNAL_LOCAL_ONLY.3: man/sd_journal_open.3
 man/SD_JOURNAL_NOP.3: man/sd_journal_get_fd.3
 man/SD_JOURNAL_RUNTIME_ONLY.3: man/sd_journal_open.3
 man/SD_JOURNAL_SUPPRESS_LOCATION.3: man/sd_journal_print.3
+man/SD_JOURNAL_SYSTEM.3: man/sd_journal_open.3
 man/SD_JOURNAL_SYSTEM_ONLY.3: man/sd_journal_open.3
 man/SD_LISTEN_FDS_START.3: man/sd_listen_fds.3
 man/SD_NOTICE.3: man/sd-daemon.3
@@ -325,6 +329,9 @@ man/SD_INFO.html: man/sd-daemon.html
 man/SD_JOURNAL_APPEND.html: man/sd_journal_get_fd.html
 	$(html-alias)
 
+man/SD_JOURNAL_CURRENT_USER.html: man/sd_journal_open.html
+	$(html-alias)
+
 man/SD_JOURNAL_FOREACH.html: man/sd_journal_next.html
 	$(html-alias)
 
@@ -352,6 +359,9 @@ man/SD_JOURNAL_RUNTIME_ONLY.html: man/sd_journal_open.html
 man/SD_JOURNAL_SUPPRESS_LOCATION.html: man/sd_journal_print.html
 	$(html-alias)
 
+man/SD_JOURNAL_SYSTEM.html: man/sd_journal_open.html
+	$(html-alias)
+
 man/SD_JOURNAL_SYSTEM_ONLY.html: man/sd_journal_open.html
 	$(html-alias)
 
diff --git a/man/sd_journal_open.xml b/man/sd_journal_open.xml
index 76b857b..dd2f32d 100644
--- a/man/sd_journal_open.xml
+++ b/man/sd_journal_open.xml
@@ -49,7 +49,8 @@
                 <refname>sd_journal</refname>
                 <refname>SD_JOURNAL_LOCAL_ONLY</refname>
                 <refname>SD_JOURNAL_RUNTIME_ONLY</refname>
-                <refname>SD_JOURNAL_SYSTEM_ONLY</refname>
+                <refname>SD_JOURNAL_SYSTEM</refname>
+                <refname>SD_JOURNAL_CURRENT_USER</refname>
                 <refpurpose>Open the system journal for reading</refpurpose>
         </refnamediv>
 
@@ -93,10 +94,14 @@
                 be opened. <literal>SD_JOURNAL_RUNTIME_ONLY</literal>
                 makes sure only volatile journal files will be opened,
                 excluding those which are stored on persistent
-                storage. <literal>SD_JOURNAL_SYSTEM_ONLY</literal>
-                will ensure that only journal files of system services
-                and the kernel (in opposition to user session processes) will
-                be opened.</para>
+                storage. <literal>SD_JOURNAL_SYSTEM</literal>
+                will cause journal files of system services and the
+                kernel (in opposition to user session processes) to
+                be opened. <literal>SD_JOURNAL_CURRENT_USER</literal>
+                will cause journal files of the current user to be
+                opened. If neither <literal>SD_JOURNAL_SYSTEM</literal>
+                nor <literal>SD_JOURNAL_CURRENT_USER</literal> are
+                specified, all journal file types will be opened.</para>
 
                 <para><function>sd_journal_open_directory()</function>
                 is similar to <function>sd_journal_open()</function>
@@ -171,6 +176,26 @@
         </refsect1>
 
         <refsect1>
+                <title>History</title>
+
+                <para><function>sd_journal_open()</function>,
+                <function>sd_journal_close()</function>,
+                <literal>SD_JOURNAL_LOCAL_ONLY</literal>,
+                <literal>SD_JOURNAL_RUNTIME_ONLY</literal>,
+                <literal>SD_JOURNAL_SYSTEM_ONLY</literal> were added
+                in systemd-38.</para>
+
+                <para><function>sd_journal_open_directory()</function>
+                was added in systemd-187.</para>
+
+                <para><literal>SD_JOURNAL_SYSTEM</literal> and
+                <literal>SD_JOURNAL_CURRENT_USER</literal> were added
+                in systemd-205.
+                <literal>SD_JOURNAL_SYSTEM_ONLY</literal>
+                was deprecated.</para>
+        </refsect1>
+
+        <refsect1>
                 <title>See Also</title>
 
                 <para>
diff --git a/src/journal/journal-gatewayd.c b/src/journal/journal-gatewayd.c
index 745f45f..86338c6 100644
--- a/src/journal/journal-gatewayd.c
+++ b/src/journal/journal-gatewayd.c
@@ -109,7 +109,7 @@ static int open_journal(RequestMeta *m) {
         if (m->journal)
                 return 0;
 
-        return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
+        return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM);
 }
 
 static int respond_oom_internal(struct MHD_Connection *connection) {
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 2bad243..46511df 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -1249,6 +1249,42 @@ static void check_network(sd_journal *j, int fd) {
                 F_TYPE_CMP(sfs.f_type, SMB_SUPER_MAGIC);
 }
 
+static bool file_has_type_prefix(const char *prefix, const char *filename) {
+        const char *full, *tilded, *atted;
+
+        full = strappend(prefix, ".journal");
+        tilded = strappenda(full, "~");
+        atted = strappenda(prefix, "@");
+
+        return streq(filename, full) ||
+               streq(filename, tilded) ||
+               startswith(filename, atted);
+}
+
+static bool file_type_wanted(int flags, const char *filename) {
+        if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
+                return false;
+
+        /* no flags set → every type is OK */
+        if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
+                return true;
+
+        if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
+                return true;
+
+        if (flags & SD_JOURNAL_CURRENT_USER) {
+                char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
+
+                assert_se(snprintf(prefix, sizeof(prefix), "user-%lu", (unsigned long) getuid())
+                          < (int) sizeof(prefix));
+
+                if (file_has_type_prefix(prefix, filename))
+                        return true;
+        }
+
+        return false;
+}
+
 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
         _cleanup_free_ char *path = NULL;
         int r;
@@ -1258,11 +1294,7 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
         assert(prefix);
         assert(filename);
 
-        if ((j->flags & SD_JOURNAL_SYSTEM_ONLY) &&
-            !(streq(filename, "system.journal") ||
-              streq(filename, "system.journal~") ||
-              (startswith(filename, "system@") &&
-               (endswith(filename, ".journal") || endswith(filename, ".journal~")))))
+        if (!file_type_wanted(j->flags, filename))
                 return 0;
 
         path = strjoin(prefix, "/", filename, NULL);
@@ -1619,7 +1651,8 @@ _public_ int sd_journal_open(sd_journal **ret, int flags) {
 
         if (flags & ~(SD_JOURNAL_LOCAL_ONLY|
                       SD_JOURNAL_RUNTIME_ONLY|
-                      SD_JOURNAL_SYSTEM_ONLY))
+                      SD_JOURNAL_SYSTEM|
+                      SD_JOURNAL_CURRENT_USER))
                 return -EINVAL;
 
         j = journal_new(flags, NULL);
diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c
index c4c4fdf..2c69963 100644
--- a/src/python-systemd/_reader.c
+++ b/src/python-systemd/_reader.c
@@ -1097,6 +1097,7 @@ init_reader(void)
         PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) ||
         PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) ||
         PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) ||
+        PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) ||
         PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) ||
         PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) {
 #if PY_MAJOR_VERSION >= 3
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 7947df3..013a281 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -1010,7 +1010,7 @@ int show_journal_by_unit(
 
         _cleanup_journal_close_ sd_journal*j = NULL;
         int r;
-        int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM_ONLY;
+        int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
 
         assert(mode >= 0);
         assert(mode < _OUTPUT_MODE_MAX);
diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h
index 5375d49..cf105cd 100644
--- a/src/systemd/sd-journal.h
+++ b/src/systemd/sd-journal.h
@@ -86,7 +86,9 @@ typedef struct sd_journal sd_journal;
 enum {
         SD_JOURNAL_LOCAL_ONLY = 1,
         SD_JOURNAL_RUNTIME_ONLY = 2,
-        SD_JOURNAL_SYSTEM_ONLY = 4
+        SD_JOURNAL_SYSTEM = 4,
+        SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM, /* deprecated */
+        SD_JOURNAL_CURRENT_USER = 8,
 };
 
 /* Wakeup event types */

commit c5a10d9ca017be6133154e09383c84c3d5b85f7c
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Jun 2 15:00:00 2013 -0400

    journal: simplify match_free_if_empty

diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index cf60ebc..2bad243 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -197,9 +197,7 @@ static void match_free(Match *m) {
 }
 
 static void match_free_if_empty(Match *m) {
-        assert(m);
-
-        if (m->matches)
+        if (!m || m->matches)
                 return;
 
         match_free(m);
@@ -296,17 +294,10 @@ _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size)
         return 0;
 
 fail:
-        if (add_here)
-                match_free_if_empty(add_here);
-
-        if (j->level2)
-                match_free_if_empty(j->level2);
-
-        if (j->level1)
-                match_free_if_empty(j->level1);
-
-        if (j->level0)
-                match_free_if_empty(j->level0);
+        match_free_if_empty(add_here);
+        match_free_if_empty(j->level2);
+        match_free_if_empty(j->level1);
+        match_free_if_empty(j->level0);
 
         return -ENOMEM;
 }



More information about the systemd-commits mailing list